vendor/blackbit/data-director/lib/Pim/FieldType/CalculatedValueDataQuerySelectorPhpCompatibilityTrait.php line 43

Open in your IDE?
  1. <?php
  2. namespace Blackbit\DataDirectorBundle\lib\Pim\FieldType;
  3. use Blackbit\DataDirectorBundle\lib\Pim\Cache\RuntimeCache;
  4. use Blackbit\DataDirectorBundle\lib\Pim\Helper;
  5. use Blackbit\DataDirectorBundle\lib\Pim\Import\CallbackFunction;
  6. use Blackbit\DataDirectorBundle\lib\Pim\Item\Importer;
  7. use Blackbit\DataDirectorBundle\lib\Pim\Item\ImporterInterface;
  8. use Blackbit\DataDirectorBundle\lib\Pim\Item\ItemMoldBuilder;
  9. use Blackbit\DataDirectorBundle\lib\Pim\Item\ParameterBagComposite;
  10. use Blackbit\DataDirectorBundle\lib\Pim\Item\ParameterBagObject;
  11. use Blackbit\DataDirectorBundle\lib\Pim\Logger\InMemoryLogger;
  12. use Blackbit\DataDirectorBundle\model\PimcoreDbRepository;
  13. use Blackbit\DataDirectorBundle\model\RawItemField;
  14. use Pimcore;
  15. use Pimcore\Db;
  16. use Pimcore\Event\Model\ElementEventInterface;
  17. use Pimcore\Localization\LocaleServiceInterface;
  18. use Pimcore\Logger;
  19. use Pimcore\Model\DataObject\ClassDefinition\Data\CalculatedValue;
  20. use Pimcore\Model\DataObject\Objectbrick\Data\AbstractData;
  21. use Pimcore\Model\Element\Service;
  22. use Psr\Log\NullLogger;
  23. trait CalculatedValueDataQuerySelectorPhpCompatibilityTrait
  24. {
  25.     /**
  26.      * @internal
  27.      *
  28.      * @var string|null
  29.      */
  30.     public $dataQuerySelector null;
  31.     /** @var ImporterInterface */
  32.     private static $importer;
  33.     /** @var ItemMoldBuilder */
  34.     private static $itemMoldBuilder;
  35.     private static $fetchFromDatabase true;
  36.     public static function disableDatabaseFetch()
  37.     {
  38.         self::$fetchFromDatabase false;
  39.     }
  40.     public function clearDatabaseCache(ElementEventInterface $e)
  41.     {
  42.         try {
  43.             if ($e->getArgument('saveVersionOnly')) {
  44.                 return;
  45.             }
  46.         } catch (\InvalidArgumentException $exception) {
  47.         }
  48.         $object $e->getElement();
  49.         if($object instanceof Pimcore\Model\DataObject\Concrete) {
  50.             $dependentObjects array_merge(
  51.                 PimcoreDbRepository::getInstance()->findInSql(
  52.                     'SELECT dependencies.targetid AS id, objects.'.Helper::prefixObjectSystemColumn('classId').' as classId
  53.                     FROM dependencies
  54.                     LEFT JOIN objects ON dependencies.targettype="object" AND dependencies.targetid=objects.'.Helper::prefixObjectSystemColumn('id').'
  55.                     WHERE dependencies.sourceid = ? AND dependencies.sourcetype = ?',
  56.                     [$object->getId(), 'object']
  57.                 ),
  58.                 PimcoreDbRepository::getInstance()->findInSql(
  59.                     'SELECT dependencies.sourceid AS id, objects.'.Helper::prefixObjectSystemColumn('classId').' as classId
  60.                     FROM dependencies
  61.                     LEFT JOIN objects ON dependencies.sourcetype="object" AND dependencies.sourceid=objects.'.Helper::prefixObjectSystemColumn('id').'
  62.                     WHERE dependencies.targetid = ? AND dependencies.targettype = ?',
  63.                     [$object->getId(), 'object']
  64.                 )
  65.             );
  66.             $groupedDependentObjects = array();
  67.             foreach ($dependentObjects as $dependentObject) {
  68.                 $groupedDependentObjects[$dependentObject['classId']][] = $dependentObject['id'];
  69.             }
  70.             if($dependentObjects) {
  71.                 foreach ((new Pimcore\Model\DataObject\ClassDefinition\Listing())->load() as $classDefinition) {
  72.                     $fields = [];
  73.                     $localizedFields = [];
  74.                     foreach ($classDefinition->getFieldDefinitions() as $fieldDefinition) {
  75.                         if ($fieldDefinition instanceof CalculatedValueDataQuerySelector) {
  76.                             $fields[] = $fieldDefinition->getName();
  77.                         } elseif ($fieldDefinition instanceof Pimcore\Model\DataObject\ClassDefinition\Data\Localizedfields) {
  78.                             foreach ($fieldDefinition->getFieldDefinitions() as $localizedFieldDefinition) {
  79.                                 if ($localizedFieldDefinition instanceof CalculatedValueDataQuerySelector) {
  80.                                     $localizedFields[] = $localizedFieldDefinition->getName();
  81.                                 }
  82.                             }
  83.                         }
  84.                     }
  85.                     if(count($fields) > 0) {
  86.                         $assignments array_map(static function ($field) {
  87.                             return Db::get()->quoteIdentifier($field).'=NULL';
  88.                         }, $fields);
  89.                         foreach (array_chunk($groupedDependentObjects[$classDefinition->getId()] ?? [], 1000) as $dependentObjectChunk) {
  90.                             try {
  91.                                 PimcoreDbRepository::retry(static function () use ($classDefinition$dependentObjectChunk$assignments) {
  92.                                     PimcoreDbRepository::getInstance()->execute('UPDATE object_query_'.$classDefinition->getId().' SET '.implode(','$assignments).' WHERE oo_id IN (?)', [$dependentObjectChunk]);
  93.                                 });
  94.                             } catch (\Throwable $e) {}
  95.                         }
  96.                     }
  97.                     if(count($localizedFields) > 0) {
  98.                         $assignments array_map(static function ($field) {
  99.                             return Db::get()->quoteIdentifier($field).'=NULL';
  100.                         }, $localizedFields);
  101.                         foreach (Pimcore\Tool::getValidLanguages() as $language) {
  102.                             foreach (array_chunk($groupedDependentObjects[$classDefinition->getId()] ?? [], 1000) as $dependentObjectChunk) {
  103.                                 try {
  104.                                     PimcoreDbRepository::retry(static function () use ($classDefinition$language$dependentObjectChunk$assignments) {
  105.                                         PimcoreDbRepository::getInstance()->execute('UPDATE object_localized_query_'.$classDefinition->getId().'_'.$language.' SET '.implode(','$assignments).' WHERE ooo_id IN (?)', [$dependentObjectChunk]);
  106.                                     });
  107.                                 } catch(\Throwable $e) {}
  108.                             }
  109.                         }
  110.                     }
  111.                 }
  112.             }
  113.         }
  114.     }
  115.     /**
  116.      * @return string|null
  117.      */
  118.     public function getDataQuerySelector(): ?string
  119.     {
  120.         return $this->dataQuerySelector;
  121.     }
  122.     /**
  123.      * @param string|null $dataQuerySelector
  124.      */
  125.     public function setDataQuerySelector(?string $dataQuerySelector): void
  126.     {
  127.         $this->dataQuerySelector $dataQuerySelector;
  128.     }
  129.     /**
  130.      * @param Pimcore\Model\DataObject\Data\CalculatedValue|null $data
  131.      * @param Pimcore\Model\DataObject\Concrete $object
  132.      * @param array $params
  133.      *
  134.      * @return string|null
  135.      * @see Data::getDataForEditmode
  136.      *
  137.      */
  138.     public function doGetDataForEditmode($data$object null$params = [])
  139.     {
  140.         return self::getResult($this->getDataQuerySelector(), $object, ['fieldName' => $this->getName(), 'locale' => $data instanceof Pimcore\Model\DataObject\Data\CalculatedValue $data->getPosition() : null]);
  141.     }
  142.     public function doGetDataForQueryResource($data$object null$params = [])
  143.     {
  144.         if (is_numeric($data)) {
  145.             return str_pad($data10'0'STR_PAD_LEFT);
  146.         }
  147.         return $data;
  148.     }
  149.     public static function getResult($dataQuerySelector$object null$params = [])
  150.     {
  151.         if (!$dataQuerySelector) {
  152.             try {
  153.                 $calculator Pimcore\Model\DataObject\ClassDefinition\Helper\CalculatorClassResolver::resolveCalculatorClass(CalculatedValueCalculator::class);
  154.                 $context = new Pimcore\Model\DataObject\Data\CalculatedValue($params['fieldName']);
  155.                 $context->setContextualData('object'nullnull$params['locale'] ?? null);
  156.                 $ownerType 'object';
  157.                 $ownerName null;
  158.                 $index null;
  159.                 $position null;
  160.                 if ($object instanceof AbstractData) {
  161.                     $ownerType 'objectbrick';
  162.                     $ownerName $object->getFieldname();
  163.                     $index $object->getType();
  164.                 }
  165.                 $context->setContextualData($ownerType$ownerName$index$position);
  166.                 return trim($calculator->compute($object$context));
  167.             } catch (\Throwable $e) {
  168.                 return null;
  169.             }
  170.         }
  171.         if(self::$fetchFromDatabase && $object instanceof Pimcore\Model\DataObject\Concrete && !empty($params['fieldName'])) {
  172.             $dbValue PimcoreDbRepository::getInstance()->findOneInSql(
  173.                 'SELECT '.Db::get()->quoteIdentifier($params['fieldName']).' FROM '.(!empty($params['locale']) ? 'object_localized_'.$object->getClassId().'_'.$params['locale'] : 'object_'.$object->getClassId()).' WHERE oo_id=?',
  174.                 [$object->getId()]
  175.             ) ?: '';
  176.             if ($dbValue) {
  177.                 return $dbValue;
  178.             }
  179.         }
  180.         try {
  181.             if (!empty($params['locale'])) {
  182.                 $originalLanguage \Pimcore::getContainer()->get(LocaleServiceInterface::class)->getLocale();
  183.                 \Pimcore::getContainer()->get(LocaleServiceInterface::class)->setLocale($params['locale']);
  184.             }
  185.             $phpPrefix '<?php';
  186.             if (substr($dataQuerySelector0strlen($phpPrefix)) === $phpPrefix || strpos($dataQuerySelector'return ') !== false) {
  187.                 $dataQuerySelector preg_replace_callback('/\{\{\s*(\S+?( +\S+?)*?)\s*\}\}/', function ($matches) use ($object) {
  188.                     if ($matches[1] === '' && $matches[4] === '') {
  189.                         return $matches[2];
  190.                     }
  191.                     if (substr($matches[1], 06) !== '.:.:.:') {
  192.                         $parts \str_getcsv($matches[1], ':''"');
  193.                         if (count($parts) >= 3) {
  194.                             if (self::getItemMoldBuilder()->getClass($parts[0]) !== null) {
  195.                                 if (strtolower(substr($parts[1], 05)) !== 'getby') {
  196.                                     // if we get here, first data query selector part also exists as data object class -> check if field for $object with same name exists -> field has higher priority
  197.                                     $fieldDefinition Importer::getFieldDefinition($object$parts[0]);
  198.                                     if (!$fieldDefinition->getLocked()) {
  199.                                         $matches[1] = '.:.:.:'.$matches[1];
  200.                                     }
  201.                                 }
  202.                             } else {
  203.                                 $matches[1] = '.:.:.:'.$matches[1];
  204.                             }
  205.                         } else {
  206.                             $matches[1] = '.:.:.:'.$matches[1];
  207.                         }
  208.                     }
  209.                     return var_export(self::getImporter()->getObjectByIdentifier($matches[1], $object), true);
  210.                 }, $dataQuerySelector);
  211.                 $currentObjectValues = function () use ($object$dataQuerySelector) {
  212.                     if (!preg_match('/currentObjectData[\'"]\][);]/'$dataQuerySelector)) {
  213.                         if (preg_match_all('/currentObjectData[\'"]\]\[["\']([A-Za-z0-9]+)["\']\]/'$dataQuerySelector$fieldsToBeSerialized)) {
  214.                             $currentObjectValues = [];
  215.                             foreach ($fieldsToBeSerialized[1] as $fieldToBeSerialized) {
  216.                                 if (isset($currentObjectValues[$fieldToBeSerialized])) {
  217.                                     continue;
  218.                                 }
  219.                                 $fieldSerialization Importer::getSerializer()->serializeField($objectImporter::getFieldDefinition($object$fieldToBeSerialized));
  220.                                 $currentObjectValues[$fieldToBeSerialized] = $fieldSerialization;
  221.                             }
  222.                         } else {
  223.                             $currentObjectValues Importer::getSerializer()->getAttributesArrayForObject($object);
  224.                         }
  225.                     } else {
  226.                         $currentObjectValues Importer::getSerializer()->getAttributesArrayForObject($object);
  227.                     }
  228.                     return $currentObjectValues;
  229.                 };
  230.                 $logger = new InMemoryLogger(function () {
  231.                     return true;
  232.                 });
  233.                 $jsParams = [
  234.                     'currentObjectData' => $currentObjectValues,
  235.                     'request' => Helper::getRequest(),
  236.                     'logger' => $logger
  237.                 ];
  238.                 $returnValue CallbackFunction::evaluateScript($dataQuerySelectorCallbackFunction::ENGINE_PHP$jsParams);
  239.                 $logs $logger->getLogs();
  240.                 if ($logs) {
  241.                     $returnValue .= PHP_EOL.PHP_EOL.implode(PHP_EOL$logs);
  242.                 }
  243.             } else {
  244.                 if (strpos($dataQuerySelector'{{') === false && strpos($dataQuerySelector'{%') === false) {
  245.                     if (strpos($dataQuerySelector'.:.:.:') !== 0) {
  246.                         $parts \str_getcsv($dataQuerySelector':''"');
  247.                         if (self::getItemMoldBuilder()->getClass($parts[0]) !== null) {
  248.                             // if we get here first data query selector part also exists as data object class -> check if field for $object with same name exists -> field has higher priority
  249.                             $fieldDefinition Importer::getFieldDefinition($object$parts[0]);
  250.                             if (!$fieldDefinition->getLocked()) {
  251.                                 $dataQuerySelector '.:.:.:'.$dataQuerySelector;
  252.                             }
  253.                         } else {
  254.                             $dataQuerySelector '.:.:.:'.$dataQuerySelector;
  255.                         }
  256.                     }
  257.                     $returnValue self::getImporter()->getObjectByIdentifier($dataQuerySelector$object);
  258.                     if ($returnValue !== null && !is_scalar($returnValue)) {
  259.                         $returnValue Importer::getLogOutput($returnValue);
  260.                     } elseif (is_bool($returnValue)) {
  261.                         $returnValue = (int)$returnValue;
  262.                     }
  263.                 } else {
  264.                     $returnValue self::getImporter()->replaceObjectIdentifier($dataQuerySelector$object);
  265.                 }
  266.             }
  267.         } catch (\Exception $e) {
  268.             $returnValue = (string)$e;
  269.         } finally {
  270.             if (!empty($params['locale'])) {
  271.                 \Pimcore::getContainer()->get(LocaleServiceInterface::class)->setLocale($originalLanguage);
  272.             }
  273.         }
  274.         if($object instanceof Pimcore\Model\DataObject\Concrete && !empty($params['fieldName'])) {
  275.             try {
  276.                 if (!empty($params['locale'])) {
  277.                     PimcoreDbRepository::getInstance()->execute('SELECT 1 FROM object_localized_query_'.$object->getClassId().'_'.$params['locale'].' WHERE ooo_id=? FOR UPDATE NOWAIT', [$object->getId()]);
  278.                     PimcoreDbRepository::getInstance()->execute('UPDATE object_localized_query_'.$object->getClassId().'_'.$params['locale'].' SET '.Db::get()->quoteIdentifier($params['fieldName']).'=? WHERE ooo_id=?', [$returnValue$object->getId()]);
  279.                 } else {
  280.                     PimcoreDbRepository::getInstance()->execute('SELECT 1 FROM object_query_'.$object->getClassId().' WHERE oo_id=? FOR UPDATE NOWAIT', [$object->getId()]);
  281.                     PimcoreDbRepository::getInstance()->execute('UPDATE object_query_'.$object->getClassId().' SET '.Db::get()->quoteIdentifier($params['fieldName']).'=? WHERE oo_id=?', [$returnValue$object->getId()]);
  282.                 }
  283.             } catch(\Throwable $e) {
  284.             }
  285.         }
  286.         return trim($returnValue);
  287.     }
  288.     /**
  289.      * @return ImporterInterface
  290.      */
  291.     private static function getImporter()
  292.     {
  293.         if (self::$importer === null) {
  294.             /** @var ImporterInterface $importer */
  295.             self::$importer = clone \Pimcore::getContainer()->get(ImporterInterface::class);
  296.             self::$importer->setLogger(new NullLogger());
  297.         }
  298.         return self::$importer;
  299.     }
  300.     /**
  301.      * @return ItemMoldBuilder
  302.      */
  303.     private static function getItemMoldBuilder()
  304.     {
  305.         if (self::$itemMoldBuilder === null) {
  306.             /** @var ImporterInterface $importer */
  307.             self::$itemMoldBuilder \Pimcore::getContainer()->get(ItemMoldBuilder::class);
  308.         }
  309.         return self::$itemMoldBuilder;
  310.     }
  311.     /**
  312.      * {@inheritdoc}
  313.      */
  314.     public function doGetGetterCode($class)
  315.     {
  316.         $key $this->getName();
  317.         $code '/**'."\n";
  318.         $code .= '* Get '.str_replace(['/**''*/''//'], ''$this->getName()).' - '.str_replace(['/**''*/''//'], ''$this->getTitle())."\n";
  319.         $code .= '* @return '.$this->getPhpdocReturnType()."\n";
  320.         $code .= '*/'."\n";
  321.         $code .= 'public function get'.ucfirst($key).'()'."\n";
  322.         $code .= '{'."\n";
  323.         if ($class instanceof Pimcore\Model\DataObject\Objectbrick\Definition) {
  324.             $code .= "\t".'$object = $this->getObject();'."\n";
  325.         } else {
  326.             $code .= "\t".'$object = $this;'."\n";
  327.         }
  328.         $code .= "\t".'$data = \\Blackbit\\DataDirectorBundle\\lib\\Pim\\FieldType\\CalculatedValueDataQuerySelector::getResult(\''.str_replace('\'','\\\''$this->getDataQuerySelector()).'\', $object, [\'fieldName\' => \''.$this->getName().'\']);'."\n\n";
  329.         $code .= "\t".'return $data;'."\n";
  330.         $code .= "}\n\n";
  331.         return $code;
  332.     }
  333.     /**
  334.      * {@inheritdoc}
  335.      */
  336.     public function doGetGetterCodeLocalizedfields($class)
  337.     {
  338.         $key $this->getName();
  339.         $code '/**'."\n";
  340.         $code .= '* Get '.str_replace(['/**''*/''//'], ''$this->getName()).' - '.str_replace(['/**''*/''//'], ''$this->getTitle())."\n";
  341.         $code .= '* @return '.$this->getPhpdocReturnType()."\n";
  342.         $code .= '*/'."\n";
  343.         $code .= 'public function get'.ucfirst($key).'($language = null)'."\n";
  344.         $code .= '{'."\n";
  345.         $code .= "\t".'if (!$language) {'."\n";
  346.         $code .= "\t\t".'try {'."\n";
  347.         $code .= "\t\t\t".'$locale = \Pimcore::getContainer()->get(\''.LocaleServiceInterface::class.'\')->getLocale();'."\n";
  348.         $code .= "\t\t\t".'if (\Pimcore\Tool::isValidLanguage($locale)) {'."\n";
  349.         $code .= "\t\t\t\t".'$language = (string) $locale;'."\n";
  350.         $code .= "\t\t\t".'} else {'."\n";
  351.         $code .= "\t\t\t\t".'throw new \Exception("Not supported language");'."\n";
  352.         $code .= "\t\t\t".'}'."\n";
  353.         $code .= "\t\t".'} catch (\Exception $e) {'."\n";
  354.         $code .= "\t\t\t".'$language = \Pimcore\Tool::getDefaultLanguage();'."\n";
  355.         $code .= "\t\t".'}'."\n";
  356.         $code .= "\t".'}'."\n";
  357.         if ($class instanceof Pimcore\Model\DataObject\Objectbrick\Definition) {
  358.             $code .= "\t".'$object = $this->getObject();'."\n";
  359.         } else {
  360.             $code .= "\t".'$object = $this;'."\n";
  361.         }
  362.         $code .= "\t".'$data'." = new \\Pimcore\\Model\\DataObject\\Data\\CalculatedValue('".$key."');\n";
  363.         $code .= "\t".'$data = \\Blackbit\\DataDirectorBundle\\lib\\Pim\\FieldType\\CalculatedValueDataQuerySelector::getResult(\''.str_replace('\'''\\\''$this->getDataQuerySelector()).'\', $object, [\'fieldName\' => \''.$this->getName().'\', \'locale\' => $language]);'."\n\n";
  364.         $code .= "\treturn ".'$data'.";\n";
  365.         $code .= "}\n\n";
  366.         return $code;
  367.     }
  368.     /**
  369.      * {@inheritdoc}
  370.      */
  371.     public function doGetGetterCodeObjectbrick($brickClass)
  372.     {
  373.         $key $this->getName();
  374.         $code '';
  375.         $code .= '/**'."\n";
  376.         $code .= '* Set '.str_replace(['/**''*/''//'], ''$this->getName()).' - '.str_replace(['/**''*/''//'], ''$this->getTitle())."\n";
  377.         $code .= '* @return '.$this->getPhpdocReturnType()."\n";
  378.         $code .= '*/'."\n";
  379.         $code .= 'public function get'.ucfirst($key).'($language = null)'."\n";
  380.         $code .= '{'."\n";
  381.         $code .= "\t".'$data = \\Blackbit\\DataDirectorBundle\\lib\\Pim\\FieldType\\CalculatedValueDataQuerySelector::getResult(\''.str_replace('\'''\\\''$this->getDataQuerySelector()).'\', $this->getObject(), [\'fieldName\' => \''.$this->getName().'\']);'."\n\n";
  382.         $code .= "\treturn ".'$data'.";\n";
  383.         $code .= "}\n\n";
  384.         return $code;
  385.     }
  386.     /**
  387.      * {@inheritdoc}
  388.      */
  389.     public function doGetGetterCodeFieldcollection($fieldcollectionDefinition)
  390.     {
  391.         $key $this->getName();
  392.         $code '';
  393.         $code .= '/**'."\n";
  394.         $code .= '* Get '.str_replace(['/**''*/''//'], ''$this->getName()).' - '.str_replace(['/**''*/''//'], ''$this->getTitle())."\n";
  395.         $code .= '* @return '.$this->getPhpdocReturnType()."\n";
  396.         $code .= '*/'."\n";
  397.         $code .= 'public function get'.ucfirst($key).'()'."\n";
  398.         $code .= '{'."\n";
  399.         $code .= "\t".'$data = \\Blackbit\\DataDirectorBundle\\lib\\Pim\\FieldType\\CalculatedValueDataQuerySelector::getResult(\''.str_replace('\'''\\\''$this->getDataQuerySelector()).'\', $this->getObject(), [\'fieldName\' => \''.$this->getName().'\']);'."\n\n";
  400.         $code .= "\t".'return $data;'."\n";
  401.         $code .= "}\n\n";
  402.         return $code;
  403.     }
  404.     public function getCalculatorClass(): string
  405.     {
  406.         return CalculatedValueCalculator::class;
  407.     }
  408. }