00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 class Mage_Catalog_Model_Url
00035 {
00036
00037
00038
00039
00040
00041 const MAX_REQUEST_PATH_LENGTH = 240;
00042
00043
00044
00045
00046
00047
00048
00049 const ALLOWED_REQUEST_PATH_OVERFLOW = 10;
00050
00051
00052
00053
00054
00055
00056 protected $_resourceModel;
00057
00058
00059
00060
00061
00062
00063 protected $_categories = array();
00064
00065
00066
00067
00068
00069
00070 protected $_rewrites = array();
00071
00072
00073
00074
00075
00076
00077 protected $_rewrite;
00078
00079
00080
00081
00082
00083
00084 protected $_productUrlSuffix = array();
00085
00086
00087
00088
00089
00090
00091 protected $_categoryUrlSuffix = array();
00092
00093
00094
00095
00096
00097
00098
00099 public function getStores($storeId = null)
00100 {
00101 return $this->getResource()->getStores($storeId);
00102 }
00103
00104
00105
00106
00107
00108
00109 public function getResource()
00110 {
00111 if (is_null($this->_resourceModel)) {
00112 $this->_resourceModel = Mage::getResourceModel('catalog/url');
00113 }
00114 return $this->_resourceModel;
00115 }
00116
00117
00118
00119
00120
00121
00122 public function getCategoryModel()
00123 {
00124 return $this->getResource()->getCategoryModel();
00125 }
00126
00127
00128
00129
00130
00131
00132 public function getProductModel()
00133 {
00134 return $this->getResource()->getProductModel();
00135 }
00136
00137
00138
00139
00140
00141
00142
00143 public function refreshRewrites($storeId = null)
00144 {
00145 if (is_null($storeId)) {
00146 foreach ($this->getStores() as $store) {
00147 $this->refreshRewrites($store->getId());
00148 }
00149 return $this;
00150 }
00151
00152 $this->refreshCategoryRewrite($this->getStores($storeId)->getRootCategoryId(), $storeId, false);
00153 $this->refreshProductRewrites($storeId);
00154 $this->getResource()->clearCategoryProduct($storeId);
00155
00156 return $this;
00157 }
00158
00159
00160
00161
00162
00163
00164
00165
00166 protected function _refreshCategoryRewrites(Varien_Object $category, $parentPath = null, $refreshProducts = true)
00167 {
00168 if ($category->getId() != $this->getStores($category->getStoreId())->getRootCategoryId()) {
00169 if ($category->getUrlKey() == '') {
00170 $urlKey = $this->getCategoryModel()->formatUrlKey($category->getName());
00171 }
00172 else {
00173 $urlKey = $this->getCategoryModel()->formatUrlKey($category->getUrlKey());
00174 }
00175
00176 $idPath = $this->generatePath('id', null, $category);
00177 $targetPath = $this->generatePath('target', null, $category);
00178 $requestPath = $this->generatePath('request', null, $category, $parentPath);
00179
00180 $rewriteData = array(
00181 'store_id' => $category->getStoreId(),
00182 'category_id' => $category->getId(),
00183 'product_id' => null,
00184 'id_path' => $idPath,
00185 'request_path' => $requestPath,
00186 'target_path' => $targetPath,
00187 'is_system' => 1
00188 );
00189
00190 $this->getResource()->saveRewrite($rewriteData, $this->_rewrite);
00191
00192 if ($category->getUrlKey() != $urlKey) {
00193 $category->setUrlKey($urlKey);
00194 $this->getResource()->saveCategoryAttribute($category, 'url_key');
00195 }
00196 if ($category->getUrlPath() != $requestPath) {
00197 $category->setUrlPath($requestPath);
00198 $this->getResource()->saveCategoryAttribute($category, 'url_path');
00199 }
00200 }
00201 else {
00202 if ($category->getUrlPath() != '') {
00203 $category->setUrlPath('');
00204 $this->getResource()->saveCategoryAttribute($category, 'url_path');
00205 }
00206 }
00207
00208 if ($refreshProducts) {
00209 $this->_refreshCategoryProductRewrites($category);
00210 }
00211
00212 foreach ($category->getChilds() as $child) {
00213 $this->_refreshCategoryRewrites($child, $category->getUrlPath() . '/', $refreshProducts);
00214 }
00215
00216 return $this;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225
00226 protected function _refreshProductRewrite(Varien_Object $product, Varien_Object $category)
00227 {
00228 if ($category->getId() == $category->getPath()) {
00229 return $this;
00230 }
00231 if ($product->getUrlKey() == '') {
00232 $urlKey = $this->getProductModel()->formatUrlKey($product->getName());
00233 }
00234 else {
00235 $urlKey = $this->getProductModel()->formatUrlKey($product->getUrlKey());
00236 }
00237
00238 $idPath = $this->generatePath('id', $product, $category);
00239 $targetPath = $this->generatePath('target', $product, $category);
00240 $requestPath = $this->generatePath('request', $product, $category);
00241 $categoryId = null;
00242 $updateKeys = true;
00243 if ($category->getUrlPath()) {
00244 $categoryId = $category->getId();
00245 $updateKeys = false;
00246 }
00247
00248 $rewriteData = array(
00249 'store_id' => $category->getStoreId(),
00250 'category_id' => $categoryId,
00251 'product_id' => $product->getId(),
00252 'id_path' => $idPath,
00253 'request_path' => $requestPath,
00254 'target_path' => $targetPath,
00255 'is_system' => 1
00256 );
00257
00258 $this->getResource()->saveRewrite($rewriteData, $this->_rewrite);
00259
00260 if ($updateKeys && $product->getUrlKey() != $urlKey) {
00261 $product->setUrlKey($urlKey);
00262 $this->getResource()->saveProductAttribute($product, 'url_key');
00263 }
00264 if ($updateKeys && $product->getUrlPath() != $requestPath) {
00265 $product->setUrlPath($requestPath);
00266 $this->getResource()->saveProductAttribute($product, 'url_path');
00267 }
00268
00269 return $this;
00270 }
00271
00272
00273
00274
00275
00276
00277
00278 protected function _refreshCategoryProductRewrites(Varien_Object $category)
00279 {
00280 $originalRewrites = $this->_rewrites;
00281 $process = true;
00282 $lastEntityId = 0;
00283 while ($process == true) {
00284 $products = $this->getResource()->getProductsByCategory($category, $lastEntityId);
00285 if (!$products) {
00286 $process = false;
00287 break;
00288 }
00289
00290 $this->_rewrites = $this->getResource()->prepareRewrites($category->getStoreId(), $category->getId(), array_keys($products));
00291
00292 foreach ($products as $product) {
00293 $this->_refreshProductRewrite($product, $category);
00294 }
00295 unset($products);
00296 }
00297 $this->_rewrites = $originalRewrites;
00298 return $this;
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 public function refreshCategoryRewrite($categoryId, $storeId = null, $refreshProducts = true)
00310 {
00311 if (is_null($storeId)) {
00312 foreach ($this->getStores() as $store) {
00313 $this->refreshCategoryRewrite($categoryId, $store->getId(), $refreshProducts);
00314 }
00315 return $this;
00316 }
00317
00318 $category = $this->getResource()->getCategory($categoryId, $storeId);
00319 if (!$category) {
00320 return $this;
00321 }
00322 $category = $this->getResource()->loadCategoryChilds($category);
00323 $categoryIds = array($category->getId());
00324 if ($category->getAllChilds()) {
00325 $categoryIds = array_merge($categoryIds, array_keys($category->getAllChilds()));
00326 }
00327 $this->_rewrites = $this->getResource()->prepareRewrites($storeId, $categoryIds);
00328 $this->_refreshCategoryRewrites($category, null, $refreshProducts);
00329
00330 unset($category);
00331 $this->_rewrites = array();
00332
00333 return $this;
00334 }
00335
00336
00337
00338
00339
00340
00341
00342
00343 public function refreshProductRewrite($productId, $storeId = null)
00344 {
00345 if (is_null($storeId)) {
00346 foreach ($this->getStores() as $store) {
00347 $this->refreshProductRewrite($productId, $store->getId());
00348 }
00349 return $this;
00350 }
00351
00352 if ($product = $this->getResource()->getProduct($productId, $storeId)) {
00353 $storeRootCategoryId = $this->getStores($storeId)->getRootCategoryId();
00354 $categories = $this->getResource()->getCategories($product->getCategoryIds(), $storeId);
00355 $this->_rewrites = $this->getResource()->prepareRewrites($storeId, '', $productId);
00356
00357 if (!isset($categories[$storeRootCategoryId])) {
00358 $categories[$storeRootCategoryId] = $this->getResource()->getCategory($storeRootCategoryId, $storeId);
00359 }
00360
00361 foreach ($categories as $category) {
00362 $this->_refreshProductRewrite($product, $category);
00363 }
00364
00365 unset($categories);
00366 unset($product);
00367
00368
00369 }
00370
00371 return $this;
00372 }
00373
00374 public function refreshProductRewrites($storeId)
00375 {
00376 $this->_categories = array();
00377 $storeRootCategoryId = $this->getStores($storeId)->getRootCategoryId();
00378 $this->_categories[$storeRootCategoryId] = $this->getResource()->getCategory($storeRootCategoryId, $storeId);
00379
00380 $lastEntityId = 0;
00381 $process = true;
00382
00383 while ($process == true) {
00384 $products = $this->getResource()->getProductsByStore($storeId, $lastEntityId);
00385 if (!$products) {
00386 $process = false;
00387 break;
00388 }
00389
00390 $this->_rewrites = array();
00391 $this->_rewrites = $this->getResource()->prepareRewrites($storeId, false, array_keys($products));
00392
00393 $loadCategories = array();
00394 foreach ($products as $product) {
00395 foreach ($product->getCategoryIds() as $categoryId) {
00396 if (!isset($this->_categories[$categoryId])) {
00397 $loadCategories[$categoryId] = $categoryId;
00398 }
00399 }
00400 }
00401
00402 if ($loadCategories) {
00403 foreach ($this->getResource()->getCategories($loadCategories, $storeId) as $category) {
00404 $this->_categories[$category->getId()] = $category;
00405 }
00406 }
00407
00408 foreach ($products as $product) {
00409 $this->_refreshProductRewrite($product, $this->_categories[$storeRootCategoryId]);
00410 foreach ($product->getCategoryIds() as $categoryId) {
00411 if ($categoryId != $storeRootCategoryId && isset($this->_categories[$categoryId])) {
00412 $this->_refreshProductRewrite($product, $this->_categories[$categoryId]);
00413 }
00414 }
00415 }
00416
00417 unset($products);
00418 $this->_rewrites = array();
00419 }
00420
00421 $this->_categories = array();
00422 return $this;
00423 }
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 public function getUnusedPath($storeId, $requestPath, $idPath)
00436 {
00437 if (empty($requestPath)) {
00438 $requestPath = '-';
00439 }
00440 elseif ($requestPath == $this->getProductUrlSuffix($storeId)) {
00441 $requestPath = '-' . $this->getProductUrlSuffix($storeId);
00442 }
00443
00444 if (strlen($requestPath) > self::MAX_REQUEST_PATH_LENGTH + self::ALLOWED_REQUEST_PATH_OVERFLOW) {
00445 $requestPath = substr($requestPath, 0, self::MAX_REQUEST_PATH_LENGTH);
00446 }
00447
00448 if (isset($this->_rewrites[$idPath])) {
00449 $this->_rewrite = $this->_rewrites[$idPath];
00450 if ($this->_rewrites[$idPath]->getRequestPath() == $requestPath) {
00451 return $requestPath;
00452 }
00453 }
00454 else {
00455 $this->_rewrite = null;
00456 }
00457
00458 $rewrite = $this->getResource()->getRewriteByRequestPath($requestPath, $storeId);
00459 if ($rewrite && $rewrite->getId()) {
00460 if ($rewrite->getIdPath() == $idPath) {
00461 $this->_rewrite = $rewrite;
00462 return $requestPath;
00463 }
00464
00465 $productUrlSuffix = $this->getProductUrlSuffix($storeId);
00466
00467 $match = array();
00468 if (!preg_match('#^([0-9a-z/-]+?)(-([0-9]+))?('.preg_quote($productUrlSuffix).')?$#i', $requestPath, $match)) {
00469 return $this->getUnusedPath($storeId, '-', $idPath);
00470 }
00471 $requestPath = $match[1].(isset($match[3])?'-'.($match[3]+1):'-1').(isset($match[4])?$match[4]:'');
00472 return $this->getUnusedPath($storeId, $requestPath, $idPath);
00473 }
00474 else {
00475 return $requestPath;
00476 }
00477 }
00478
00479
00480
00481
00482
00483
00484
00485 public function getProductUrlSuffix($storeId)
00486 {
00487 return Mage::helper('catalog/product')->getProductUrlSuffix($storeId);
00488 }
00489
00490
00491
00492
00493
00494
00495
00496 public function getCategoryUrlSuffix($storeId)
00497 {
00498 return Mage::helper('catalog/category')->getCategoryUrlSuffix($storeId);
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515 public function generatePath($type = 'target', $product = null, $category = null, $parentPath = null)
00516 {
00517 if (!$product && !$category) {
00518 Mage::throwException(Mage::helper('core')->__('Specify either category or product, or both.'));
00519 }
00520
00521
00522 if ('id' === $type) {
00523 if (!$product) {
00524 return 'category/' . $category->getId();
00525 }
00526 if ($category && $category->getUrlPath()) {
00527 return 'product/' . $product->getId() . '/' . $category->getId();
00528 }
00529 return 'product/' . $product->getId();
00530 }
00531
00532
00533 if ('request' === $type) {
00534
00535 if (!$product) {
00536 if ($category->getUrlKey() == '') {
00537 $urlKey = $this->getCategoryModel()->formatUrlKey($category->getName());
00538 }
00539 else {
00540 $urlKey = $this->getCategoryModel()->formatUrlKey($category->getUrlKey());
00541 }
00542
00543 $categoryUrlSuffix = $this->getCategoryUrlSuffix($category->getStoreId());
00544 if (null === $parentPath) {
00545 $parentPath = $this->getResource()->getCategoryParentPath($category);
00546 }
00547 elseif ($parentPath == '/') {
00548 $parentPath = '';
00549 }
00550 $parentPath = Mage::helper('catalog/category')->getCategoryUrlPath($parentPath, true, $category->getStoreId());
00551
00552 return $this->getUnusedPath($category->getStoreId(), $parentPath . $urlKey . $categoryUrlSuffix,
00553 $this->generatePath('id', null, $category)
00554 );
00555 }
00556
00557
00558 if (!$category) {
00559 Mage::throwException(Mage::helper('core')->__('Category object is required for determining product request path'));
00560 }
00561
00562 if ($product->getUrlKey() == '') {
00563 $urlKey = $this->getProductModel()->formatUrlKey($product->getName());
00564 }
00565 else {
00566 $urlKey = $this->getProductModel()->formatUrlKey($product->getUrlKey());
00567 }
00568 $productUrlSuffix = $this->getProductUrlSuffix($category->getStoreId());
00569 if ($category->getUrlPath()) {
00570 $categoryUrl = Mage::helper('catalog/category')->getCategoryUrlPath($category->getUrlPath(), false, $category->getStoreId());
00571 return $this->getUnusedPath($category->getStoreId(), $categoryUrl . '/' . $urlKey . $productUrlSuffix,
00572 $this->generatePath('id', $product, $category)
00573 );
00574 }
00575
00576
00577 return $this->getUnusedPath($category->getStoreId(), $urlKey . $productUrlSuffix,
00578 $this->generatePath('id', $product)
00579 );
00580 }
00581
00582
00583 if (!$product) {
00584 return 'catalog/category/view/id/' . $category->getId();
00585 }
00586 if ($category && $category->getUrlPath()) {
00587 return 'catalog/product/view/id/' . $product->getId() . '/category/' . $category->getId();
00588 }
00589 return 'catalog/product/view/id/' . $product->getId();
00590 }
00591 }