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
  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
  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
  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
  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
  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.             $query sprintf(
  294.                 'SELECT * FROM %s WHERE slug = %s AND (siteId = %d OR siteId = 0) ORDER BY siteId DESC LIMIT 1',
  295.                 self::TABLE_NAME,
  296.                 $db->quote($path),
  297.                 $siteId
  298.             );
  299.             $rawItem $db->fetchRow($query);
  300.             if ($rawItem) {
  301.                 $slug self::createFromDataRow($rawItem);
  302.             }
  303.         } catch (\Exception $e) {
  304.             Logger::error($e);
  305.         }
  306.         self::$cache[$cacheKey] = $slug;
  307.         return $slug;
  308.     }
  309.     /**
  310.      * @internal
  311.      *
  312.      * @return string
  313.      *
  314.      * @throws \Exception
  315.      */
  316.     public function getAction()
  317.     {
  318.         /** @var ClassDefinition\Data\UrlSlug $fd */
  319.         $fd null;
  320.         $classDefinition ClassDefinition::getById($this->getClassId());
  321.         if ($classDefinition) {
  322.             // reverse look up the field definition ...
  323.             if ($this->getOwnertype() === 'object') {
  324.                 $fd $classDefinition->getFieldDefinition($this->getFieldname());
  325.             } elseif ($this->getOwnertype() === 'localizedfield') {
  326.                 $ownerName $this->getOwnername();
  327.                 if (strpos($ownerName'~') !== false) {
  328.                     // this is a localized field inside a field collection or objectbrick
  329.                     $parts explode('~'$this->getOwnername());
  330.                     $type trim($parts[0], '/');
  331.                     $objectFieldnameParts $this->getOwnername();
  332.                     $objectFieldnameParts explode('~'$objectFieldnameParts);
  333.                     $objectFieldnameParts $objectFieldnameParts[1];
  334.                     $objectFieldname explode('/'$objectFieldnameParts);
  335.                     $objectFieldname $objectFieldname[0];
  336.                     if ($type == 'objectbrick') {
  337.                         $objectFieldDef $classDefinition->getFieldDefinition($objectFieldname);
  338.                         if ($objectFieldDef instanceof Objectbricks) {
  339.                             $allowedBricks $objectFieldDef->getAllowedTypes();
  340.                             if (is_array($allowedBricks)) {
  341.                                 foreach ($allowedBricks as $allowedBrick) {
  342.                                     $brickDef Definition::getByKey($allowedBrick);
  343.                                     if ($brickDef instanceof Definition) {
  344.                                         $lfDef $brickDef->getFieldDefinition('localizedfields');
  345.                                         if ($lfDef instanceof Localizedfields) {
  346.                                             $fd $lfDef->getFieldDefinition($this->getFieldname());
  347.                                             break;
  348.                                         }
  349.                                     }
  350.                                 }
  351.                             }
  352.                         }
  353.                     } elseif ($type == 'fieldcollection') {
  354.                         // note that for fieldcollections we need the object data for resolving the
  355.                         // fieldcollection type. alternative: store the fc type as well (similar to class id)
  356.                         $object Concrete::getById($this->getObjectId());
  357.                         $getter 'get' ucfirst($objectFieldname);
  358.                         if ($object && method_exists($object$getter)) {
  359.                             $fc $object->$getter();
  360.                             if ($fc instanceof Fieldcollection) {
  361.                                 $index explode('/'$objectFieldnameParts);
  362.                                 $index $index[1];
  363.                                 $item $fc->get($index);
  364.                                 if ($item instanceof AbstractData) {
  365.                                     if ($colDef Fieldcollection\Definition::getByKey($item->getType())) {
  366.                                         $lfDef $colDef->getFieldDefinition('localizedfields');
  367.                                         if ($lfDef instanceof Localizedfields) {
  368.                                             $fd $lfDef->getFieldDefinition($this->getFieldname());
  369.                                         }
  370.                                     }
  371.                                 }
  372.                             }
  373.                         }
  374.                     }
  375.                 } else {
  376.                     $lfDef $classDefinition->getFieldDefinition('localizedfields');
  377.                     if ($lfDef instanceof Localizedfields) {
  378.                         $fd $lfDef->getFieldDefinition($this->getFieldname());
  379.                     }
  380.                 }
  381.             } elseif ($this->getOwnertype() === 'objectbrick') {
  382.                 $brickDef Definition::getByKey($this->getPosition());
  383.                 if ($brickDef) {
  384.                     $fd $brickDef->getFieldDefinition($this->getFieldname());
  385.                 }
  386.             } elseif ($this->getOwnertype() == 'fieldcollection') {
  387.                 $ownerName $this->getOwnername();
  388.                 $getter 'get' ucfirst($ownerName);
  389.                 // note that for fieldcollections we need the object data for resolving the
  390.                 // fieldcollection type. alternative: store the fc type as well (similar to class id)
  391.                 $object Concrete::getById($this->getObjectId());
  392.                 if (method_exists($object$getter)) {
  393.                     $fcValue $object->$getter();
  394.                     if ($fcValue instanceof Fieldcollection) {
  395.                         $item $fcValue->get($this->getPosition());
  396.                         $fcType $item->getType();
  397.                         if ($fcDef Fieldcollection\Definition::getByKey($fcType)) {
  398.                             $fd $fcDef->getFieldDefinition($this->getFieldname());
  399.                         }
  400.                     }
  401.                 }
  402.             }
  403.         }
  404.         if (!$fd instanceof \Pimcore\Model\DataObject\ClassDefinition\Data\UrlSlug) {
  405.             // slug could not be resolved which means that the data model has changed in the meantime, delete me.
  406.             $this->delete();
  407.             throw new \Exception('Could not resolve field definition for slug: ' $this->getSlug(). '. Remove it!');
  408.         }
  409.         return $fd->getAction();
  410.     }
  411.     /**
  412.      * @throws \Exception
  413.      */
  414.     public function delete()
  415.     {
  416.         $db Db::get();
  417.         $db->delete(self::TABLE_NAME, ['slug' => $this->getSlug(), 'siteId' => $this->getSiteId()]);
  418.         $cacheKey $this->getSlug() . '~~' $this->getSiteId();
  419.         if (isset(self::$cache[$cacheKey])) {
  420.             unset(self::$cache[$cacheKey]);
  421.         }
  422.     }
  423.     /**
  424.      * @param int $siteId
  425.      *
  426.      * @throws \Exception
  427.      */
  428.     public static function handleSiteDeleted(int $siteId)
  429.     {
  430.         $db Db::get();
  431.         $db->delete(self::TABLE_NAME, ['siteId' => $siteId]);
  432.     }
  433.     /**
  434.      * @param string $classId
  435.      *
  436.      * @throws \Exception
  437.      */
  438.     public static function handleClassDeleted(string $classId)
  439.     {
  440.         $db Db::get();
  441.         $db->delete(self::TABLE_NAME, ['classId' => $classId]);
  442.     }
  443. }