Advertisement
Guest User

Untitled

a guest
Jan 26th, 2015
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 33.49 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Magento
  4.  *
  5.  * NOTICE OF LICENSE
  6.  *
  7.  * This source file is subject to the Open Software License (OSL 3.0)
  8.  * that is bundled with this package in the file LICENSE.txt.
  9.  * It is also available through the world-wide-web at this URL:
  10.  * http://opensource.org/licenses/osl-3.0.php
  11.  * If you did not receive a copy of the license and are unable to
  12.  * obtain it through the world-wide-web, please send an email
  13.  * to license@magento.com so we can send you a copy immediately.
  14.  *
  15.  * DISCLAIMER
  16.  *
  17.  * Do not edit or add to this file if you wish to upgrade Magento to newer
  18.  * versions in the future. If you wish to customize Magento for your
  19.  * needs please refer to http://www.magento.com for more information.
  20.  *
  21.  * @category    Mage
  22.  * @package     Mage_Catalog
  23.  * @copyright  Copyright (c) 2006-2014 X.commerce, Inc. (http://www.magento.com)
  24.  * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  25.  */
  26.  
  27. /**
  28.  * Catalog url model
  29.  *
  30.  * @category   Mage
  31.  * @package    Mage_Catalog
  32.  * @author     Magento Core Team <core@magentocommerce.com>
  33.  */
  34. class Mage_Catalog_Model_Url
  35. {
  36.     /**
  37.      * Number of characters allowed to be in URL path
  38.      *
  39.      * @var int
  40.      */
  41.     const MAX_REQUEST_PATH_LENGTH = 240;
  42.  
  43.     /**
  44.      * Number of characters allowed to be in URL path
  45.      * after MAX_REQUEST_PATH_LENGTH number of characters
  46.      *
  47.      * @var int
  48.      */
  49.     const ALLOWED_REQUEST_PATH_OVERFLOW = 10;
  50.  
  51.     /**
  52.      * Resource model
  53.      *
  54.      * @var Mage_Catalog_Model_Resource_Eav_Mysql4_Url
  55.      */
  56.     protected $_resourceModel;
  57.  
  58.     /**
  59.      * Categories cache for products
  60.      *
  61.      * @var array
  62.      */
  63.     protected $_categories = array();
  64.  
  65.     /**
  66.      * Store root categories cache
  67.      *
  68.      * @var array
  69.      */
  70.     protected $_rootCategories = array();
  71.  
  72.     /**
  73.      * Rewrite cache
  74.      *
  75.      * @var array
  76.      */
  77.     protected $_rewrites = array();
  78.  
  79.     /**
  80.      * Current url rewrite rule
  81.      *
  82.      * @var Varien_Object
  83.      */
  84.     protected $_rewrite;
  85.  
  86.     /**
  87.      * Cache for product rewrite suffix
  88.      *
  89.      * @var array
  90.      */
  91.     protected $_productUrlSuffix = array();
  92.  
  93.     /**
  94.      * Cache for category rewrite suffix
  95.      *
  96.      * @var array
  97.      */
  98.     protected $_categoryUrlSuffix = array();
  99.  
  100.     /**
  101.      * Flag to overwrite config settings for Catalog URL rewrites history maintainance
  102.      *
  103.      * @var bool
  104.      */
  105.     protected $_saveRewritesHistory = null;
  106.  
  107.      /**
  108.      * Singleton of category model for building URL path
  109.      *
  110.      * @var Mage_Catalog_Model_Category
  111.      */
  112.     static protected $_categoryForUrlPath;
  113.  
  114.     /**
  115.      * Adds url_path property for non-root category - to ensure that url path is not empty.
  116.      *
  117.      * Sometimes attribute 'url_path' can be empty, because url_path hasn't been generated yet,
  118.      * in this case category is loaded with empty url_path and we should generate it manually.
  119.      *
  120.      * @param Varien_Object $category
  121.      * @return void
  122.      */
  123.     protected function _addCategoryUrlPath($category)
  124.     {
  125.         if (!($category instanceof Varien_Object) || $category->getUrlPath()) {
  126.             return;
  127.         }
  128.  
  129.         // This routine is not intended to be used with root categories,
  130.         // but handle 'em gracefully - ensure them to have empty path.
  131.         if ($category->getLevel() <= 1) {
  132.             $category->setUrlPath('');
  133.             return;
  134.         }
  135.  
  136.         if (self::$_categoryForUrlPath === null) {
  137.             self::$_categoryForUrlPath = Mage::getModel('catalog/category');
  138.         }
  139.  
  140.         // Generate url_path
  141.         $urlPath = self::$_categoryForUrlPath
  142.             ->setData($category->getData())
  143.             ->getUrlPath();
  144.         $category->setUrlPath($urlPath);
  145.     }
  146.  
  147.     /**
  148.      * Retrieve stores array or store model
  149.      *
  150.      * @param int $storeId
  151.      * @return Mage_Core_Model_Store|array
  152.      */
  153.     public function getStores($storeId = null)
  154.     {
  155.         return $this->getResource()->getStores($storeId);
  156.     }
  157.  
  158.     /**
  159.      * Retrieve resource model
  160.      *
  161.      * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Url
  162.      */
  163.     public function getResource()
  164.     {
  165.         if (is_null($this->_resourceModel)) {
  166.             $this->_resourceModel = Mage::getResourceModel('catalog/url');
  167.         }
  168.         return $this->_resourceModel;
  169.     }
  170.  
  171.     /**
  172.      * Retrieve Category model singleton
  173.      *
  174.      * @return Mage_Catalog_Model_Category
  175.      */
  176.     public function getCategoryModel()
  177.     {
  178.         return $this->getResource()->getCategoryModel();
  179.     }
  180.  
  181.     /**
  182.      * Retrieve product model singleton
  183.      *
  184.      * @return Mage_Catalog_Model_Product
  185.      */
  186.     public function getProductModel()
  187.     {
  188.         return $this->getResource()->getProductModel();
  189.     }
  190.  
  191.     /**
  192.      * Returns store root category, uses caching for it
  193.      *
  194.      * @param int $storeId
  195.      * @return Varien_Object
  196.      */
  197.     public function getStoreRootCategory($storeId) {
  198.         if (!array_key_exists($storeId, $this->_rootCategories)) {
  199.             $category = null;
  200.             $store = $this->getStores($storeId);
  201.             if ($store) {
  202.                 $rootCategoryId = $store->getRootCategoryId();
  203.                 $category = $this->getResource()->getCategory($rootCategoryId, $storeId);
  204.             }
  205.             $this->_rootCategories[$storeId] = $category;
  206.         }
  207.         return $this->_rootCategories[$storeId];
  208.     }
  209.  
  210.     /**
  211.      * Setter for $_saveRewritesHistory
  212.      * Force Rewrites History save bypass config settings
  213.      *
  214.      * @param bool $flag
  215.      * @return Mage_Catalog_Model_Url
  216.      */
  217.     public function setShouldSaveRewritesHistory($flag)
  218.     {
  219.         $this->_saveRewritesHistory = (bool)$flag;
  220.         return $this;
  221.     }
  222.  
  223.     /**
  224.      * Indicate whether to save URL Rewrite History or not (create redirects to old URLs)
  225.      *
  226.      * @param int $storeId Store View
  227.      * @return bool
  228.      */
  229.     public function getShouldSaveRewritesHistory($storeId = null)
  230.     {
  231.         if ($this->_saveRewritesHistory !== null) {
  232.             return $this->_saveRewritesHistory;
  233.         }
  234.         return Mage::helper('catalog')->shouldSaveUrlRewritesHistory($storeId);
  235.     }
  236.  
  237.     /**
  238.      * Refresh all rewrite urls for some store or for all stores
  239.      * Used to make full reindexing of url rewrites
  240.      *
  241.      * @param int $storeId
  242.      * @return Mage_Catalog_Model_Url
  243.      */
  244.     public function refreshRewrites($storeId = null)
  245.     {
  246.         if (is_null($storeId)) {
  247.             foreach ($this->getStores() as $store) {
  248.                 $this->refreshRewrites($store->getId());
  249.             }
  250.             return $this;
  251.         }
  252.  
  253.         $this->clearStoreInvalidRewrites($storeId);
  254.         $this->refreshCategoryRewrite($this->getStores($storeId)->getRootCategoryId(), $storeId, false);
  255.         $this->refreshProductRewrites($storeId);
  256.         $this->getResource()->clearCategoryProduct($storeId);
  257.  
  258.         return $this;
  259.     }
  260.  
  261.     /**
  262.      * Refresh category rewrite
  263.      *
  264.      * @param Varien_Object $category
  265.      * @param string $parentPath
  266.      * @param bool $refreshProducts
  267.      * @return Mage_Catalog_Model_Url
  268.      */
  269.     protected function _refreshCategoryRewrites(Varien_Object $category, $parentPath = null, $refreshProducts = true)
  270.     {
  271.         if ($category->getId() != $this->getStores($category->getStoreId())->getRootCategoryId()) {
  272.             if ($category->getUrlKey() == '') {
  273.                 $urlKey = $this->getCategoryModel()->formatUrlKey($category->getName());
  274.             }
  275.             else {
  276.                 $urlKey = $this->getCategoryModel()->formatUrlKey($category->getUrlKey());
  277.             }
  278.  
  279.             $idPath      = $this->generatePath('id', null, $category);
  280.             $targetPath  = $this->generatePath('target', null, $category);
  281.             $requestPath = $this->getCategoryRequestPath($category, $parentPath);
  282.  
  283.             $rewriteData = array(
  284.                 'store_id'      => $category->getStoreId(),
  285.                 'category_id'   => $category->getId(),
  286.                 'product_id'    => null,
  287.                 'id_path'       => $idPath,
  288.                 'request_path'  => $requestPath,
  289.                 'target_path'   => $targetPath,
  290.                 'is_system'     => 1
  291.             );
  292.  
  293.             $this->getResource()->saveRewrite($rewriteData, $this->_rewrite);
  294.  
  295.             if ($this->getShouldSaveRewritesHistory($category->getStoreId())) {
  296.                 $this->_saveRewriteHistory($rewriteData, $this->_rewrite);
  297.             }
  298.  
  299.             if ($category->getUrlKey() != $urlKey) {
  300.                 $category->setUrlKey($urlKey);
  301.                 $this->getResource()->saveCategoryAttribute($category, 'url_key');
  302.             }
  303.             if ($category->getUrlPath() != $requestPath) {
  304.                 $category->setUrlPath($requestPath);
  305.                 $this->getResource()->saveCategoryAttribute($category, 'url_path');
  306.             }
  307.         }
  308.         else {
  309.             if ($category->getUrlPath() != '') {
  310.                 $category->setUrlPath('');
  311.                 $this->getResource()->saveCategoryAttribute($category, 'url_path');
  312.             }
  313.         }
  314.  
  315.         if ($refreshProducts) {
  316.             $this->_refreshCategoryProductRewrites($category);
  317.         }
  318.  
  319.         foreach ($category->getChilds() as $child) {
  320.             $this->_refreshCategoryRewrites($child, $category->getUrlPath() . '/', $refreshProducts);
  321.         }
  322.  
  323.         return $this;
  324.     }
  325.  
  326.     /**
  327.      * Refresh product rewrite
  328.      *
  329.      * @param Varien_Object $product
  330.      * @param Varien_Object $category
  331.      * @return Mage_Catalog_Model_Url
  332.      */
  333.     protected function _refreshProductRewrite(Varien_Object $product, Varien_Object $category)
  334.     {
  335.         if ($category->getId() == $category->getPath()) {
  336.             return $this;
  337.         }
  338.         if ($product->getUrlKey() == '') {
  339.             $urlKey = $this->getProductModel()->formatUrlKey($product->getName());
  340.         }
  341.         else {
  342.             $urlKey = $this->getProductModel()->formatUrlKey($product->getUrlKey());
  343.         }
  344.  
  345.         $idPath      = $this->generatePath('id', $product, $category);
  346.         $targetPath  = $this->generatePath('target', $product, $category);
  347.         $requestPath = $this->getProductRequestPath($product, $category);
  348.  
  349.         $categoryId = null;
  350.         $updateKeys = true;
  351.         if ($category->getLevel() > 1) {
  352.             $categoryId = $category->getId();
  353.             $updateKeys = false;
  354.         }
  355.  
  356.         $rewriteData = array(
  357.             'store_id'      => $category->getStoreId(),
  358.             'category_id'   => $categoryId,
  359.             'product_id'    => $product->getId(),
  360.             'id_path'       => $idPath,
  361.             'request_path'  => $requestPath,
  362.             'target_path'   => $targetPath,
  363.             'is_system'     => 1
  364.         );
  365.  
  366.         $this->getResource()->saveRewrite($rewriteData, $this->_rewrite);
  367.  
  368.         if ($this->getShouldSaveRewritesHistory($category->getStoreId())) {
  369.             $this->_saveRewriteHistory($rewriteData, $this->_rewrite);
  370.         }
  371.  
  372.         if ($updateKeys && $product->getUrlKey() != $urlKey) {
  373.             $product->setUrlKey($urlKey);
  374.             $this->getResource()->saveProductAttribute($product, 'url_key');
  375.         }
  376.         if ($updateKeys && $product->getUrlPath() != $requestPath) {
  377.             $product->setUrlPath($requestPath);
  378.             $this->getResource()->saveProductAttribute($product, 'url_path');
  379.         }
  380.  
  381.         return $this;
  382.     }
  383.  
  384.     /**
  385.      * Refresh products for catwgory
  386.      *
  387.      * @param Varien_Object $category
  388.      * @return Mage_Catalog_Model_Url
  389.      */
  390.     protected function _refreshCategoryProductRewrites(Varien_Object $category)
  391.     {
  392.         $originalRewrites = $this->_rewrites;
  393.         $process = true;
  394.         $lastEntityId = 0;
  395.         $firstIteration = true;
  396.         while ($process == true) {
  397.             $products = $this->getResource()->getProductsByCategory($category, $lastEntityId);
  398.             if (!$products) {
  399.                 if ($firstIteration) {
  400.                     $this->getResource()->deleteCategoryProductStoreRewrites(
  401.                         $category->getId(),
  402.                         array(),
  403.                         $category->getStoreId()
  404.                     );
  405.                 }
  406.                 $process = false;
  407.                 break;
  408.             }
  409.  
  410.             // Prepare rewrites for generation
  411.             $rootCategory = $this->getStoreRootCategory($category->getStoreId());
  412.             $categoryIds = array($category->getId(), $rootCategory->getId());
  413.             $this->_rewrites = $this->getResource()->prepareRewrites(
  414.                 $category->getStoreId(),
  415.                 $categoryIds,
  416.                 array_keys($products)
  417.             );
  418.  
  419.             foreach ($products as $product) {
  420.                 // Product always must have rewrite in root category
  421.                 $this->_refreshProductRewrite($product, $rootCategory);
  422.                 $this->_refreshProductRewrite($product, $category);
  423.             }
  424.             $firstIteration = false;
  425.             unset($products);
  426.         }
  427.         $this->_rewrites = $originalRewrites;
  428.         return $this;
  429.     }
  430.  
  431.     /**
  432.      * Refresh category and childs rewrites
  433.      * Called when reindexing all rewrites and as a reaction on category change that affects rewrites
  434.      *
  435.      * @param int $categoryId
  436.      * @param int|null $storeId
  437.      * @param bool $refreshProducts
  438.      * @return Mage_Catalog_Model_Url
  439.      */
  440.     public function refreshCategoryRewrite($categoryId, $storeId = null, $refreshProducts = true)
  441.     {
  442.         if (is_null($storeId)) {
  443.             foreach ($this->getStores() as $store) {
  444.                 $this->refreshCategoryRewrite($categoryId, $store->getId(), $refreshProducts);
  445.             }
  446.             return $this;
  447.         }
  448.  
  449.         $category = $this->getResource()->getCategory($categoryId, $storeId);
  450.         if (!$category) {
  451.             return $this;
  452.         }
  453.  
  454.         // Load all childs and refresh all categories
  455.         $category = $this->getResource()->loadCategoryChilds($category);
  456.         $categoryIds = array($category->getId());
  457.         if ($category->getAllChilds()) {
  458.             $categoryIds = array_merge($categoryIds, array_keys($category->getAllChilds()));
  459.         }
  460.         $this->_rewrites = $this->getResource()->prepareRewrites($storeId, $categoryIds);
  461.         $this->_refreshCategoryRewrites($category, null, $refreshProducts);
  462.  
  463.         unset($category);
  464.         $this->_rewrites = array();
  465.  
  466.         return $this;
  467.     }
  468.  
  469.     /**
  470.      * Refresh product rewrite urls for one store or all stores
  471.      * Called as a reaction on product change that affects rewrites
  472.      *
  473.      * @param int $productId
  474.      * @param int|null $storeId
  475.      * @return Mage_Catalog_Model_Url
  476.      */
  477.     public function refreshProductRewrite($productId, $storeId = null)
  478.     {
  479.         if (is_null($storeId)) {
  480.             foreach ($this->getStores() as $store) {
  481.                 $this->refreshProductRewrite($productId, $store->getId());
  482.             }
  483.             return $this;
  484.         }
  485.  
  486.         $product = $this->getResource()->getProduct($productId, $storeId);
  487.         if ($product) {
  488.             $store = $this->getStores($storeId);
  489.             $storeRootCategoryId = $store->getRootCategoryId();
  490.  
  491.             // List of categories the product is assigned to, filtered by being within the store's categories root
  492.             $categories = $this->getResource()->getCategories($product->getCategoryIds(), $storeId);
  493.             $this->_rewrites = $this->getResource()->prepareRewrites($storeId, '', $productId);
  494.  
  495.             // Add rewrites for all needed categories
  496.             // If product is assigned to any of store's categories -
  497.             // we also should use store root category to create root product url rewrite
  498.             if (!isset($categories[$storeRootCategoryId])) {
  499.                 $categories[$storeRootCategoryId] = $this->getResource()->getCategory($storeRootCategoryId, $storeId);
  500.             }
  501.  
  502.             // Create product url rewrites
  503.             foreach ($categories as $category) {
  504.                 $this->_refreshProductRewrite($product, $category);
  505.             }
  506.  
  507.             // Remove all other product rewrites created earlier for this store - they're invalid now
  508.             $excludeCategoryIds = array_keys($categories);
  509.             $this->getResource()->clearProductRewrites($productId, $storeId, $excludeCategoryIds);
  510.  
  511.             unset($categories);
  512.             unset($product);
  513.         } else {
  514.             // Product doesn't belong to this store - clear all its url rewrites including root one
  515.             $this->getResource()->clearProductRewrites($productId, $storeId, array());
  516.         }
  517.  
  518.         return $this;
  519.     }
  520.  
  521.     /**
  522.      * Refresh all product rewrites for designated store
  523.      *
  524.      * @param int $storeId
  525.      * @return Mage_Catalog_Model_Url
  526.      */
  527.     public function refreshProductRewrites($storeId)
  528.     {
  529.         $this->_categories      = array();
  530.         $storeRootCategoryId    = $this->getStores($storeId)->getRootCategoryId();
  531.         $storeRootCategoryPath  = $this->getStores($storeId)->getRootCategoryPath();
  532.         $this->_categories[$storeRootCategoryId] = $this->getResource()->getCategory($storeRootCategoryId, $storeId);
  533.  
  534.         $lastEntityId = 0;
  535.         $process = true;
  536.  
  537.         while ($process == true) {
  538.             $products = $this->getResource()->getProductsByStore($storeId, $lastEntityId);
  539.             if (!$products) {
  540.                 $process = false;
  541.                 break;
  542.             }
  543.  
  544.             $this->_rewrites = $this->getResource()->prepareRewrites($storeId, false, array_keys($products));
  545.  
  546.             $loadCategories = array();
  547.             foreach ($products as $product) {
  548.                 foreach ($product->getCategoryIds() as $categoryId) {
  549.                     if (!isset($this->_categories[$categoryId])) {
  550.                         $loadCategories[$categoryId] = $categoryId;
  551.                     }
  552.                 }
  553.             }
  554.  
  555.             if ($loadCategories) {
  556.                 foreach ($this->getResource()->getCategories($loadCategories, $storeId) as $category) {
  557.                     $this->_categories[$category->getId()] = $category;
  558.                 }
  559.             }
  560.  
  561.             foreach ($products as $product) {
  562.                 $this->_refreshProductRewrite($product, $this->_categories[$storeRootCategoryId]);
  563.                 foreach ($product->getCategoryIds() as $categoryId) {
  564.                     if ($categoryId != $storeRootCategoryId && isset($this->_categories[$categoryId])) {
  565.                         if (strpos($this->_categories[$categoryId]['path'], $storeRootCategoryPath . '/') !== 0) {
  566.                             continue;
  567.                         }
  568.                         $this->_refreshProductRewrite($product, $this->_categories[$categoryId]);
  569.                     }
  570.                 }
  571.             }
  572.  
  573.             unset($products);
  574.             $this->_rewrites = array();
  575.         }
  576.  
  577.         $this->_categories = array();
  578.         return $this;
  579.     }
  580.  
  581.     /**
  582.      * Deletes old rewrites for store, left from the times when store had some other root category
  583.      *
  584.      * @param int $storeId
  585.      * @return Mage_Catalog_Model_Url
  586.      */
  587.     public function clearStoreInvalidRewrites($storeId = null)
  588.     {
  589.         if (is_null($storeId)) {
  590.             foreach ($this->getStores() as $store) {
  591.                 $this->clearStoreInvalidRewrites($store->getId());
  592.             }
  593.             return $this;
  594.         }
  595.  
  596.         $this->getResource()->clearStoreInvalidRewrites($storeId);
  597.         return $this;
  598.     }
  599.  
  600.     /**
  601.      * Get requestPath that was not used yet.
  602.      *
  603.      * Will try to get unique path by adding -1 -2 etc. between url_key and optional url_suffix
  604.      *
  605.      * @param int $storeId
  606.      * @param string $requestPath
  607.      * @param string $idPath
  608.      * @return string
  609.      */
  610.     public function getUnusedPath($storeId, $requestPath, $idPath)
  611.     {
  612.         if (strpos($idPath, 'product') !== false) {
  613.             $suffix = $this->getProductUrlSuffix($storeId);
  614.         } else {
  615.             $suffix = $this->getCategoryUrlSuffix($storeId);
  616.         }
  617.         if (empty($requestPath)) {
  618.             $requestPath = '-';
  619.         } elseif ($requestPath == $suffix) {
  620.             $requestPath = '-' . $suffix;
  621.         }
  622.  
  623.         /**
  624.          * Validate maximum length of request path
  625.          */
  626.         if (strlen($requestPath) > self::MAX_REQUEST_PATH_LENGTH + self::ALLOWED_REQUEST_PATH_OVERFLOW) {
  627.             $requestPath = substr($requestPath, 0, self::MAX_REQUEST_PATH_LENGTH);
  628.         }
  629.  
  630.         if (isset($this->_rewrites[$idPath])) {
  631.             $this->_rewrite = $this->_rewrites[$idPath];
  632.             if ($this->_rewrites[$idPath]->getRequestPath() == $requestPath) {
  633.                 return $requestPath;
  634.             }
  635.         }
  636.         else {
  637.             $this->_rewrite = null;
  638.         }
  639.  
  640.         $rewrite = $this->getResource()->getRewriteByRequestPath($requestPath, $storeId);
  641.         if ($rewrite && $rewrite->getId()) {
  642.             if ($rewrite->getIdPath() == $idPath) {
  643.                 $this->_rewrite = $rewrite;
  644.                 return $requestPath;
  645.             }
  646.             // match request_url abcdef1234(-12)(.html) pattern
  647.             $match = array();
  648.             $regularExpression = '#^([0-9a-z/-]+?)(-([0-9]+))?('.preg_quote($suffix).')?$#i';
  649.             if (!preg_match($regularExpression, $requestPath, $match)) {
  650.                 return $this->getUnusedPath($storeId, '-', $idPath);
  651.             }
  652.             $match[1] = $match[1] . '-';
  653.             $match[4] = isset($match[4]) ? $match[4] : '';
  654.  
  655.             $lastRequestPath = $this->getResource()
  656.                 ->getLastUsedRewriteRequestIncrement($match[1], $match[4], $storeId);
  657.             if ($lastRequestPath) {
  658.                 $match[3] = $lastRequestPath;
  659.             }
  660.             return $match[1]
  661.                 . (isset($match[3]) ? ($match[3]+1) : '1')
  662.                 . $match[4];
  663.         }
  664.         else {
  665.             return $requestPath;
  666.         }
  667.     }
  668.  
  669.     /**
  670.      * Retrieve product rewrite sufix for store
  671.      *
  672.      * @param int $storeId
  673.      * @return string
  674.      */
  675.     public function getProductUrlSuffix($storeId)
  676.     {
  677.         return Mage::helper('catalog/product')->getProductUrlSuffix($storeId);
  678.     }
  679.  
  680.     /**
  681.      * Retrieve category rewrite sufix for store
  682.      *
  683.      * @param int $storeId
  684.      * @return string
  685.      */
  686.     public function getCategoryUrlSuffix($storeId)
  687.     {
  688.         return Mage::helper('catalog/category')->getCategoryUrlSuffix($storeId);
  689.     }
  690.  
  691.     /**
  692.      * Get unique category request path
  693.      *
  694.      * @param Varien_Object $category
  695.      * @param string $parentPath
  696.      * @return string
  697.      */
  698.     public function getCategoryRequestPath($category, $parentPath)
  699.     {
  700.         $storeId = $category->getStoreId();
  701.         $idPath  = $this->generatePath('id', null, $category);
  702.         $suffix  = $this->getCategoryUrlSuffix($storeId);
  703.  
  704.         if (isset($this->_rewrites[$idPath])) {
  705.             $this->_rewrite = $this->_rewrites[$idPath];
  706.             $existingRequestPath = $this->_rewrites[$idPath]->getRequestPath();
  707.         }
  708.  
  709.         if ($category->getUrlKey() == '') {
  710.             $urlKey = $this->getCategoryModel()->formatUrlKey($category->getName());
  711.         }
  712.         else {
  713.             $urlKey = $this->getCategoryModel()->formatUrlKey($category->getUrlKey());
  714.         }
  715.  
  716.         $categoryUrlSuffix = $this->getCategoryUrlSuffix($category->getStoreId());
  717.         if (null === $parentPath) {
  718.             $parentPath = $this->getResource()->getCategoryParentPath($category);
  719.         }
  720.         elseif ($parentPath == '/') {
  721.             $parentPath = '';
  722.         }
  723.         $parentPath = Mage::helper('catalog/category')->getCategoryUrlPath($parentPath,
  724.                                                                            true, $category->getStoreId());
  725.  
  726.         $requestPath = $parentPath . $urlKey . $categoryUrlSuffix;
  727.         if (isset($existingRequestPath) && $existingRequestPath == $requestPath . $suffix) {
  728.             return $existingRequestPath;
  729.         }
  730.  
  731.         if ($this->_deleteOldTargetPath($requestPath, $idPath, $storeId)) {
  732.             return $requestPath;
  733.         }
  734.  
  735.         return $this->getUnusedPath($category->getStoreId(), $requestPath,
  736.                                     $this->generatePath('id', null, $category)
  737.         );
  738.     }
  739.  
  740.     /**
  741.      * Check if current generated request path is one of the old paths
  742.      *
  743.      * @param string $requestPath
  744.      * @param string $idPath
  745.      * @param int $storeId
  746.      * @return bool
  747.      */
  748.     protected function _deleteOldTargetPath($requestPath, $idPath, $storeId)
  749.     {
  750.         $finalOldTargetPath = $this->getResource()->findFinalTargetPath($requestPath, $storeId);
  751.         if ($finalOldTargetPath && $finalOldTargetPath == $idPath) {
  752.             $this->getResource()->deleteRewriteRecord($requestPath, $storeId, true);
  753.             return true;
  754.         }
  755.  
  756.         return false;
  757.     }
  758.  
  759.     /**
  760.      * Get unique product request path
  761.      *
  762.      * @param   Varien_Object $product
  763.      * @param   Varien_Object $category
  764.      * @return  string
  765.      */
  766.     public function getProductRequestPath($product, $category)
  767.     {
  768.         if ($product->getUrlKey() == '') {
  769.             $urlKey = $this->getProductModel()->formatUrlKey($product->getName());
  770.         } else {
  771.             $urlKey = $this->getProductModel()->formatUrlKey($product->getUrlKey());
  772.         }
  773.         $storeId = $category->getStoreId();
  774.         $suffix  = $this->getProductUrlSuffix($storeId);
  775.         $idPath  = $this->generatePath('id', $product, $category);
  776.         /**
  777.          * Prepare product base request path
  778.          */
  779.         if ($category->getLevel() > 1) {
  780.             // To ensure, that category has path either from attribute or generated now
  781.             $this->_addCategoryUrlPath($category);
  782.             $categoryUrl = Mage::helper('catalog/category')->getCategoryUrlPath($category->getUrlPath(),
  783.                 false, $storeId);
  784.             $requestPath = $categoryUrl . '/' . $urlKey;
  785.         } else {
  786.             $requestPath = $urlKey;
  787.         }
  788.  
  789.         if (strlen($requestPath) > self::MAX_REQUEST_PATH_LENGTH + self::ALLOWED_REQUEST_PATH_OVERFLOW) {
  790.             $requestPath = substr($requestPath, 0, self::MAX_REQUEST_PATH_LENGTH);
  791.         }
  792.  
  793.         $this->_rewrite = null;
  794.         /**
  795.          * Check $requestPath should be unique
  796.          */
  797.         if (isset($this->_rewrites[$idPath])) {
  798.             $this->_rewrite = $this->_rewrites[$idPath];
  799.             $existingRequestPath = $this->_rewrites[$idPath]->getRequestPath();
  800.  
  801.             if ($existingRequestPath == $requestPath . $suffix) {
  802.                 return $existingRequestPath;
  803.             }
  804.  
  805.             $existingRequestPath = preg_replace('/' . preg_quote($suffix, '/') . '$/', '', $existingRequestPath);
  806.             /**
  807.              * Check if existing request past can be used
  808.              */
  809.             if ($product->getUrlKey() == '' && !empty($requestPath)
  810.                 && strpos($existingRequestPath, $requestPath) === 0
  811.             ) {
  812.                 $existingRequestPath = preg_replace(
  813.                     '/^' . preg_quote($requestPath, '/') . '/', '', $existingRequestPath
  814.                 );
  815.                 if (preg_match('#^-([0-9]+)$#i', $existingRequestPath)) {
  816.                     return $this->_rewrites[$idPath]->getRequestPath();
  817.                 }
  818.             }
  819.  
  820.             $fullPath = $requestPath.$suffix;
  821.             if ($this->_deleteOldTargetPath($fullPath, $idPath, $storeId)) {
  822.                 return $fullPath;
  823.             }
  824.         }
  825.         /**
  826.          * Check 2 variants: $requestPath and $requestPath . '-' . $productId
  827.          */
  828.         $validatedPath = $this->getResource()->checkRequestPaths(
  829.             array($requestPath.$suffix, $requestPath.'-'.$product->getId().$suffix),
  830.             $storeId
  831.         );
  832.  
  833.         if ($validatedPath) {
  834.             return $validatedPath;
  835.         }
  836.         /**
  837.          * Use unique path generator
  838.          */
  839.         return $this->getUnusedPath($storeId, $requestPath.$suffix, $idPath);
  840.     }
  841.  
  842.     /**
  843.      * Generate either id path, request path or target path for product and/or category
  844.      *
  845.      * For generating id or system path, either product or category is required
  846.      * For generating request path - category is required
  847.      * $parentPath used only for generating category path
  848.      *
  849.      * @param string $type
  850.      * @param Varien_Object $product
  851.      * @param Varien_Object $category
  852.      * @param string $parentPath
  853.      * @return string
  854.      * @throws Mage_Core_Exception
  855.      */
  856.     public function generatePath($type = 'target', $product = null, $category = null, $parentPath = null)
  857.     {
  858.         if (!$product && !$category) {
  859.             Mage::throwException(Mage::helper('core')->__('Please specify either a category or a product, or both.'));
  860.         }
  861.  
  862.         // generate id_path
  863.         if ('id' === $type) {
  864.             if (!$product) {
  865.                 return 'category/' . $category->getId();
  866.             }
  867.             if ($category && $category->getLevel() > 1) {
  868.                 return 'product/' . $product->getId() . '/' . $category->getId();
  869.             }
  870.             return 'product/' . $product->getId();
  871.         }
  872.  
  873.         // generate request_path
  874.         if ('request' === $type) {
  875.             // for category
  876.             if (!$product) {
  877.                 if ($category->getUrlKey() == '') {
  878.                     $urlKey = $this->getCategoryModel()->formatUrlKey($category->getName());
  879.                 }
  880.                 else {
  881.                     $urlKey = $this->getCategoryModel()->formatUrlKey($category->getUrlKey());
  882.                 }
  883.  
  884.                 $categoryUrlSuffix = $this->getCategoryUrlSuffix($category->getStoreId());
  885.                 if (null === $parentPath) {
  886.                     $parentPath = $this->getResource()->getCategoryParentPath($category);
  887.                 }
  888.                 elseif ($parentPath == '/') {
  889.                     $parentPath = '';
  890.                 }
  891.                 $parentPath = Mage::helper('catalog/category')->getCategoryUrlPath($parentPath,
  892.                     true, $category->getStoreId());
  893.  
  894.                 return $this->getUnusedPath($category->getStoreId(), $parentPath . $urlKey . $categoryUrlSuffix,
  895.                     $this->generatePath('id', null, $category)
  896.                 );
  897.             }
  898.  
  899.             // for product & category
  900.             if (!$category) {
  901.                 Mage::throwException(Mage::helper('core')->__('A category object is required for determining the product request path.')); // why?
  902.             }
  903.  
  904.             if ($product->getUrlKey() == '') {
  905.                 $urlKey = $this->getProductModel()->formatUrlKey($product->getName());
  906.             }
  907.             else {
  908.                 $urlKey = $this->getProductModel()->formatUrlKey($product->getUrlKey());
  909.             }
  910.             $productUrlSuffix  = $this->getProductUrlSuffix($category->getStoreId());
  911.             if ($category->getLevel() > 1) {
  912.                 // To ensure, that category has url path either from attribute or generated now
  913.                 $this->_addCategoryUrlPath($category);
  914.                 $categoryUrl = Mage::helper('catalog/category')->getCategoryUrlPath($category->getUrlPath(),
  915.                     false, $category->getStoreId());
  916.                 return $this->getUnusedPath($category->getStoreId(), $categoryUrl . '/' . $urlKey . $productUrlSuffix,
  917.                     $this->generatePath('id', $product, $category)
  918.                 );
  919.             }
  920.  
  921.             // for product only
  922.             return $this->getUnusedPath($category->getStoreId(), $urlKey . $productUrlSuffix,
  923.                 $this->generatePath('id', $product)
  924.             );
  925.         }
  926.  
  927.         // generate target_path
  928.         if (!$product) {
  929.             return 'catalog/category/view/id/' . $category->getId();
  930.         }
  931.         if ($category && $category->getLevel() > 1) {
  932.             return 'catalog/product/view/id/' . $product->getId() . '/category/' . $category->getId();
  933.         }
  934.         return 'catalog/product/view/id/' . $product->getId();
  935.     }
  936.  
  937.     /**
  938.      * Return unique string based on the time in microseconds.
  939.      *
  940.      * @return string
  941.      */
  942.     public function generateUniqueIdPath()
  943.     {
  944.         return str_replace('0.', '', str_replace(' ', '_', microtime()));
  945.     }
  946.  
  947.     /**
  948.      * Create Custom URL Rewrite for old product/category URL after url_key changed
  949.      * It will perform permanent redirect from old URL to new URL
  950.      *
  951.      * @param array $rewriteData New rewrite data
  952.      * @param Varien_Object $rewrite Rewrite model
  953.      * @return Mage_Catalog_Model_Url
  954.      */
  955.     protected function _saveRewriteHistory($rewriteData, $rewrite)
  956.     {
  957.         if ($rewrite instanceof Varien_Object && $rewrite->getId()) {
  958.             $rewriteData['target_path'] = $rewriteData['request_path'];
  959.             $rewriteData['request_path'] = $rewrite->getRequestPath();
  960.             $rewriteData['id_path'] = $this->generateUniqueIdPath();
  961.             $rewriteData['is_system'] = 0;
  962.             $rewriteData['options'] = 'RP'; // Redirect = Permanent
  963.             $this->getResource()->saveRewriteHistory($rewriteData);
  964.         }
  965.  
  966.         return $this;
  967.     }
  968. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement