vendor/pimcore/pimcore/models/DataObject/Data/UrlSlug.php line 31

Open in your IDE?
  1. <?php
  2. /**
  3.  * Pimcore
  4.  *
  5.  * This source file is available under two different licenses:
  6.  * - GNU General Public License version 3 (GPLv3)
  7.  * - Pimcore Commercial License (PCL)
  8.  * Full copyright and license information is available in
  9.  * LICENSE.md which is distributed with this source code.
  10.  *
  11.  *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
  12.  *  @license    http://www.pimcore.org/license     GPLv3 and PCL
  13.  */
  14. namespace Pimcore\Model\DataObject\Data;
  15. use Pimcore\Db;
  16. use Pimcore\Logger;
  17. use Pimcore\Model\DataObject\ClassDefinition;
  18. use Pimcore\Model\DataObject\ClassDefinition\Data\Localizedfields;
  19. use Pimcore\Model\DataObject\ClassDefinition\Data\Objectbricks;
  20. use Pimcore\Model\DataObject\Concrete;
  21. use Pimcore\Model\DataObject\Fieldcollection;
  22. use Pimcore\Model\DataObject\Fieldcollection\Data\AbstractData;
  23. use Pimcore\Model\DataObject\Objectbrick\Definition;
  24. use Pimcore\Model\DataObject\OwnerAwareFieldInterface;
  25. use Pimcore\Model\DataObject\Traits\ObjectVarTrait;
  26. use Pimcore\Model\DataObject\Traits\OwnerAwareFieldTrait;
  27. class UrlSlug implements OwnerAwareFieldInterface
  28. {
  29.     use ObjectVarTrait;
  30.     use OwnerAwareFieldTrait;
  31.     public const TABLE_NAME 'object_url_slugs';
  32.     /**
  33.      * @var int
  34.      */
  35.     protected $objectId;
  36.     /**
  37.      * @var string
  38.      */
  39.     protected $classId;
  40.     /**
  41.      * @var string|null
  42.      */
  43.     protected $slug;
  44.     /**
  45.      * @var int|null
  46.      */
  47.     protected $siteId;
  48.     /**
  49.      * @var string
  50.      */
  51.     protected $fieldname;
  52.     /**
  53.      * @var int
  54.      */
  55.     protected $index;
  56.     /**
  57.      * @var string
  58.      */
  59.     protected $ownertype;
  60.     /**
  61.      * @var string
  62.      */
  63.     protected $ownername;
  64.     /**
  65.      * @var string
  66.      */
  67.     protected $position;
  68.     /**
  69.      * @var null|string
  70.      */
  71.     protected $previousSlug;
  72.     /**
  73.      * @var array
  74.      */
  75.     protected static $cache = [];
  76.     /**
  77.      * UrlSlug constructor.
  78.      *
  79.      * @param string|null $slug
  80.      * @param int|null $siteId
  81.      */
  82.     public function __construct(?string $slug, ?int $siteId 0)
  83.     {
  84.         $this->slug $slug;
  85.         $this->siteId $siteId ?? 0;
  86.     }
  87.     /**
  88.      * @return int
  89.      */
  90.     public function getObjectId(): int
  91.     {
  92.         return $this->objectId;
  93.     }
  94.     /**
  95.      * @param int $objectId
  96.      *
  97.      * @return $this
  98.      */
  99.     public function setObjectId(int $objectId)
  100.     {
  101.         $this->objectId $objectId;
  102.         return $this;
  103.     }
  104.     /**
  105.      * @return string|null
  106.      */
  107.     public function getSlug(): ?string
  108.     {
  109.         return $this->slug;
  110.     }
  111.     /**
  112.      * @param string|null $slug
  113.      *
  114.      * @return $this
  115.      */
  116.     public function setSlug(?string $slug)
  117.     {
  118.         $this->slug $slug;
  119.         return $this;
  120.     }
  121.     /**
  122.      * @internal
  123.      *
  124.      * @return string|null
  125.      */
  126.     public function getPreviousSlug(): ?string
  127.     {
  128.         return $this->previousSlug;
  129.     }
  130.     /**
  131.      * @internal
  132.      *
  133.      * @param string|null $previousSlug
  134.      */
  135.     public function setPreviousSlug(?string $previousSlug): void
  136.     {
  137.         $this->previousSlug $previousSlug;
  138.     }
  139.     /**
  140.      * @return int|null
  141.      */
  142.     public function getSiteId(): ?int
  143.     {
  144.         return $this->siteId;
  145.     }
  146.     /**
  147.      * @param int|null $siteId
  148.      *
  149.      * @return $this
  150.      */
  151.     public function setSiteId(?int $siteId)
  152.     {
  153.         $this->siteId $siteId ?? 0;
  154.         return $this;
  155.     }
  156.     /**
  157.      * @return string|null
  158.      */
  159.     public function getFieldname(): ?string
  160.     {
  161.         return $this->fieldname;
  162.     }
  163.     /**
  164.      * @param string|null $fieldname
  165.      *
  166.      * @return $this
  167.      */
  168.     public function setFieldname(?string $fieldname)
  169.     {
  170.         $this->fieldname $fieldname;
  171.         return $this;
  172.     }
  173.     /**
  174.      * @return int|null
  175.      */
  176.     public function getIndex(): ?int
  177.     {
  178.         return $this->index;
  179.     }
  180.     /**
  181.      * @param int|null $index
  182.      *
  183.      * @return $this
  184.      */
  185.     public function setIndex(?int $index)
  186.     {
  187.         $this->index $index;
  188.         return $this;
  189.     }
  190.     /**
  191.      * @return string|null
  192.      */
  193.     public function getOwnertype(): ?string
  194.     {
  195.         return $this->ownertype;
  196.     }
  197.     /**
  198.      * @param string|null $ownertype
  199.      *
  200.      * @return $this
  201.      */
  202.     public function setOwnertype(?string $ownertype)
  203.     {
  204.         $this->ownertype $ownertype;
  205.         return $this;
  206.     }
  207.     /**
  208.      * @return string|null
  209.      */
  210.     public function getOwnername(): ?string
  211.     {
  212.         return $this->ownername;
  213.     }
  214.     /**
  215.      * @param string|null $ownername
  216.      *
  217.      * @return $this
  218.      */
  219.     public function setOwnername(?string $ownername)
  220.     {
  221.         $this->ownername $ownername;
  222.         return $this;
  223.     }
  224.     /**
  225.      * @return string|null
  226.      */
  227.     public function getPosition(): ?string
  228.     {
  229.         return $this->position;
  230.     }
  231.     /**
  232.      * @param string|null $position
  233.      *
  234.      * @return $this
  235.      */
  236.     public function setPosition(?string $position)
  237.     {
  238.         $this->position $position;
  239.         return $this;
  240.     }
  241.     /**
  242.      * @return string
  243.      */
  244.     public function getClassId()
  245.     {
  246.         return $this->classId;
  247.     }
  248.     /**
  249.      * @param string $classId
  250.      *
  251.      * @return $this
  252.      */
  253.     public function setClassId($classId)
  254.     {
  255.         $this->classId $classId;
  256.         return $this;
  257.     }
  258.     /**
  259.      * @param array $rawItem
  260.      *
  261.      * @return UrlSlug
  262.      */
  263.     public static function createFromDataRow($rawItem): UrlSlug
  264.     {
  265.         $slug = new self($rawItem['slug'], $rawItem['siteId']);
  266.         $slug->setObjectId($rawItem['objectId']);
  267.         $slug->setClassId($rawItem['classId']);
  268.         $slug->setFieldname($rawItem['fieldname']);
  269.         $slug->setIndex($rawItem['index']);
  270.         $slug->setOwnertype($rawItem['ownertype']);
  271.         $slug->setOwnername($rawItem['ownername']);
  272.         $slug->setPosition($rawItem['position']);
  273.         $slug->setPreviousSlug($rawItem['slug']);
  274.         return $slug;
  275.     }
  276.     /**
  277.      * @internal
  278.      *
  279.      * @param string $path
  280.      * @param int $siteId
  281.      *
  282.      * @return UrlSlug|null
  283.      */
  284.     public static function resolveSlug($path$siteId 0)
  285.     {
  286.         $cacheKey $path '~~' $siteId;
  287.         if (isset(self::$cache[$cacheKey])) {
  288.             return self::$cache[$cacheKey];
  289.         }
  290.         $slug null;
  291.         $db Db::get();
  292.         try {
  293.             $filterSiteId 'siteId = 0';
  294.             if ($siteId) {
  295.                 $filterSiteId sprintf('(siteId = %d OR siteId = 0)'$siteId);
  296.             }
  297.             $query sprintf(
  298.                 'SELECT * FROM %s WHERE slug = %s AND %s ORDER BY siteId DESC LIMIT 1',
  299.                 self::TABLE_NAME,
  300.                 $db->quote($path),
  301.                 $filterSiteId
  302.             );
  303.             $rawItem $db->fetchRow($query);
  304.             if ($rawItem) {
  305.                 $slug self::createFromDataRow($rawItem);
  306.             }
  307.         } catch (\Exception $e) {
  308.             Logger::error((string) $e);
  309.         }
  310.         self::$cache[$cacheKey] = $slug;
  311.         return $slug;
  312.     }
  313.     /**
  314.      * @internal
  315.      *
  316.      * @return string
  317.      *
  318.      * @throws \Exception
  319.      */
  320.     public function getAction()
  321.     {
  322.         /** @var ClassDefinition\Data\UrlSlug $fd */
  323.         $fd null;
  324.         $classDefinition ClassDefinition::getById($this->getClassId());
  325.         if ($classDefinition) {
  326.             // reverse look up the field definition ...
  327.             if ($this->getOwnertype() === 'object') {
  328.                 $fd $classDefinition->getFieldDefinition($this->getFieldname());
  329.             } elseif ($this->getOwnertype() === 'localizedfield') {
  330.                 $ownerName $this->getOwnername();
  331.                 if (strpos($ownerName'~') !== false) {
  332.                     // this is a localized field inside a field collection or objectbrick
  333.                     $parts explode('~'$this->getOwnername());
  334.                     $type trim($parts[0], '/');
  335.                     $objectFieldnameParts $this->getOwnername();
  336.                     $objectFieldnameParts explode('~'$objectFieldnameParts);
  337.                     $objectFieldnameParts $objectFieldnameParts[1];
  338.                     $objectFieldname explode('/'$objectFieldnameParts);
  339.                     $objectFieldname $objectFieldname[0];
  340.                     if ($type == 'objectbrick') {
  341.                         $objectFieldDef $classDefinition->getFieldDefinition($objectFieldname);
  342.                         if ($objectFieldDef instanceof Objectbricks) {
  343.                             $allowedBricks $objectFieldDef->getAllowedTypes();
  344.                             if (is_array($allowedBricks)) {
  345.                                 foreach ($allowedBricks as $allowedBrick) {
  346.                                     $brickDef Definition::getByKey($allowedBrick);
  347.                                     if ($brickDef instanceof Definition) {
  348.                                         $lfDef $brickDef->getFieldDefinition('localizedfields');
  349.                                         if ($lfDef instanceof Localizedfields) {
  350.                                             $fd $lfDef->getFieldDefinition($this->getFieldname());
  351.                                             break;
  352.                                         }
  353.                                     }
  354.                                 }
  355.                             }
  356.                         }
  357.                     } elseif ($type == 'fieldcollection') {
  358.                         // note that for fieldcollections we need the object data for resolving the
  359.                         // fieldcollection type. alternative: store the fc type as well (similar to class id)
  360.                         $object Concrete::getById($this->getObjectId());
  361.                         $getter 'get' ucfirst($objectFieldname);
  362.                         if ($object && method_exists($object$getter)) {
  363.                             $fc $object->$getter();
  364.                             if ($fc instanceof Fieldcollection) {
  365.                                 $index explode('/'$objectFieldnameParts);
  366.                                 $index = (int) $index[1];
  367.                                 $item $fc->get($index);
  368.                                 if ($item instanceof AbstractData) {
  369.                                     if ($colDef Fieldcollection\Definition::getByKey($item->getType())) {
  370.                                         $lfDef $colDef->getFieldDefinition('localizedfields');
  371.                                         if ($lfDef instanceof Localizedfields) {
  372.                                             $fd $lfDef->getFieldDefinition($this->getFieldname());
  373.                                         }
  374.                                     }
  375.                                 }
  376.                             }
  377.                         }
  378.                     }
  379.                 } else {
  380.                     $lfDef $classDefinition->getFieldDefinition('localizedfields');
  381.                     if ($lfDef instanceof Localizedfields) {
  382.                         $fd $lfDef->getFieldDefinition($this->getFieldname());
  383.                     }
  384.                 }
  385.             } elseif ($this->getOwnertype() === 'objectbrick') {
  386.                 $brickDef Definition::getByKey($this->getPosition());
  387.                 if ($brickDef) {
  388.                     $fd $brickDef->getFieldDefinition($this->getFieldname());
  389.                 }
  390.             } elseif ($this->getOwnertype() == 'fieldcollection') {
  391.                 $ownerName $this->getOwnername();
  392.                 $getter 'get' ucfirst($ownerName);
  393.                 // note that for fieldcollections we need the object data for resolving the
  394.                 // fieldcollection type. alternative: store the fc type as well (similar to class id)
  395.                 $object Concrete::getById($this->getObjectId());
  396.                 if (method_exists($object$getter)) {
  397.                     $fcValue $object->$getter();
  398.                     if ($fcValue instanceof Fieldcollection) {
  399.                         $item $fcValue->get($this->getIndex());
  400.                         $fcType $item->getType();
  401.                         if ($fcDef Fieldcollection\Definition::getByKey($fcType)) {
  402.                             $fd $fcDef->getFieldDefinition($this->getFieldname());
  403.                         }
  404.                     }
  405.                 }
  406.             }
  407.         }
  408.         if (!$fd instanceof \Pimcore\Model\DataObject\ClassDefinition\Data\UrlSlug) {
  409.             // slug could not be resolved which means that the data model has changed in the meantime, delete me.
  410.             $this->delete();
  411.             throw new \Exception('Could not resolve field definition for slug: ' $this->getSlug(). '. Remove it!');
  412.         }
  413.         return $fd->getAction();
  414.     }
  415.     /**
  416.      * @throws \Exception
  417.      */
  418.     public function delete()
  419.     {
  420.         $db Db::get();
  421.         $db->delete(self::TABLE_NAME, ['slug' => $this->getSlug(), 'siteId' => $this->getSiteId()]);
  422.         $cacheKey $this->getSlug() . '~~' $this->getSiteId();
  423.         if (isset(self::$cache[$cacheKey])) {
  424.             unset(self::$cache[$cacheKey]);
  425.         }
  426.     }
  427.     /**
  428.      * @param int $siteId
  429.      *
  430.      * @throws \Exception
  431.      */
  432.     public static function handleSiteDeleted(int $siteId)
  433.     {
  434.         $db Db::get();
  435.         $db->delete(self::TABLE_NAME, ['siteId' => $siteId]);
  436.     }
  437.     /**
  438.      * @param string $classId
  439.      *
  440.      * @throws \Exception
  441.      */
  442.     public static function handleClassDeleted(string $classId)
  443.     {
  444.         $db Db::get();
  445.         $db->delete(self::TABLE_NAME, ['classId' => $classId]);
  446.     }
  447. }