vendor/pimcore/pimcore/bundles/EcommerceFrameworkBundle/IndexService/ProductList/DefaultMysql.php line 435

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\Bundle\EcommerceFrameworkBundle\IndexService\ProductList;
  15. use Pimcore\Bundle\EcommerceFrameworkBundle\CoreExtensions\ObjectData\IndexFieldSelection;
  16. use Pimcore\Bundle\EcommerceFrameworkBundle\Factory;
  17. use Pimcore\Bundle\EcommerceFrameworkBundle\IndexService\Config\MysqlConfigInterface;
  18. use Pimcore\Bundle\EcommerceFrameworkBundle\Model\AbstractCategory;
  19. use Pimcore\Bundle\EcommerceFrameworkBundle\Model\IndexableInterface;
  20. use Psr\Log\LoggerInterface;
  21. /**
  22.  * Implementation of product list which works based on the product index of the online shop framework
  23.  */
  24. class DefaultMysql implements ProductListInterface
  25. {
  26.     /**
  27.      * @var null|IndexableInterface[]
  28.      */
  29.     protected $products null;
  30.     /**
  31.      * @var string
  32.      */
  33.     protected $tenantName;
  34.     /**
  35.      * @var MysqlConfigInterface
  36.      */
  37.     protected $tenantConfig;
  38.     /**
  39.      * @var null|int
  40.      */
  41.     protected $totalCount null;
  42.     /**
  43.      * @var string
  44.      */
  45.     protected $variantMode ProductListInterface::VARIANT_MODE_INCLUDE;
  46.     /**
  47.      * @var int|null
  48.      */
  49.     protected $limit;
  50.     /**
  51.      * @var int
  52.      */
  53.     protected $offset;
  54.     /**
  55.      * @var AbstractCategory|null
  56.      */
  57.     protected $category;
  58.     /**
  59.      * @var DefaultMysql\Dao|null
  60.      */
  61.     protected $resource;
  62.     /**
  63.      * @var bool
  64.      */
  65.     protected $inProductList true;
  66.     /**
  67.      * @var LoggerInterface
  68.      */
  69.     protected $logger;
  70.     public function __construct(MysqlConfigInterface $tenantConfig)
  71.     {
  72.         $this->tenantName $tenantConfig->getTenantName();
  73.         $this->tenantConfig $tenantConfig;
  74.         $this->logger \Pimcore::getContainer()->get('monolog.logger.pimcore_ecommerce_sql');
  75.         $this->resource = new DefaultMysql\Dao($this$this->logger);
  76.     }
  77.     /**
  78.      * {@inheritDoc}
  79.      */
  80.     public function getProducts()
  81.     {
  82.         if ($this->products === null) {
  83.             $this->load();
  84.         }
  85.         return $this->products;
  86.     }
  87.     /**
  88.      * @var array
  89.      */
  90.     protected $conditions = [];
  91.     /**
  92.      * @var array<string[]>
  93.      */
  94.     protected $relationConditions = [];
  95.     /**
  96.      * @var string[][]
  97.      */
  98.     protected $queryConditions = [];
  99.     /**
  100.      * @var float|null
  101.      */
  102.     protected $conditionPriceFrom null;
  103.     /**
  104.      * @var float|null
  105.      */
  106.     protected $conditionPriceTo null;
  107.     /**
  108.      * @param array|string $condition
  109.      * @param string $fieldname
  110.      */
  111.     public function addCondition($condition$fieldname '')
  112.     {
  113.         $this->products null;
  114.         $this->conditions[$fieldname][] = $condition;
  115.     }
  116.     public function resetCondition($fieldname)
  117.     {
  118.         $this->products null;
  119.         unset($this->conditions[$fieldname]);
  120.     }
  121.     /**
  122.      * @param string $fieldname
  123.      * @param string|array $condition
  124.      */
  125.     public function addRelationCondition($fieldname$condition)
  126.     {
  127.         $this->products null;
  128.         $this->relationConditions[$fieldname][] = '`fieldname` = ' $this->quote($fieldname) . ' AND '  $condition;
  129.     }
  130.     /**
  131.      * resets all conditions of product list
  132.      */
  133.     public function resetConditions()
  134.     {
  135.         $this->conditions = [];
  136.         $this->relationConditions = [];
  137.         $this->queryConditions = [];
  138.         $this->conditionPriceFrom null;
  139.         $this->conditionPriceTo null;
  140.         $this->products null;
  141.     }
  142.     /**
  143.      * Adds query condition to product list for fulltext search
  144.      * Fieldname is optional but highly recommended - needed for resetting condition based on fieldname
  145.      * and exclude functionality in group by results
  146.      *
  147.      * @param string $condition
  148.      * @param string $fieldname
  149.      */
  150.     public function addQueryCondition($condition$fieldname '')
  151.     {
  152.         $this->products null;
  153.         $this->queryConditions[$fieldname][] = $condition;
  154.     }
  155.     /**
  156.      * Reset query condition for fieldname
  157.      *
  158.      * @param string $fieldname
  159.      */
  160.     public function resetQueryCondition($fieldname)
  161.     {
  162.         $this->products null;
  163.         unset($this->queryConditions[$fieldname]);
  164.     }
  165.     /**
  166.      * @param null|float $from
  167.      * @param null|float $to
  168.      */
  169.     public function addPriceCondition($from null$to null)
  170.     {
  171.         $this->products null;
  172.         $this->conditionPriceFrom $from;
  173.         $this->conditionPriceTo $to;
  174.     }
  175.     /**
  176.      * @param bool $inProductList
  177.      */
  178.     public function setInProductList($inProductList)
  179.     {
  180.         $this->products null;
  181.         $this->inProductList $inProductList;
  182.     }
  183.     /**
  184.      * @return bool
  185.      */
  186.     public function getInProductList()
  187.     {
  188.         return $this->inProductList;
  189.     }
  190.     /**
  191.      * @var string|null
  192.      */
  193.     protected $order;
  194.     /**
  195.      * @var string|array|null
  196.      */
  197.     protected $orderKey;
  198.     /**
  199.      * @var bool
  200.      */
  201.     protected $orderByPrice false;
  202.     public function setOrder($order)
  203.     {
  204.         $this->products null;
  205.         $this->order $order;
  206.     }
  207.     public function getOrder()
  208.     {
  209.         return $this->order;
  210.     }
  211.     /**
  212.      * @param string|array $orderKey either single field name, or array of field names or array of arrays (field name, direction)
  213.      */
  214.     public function setOrderKey($orderKey)
  215.     {
  216.         $this->products null;
  217.         if ($orderKey == ProductListInterface::ORDERKEY_PRICE) {
  218.             $this->orderByPrice true;
  219.         } else {
  220.             $this->orderByPrice false;
  221.         }
  222.         $this->orderKey $orderKey;
  223.     }
  224.     public function getOrderKey()
  225.     {
  226.         return $this->orderKey;
  227.     }
  228.     public function setLimit($limit)
  229.     {
  230.         if ($this->limit != $limit) {
  231.             $this->products null;
  232.         }
  233.         $this->limit $limit;
  234.     }
  235.     public function getLimit()
  236.     {
  237.         return $this->limit;
  238.     }
  239.     public function setOffset($offset)
  240.     {
  241.         if ($this->offset != $offset) {
  242.             $this->products null;
  243.         }
  244.         $this->offset $offset;
  245.     }
  246.     public function getOffset()
  247.     {
  248.         return $this->offset;
  249.     }
  250.     public function setCategory(AbstractCategory $category)
  251.     {
  252.         $this->products null;
  253.         $this->category $category;
  254.     }
  255.     public function getCategory()
  256.     {
  257.         return $this->category;
  258.     }
  259.     public function setVariantMode($variantMode)
  260.     {
  261.         $this->products null;
  262.         $this->variantMode $variantMode;
  263.     }
  264.     public function getVariantMode()
  265.     {
  266.         return $this->variantMode;
  267.     }
  268.     public function load()
  269.     {
  270.         $objectRaws = [];
  271.         //First case: no price filtering and no price sorting
  272.         if (!$this->orderByPrice && $this->conditionPriceFrom === null && $this->conditionPriceTo === null) {
  273.             $objectRaws $this->loadWithoutPriceFilterWithoutPriceSorting();
  274.         }
  275.         //Second case: no price filtering but price sorting
  276.         elseif ($this->orderByPrice && $this->conditionPriceFrom === null && $this->conditionPriceTo === null) {
  277.             $objectRaws $this->loadWithoutPriceFilterWithPriceSorting();
  278.         }
  279.         //Third case: price filtering but no price sorting
  280.         elseif (!$this->orderByPrice && ($this->conditionPriceFrom !== null || $this->conditionPriceTo !== null)) {
  281.             $objectRaws $this->loadWithPriceFilterWithoutPriceSorting();
  282.         }
  283.         //Forth case: price filtering and price sorting
  284.         elseif ($this->orderByPrice && ($this->conditionPriceFrom !== null || $this->conditionPriceTo !== null)) {
  285.             $objectRaws $this->loadWithPriceFilterWithPriceSorting();
  286.         }
  287.         $this->products = [];
  288.         foreach ($objectRaws as $raw) {
  289.             $product $this->loadElementById($raw['o_id']);
  290.             if ($product) {
  291.                 $this->products[] = $product;
  292.             }
  293.         }
  294.         return $this->products;
  295.     }
  296.     /**
  297.      * First case: no price filtering and no price sorting
  298.      *
  299.      * @return array
  300.      */
  301.     protected function loadWithoutPriceFilterWithoutPriceSorting()
  302.     {
  303.         $objectRaws $this->resource->load($this->buildQueryFromConditions(), $this->buildOrderBy(), $this->getLimit(), $this->getOffset());
  304.         $this->totalCount $this->resource->getLastRecordCount();
  305.         return $objectRaws;
  306.     }
  307.     /**
  308.      * Second case: no price filtering but price sorting
  309.      *
  310.      * @return array
  311.      *
  312.      * @throws \Exception
  313.      *
  314.      * @todo Not implemented yet
  315.      */
  316.     protected function loadWithoutPriceFilterWithPriceSorting()
  317.     {
  318.         $objectRaws $this->resource->load($this->buildQueryFromConditions());
  319.         $this->totalCount $this->resource->getLastRecordCount();
  320.         $priceSystemArrays = [];
  321.         foreach ($objectRaws as $raw) {
  322.             $priceSystemArrays[$raw['priceSystemName']][] = $raw['o_id'];
  323.         }
  324.         if (count($priceSystemArrays) == 1) {
  325.             $priceSystemName key($priceSystemArrays);
  326.             $priceSystem Factory::getInstance()->getPriceSystem($priceSystemName);
  327.             $objectRaws $priceSystem->filterProductIds($priceSystemArrays[$priceSystemName], nullnull$this->order$this->getOffset(), $this->getLimit());
  328.         } elseif (count($priceSystemArrays) == 0) {
  329.             //nothing to do
  330.         } else {
  331.             throw new \Exception('Not implemented yet - multiple pricing systems are not supported yet');
  332.         }
  333.         return $objectRaws;
  334.     }
  335.     /**
  336.      * Third case: price filtering but no price sorting
  337.      *
  338.      * @return array
  339.      *
  340.      * @throws \Exception
  341.      *
  342.      * @todo Not implemented yet
  343.      */
  344.     protected function loadWithPriceFilterWithoutPriceSorting()
  345.     {
  346.         //check number of price systems
  347.         //set $this->totalCount
  348.         throw new \Exception('Not implemented yet');
  349.     }
  350.     /**
  351.      * Forth case: price filtering and price sorting
  352.      *
  353.      * @return array
  354.      *
  355.      * @throws \Exception
  356.      *
  357.      * @todo Not implemented yet
  358.      */
  359.     protected function loadWithPriceFilterWithPriceSorting()
  360.     {
  361.         //check number of price systems
  362.         //set $this->totalCount
  363.         throw new \Exception('Not implemented yet');
  364.     }
  365.     /**
  366.      * loads element by id
  367.      *
  368.      * @param int $elementId
  369.      *
  370.      * @return IndexableInterface|null
  371.      */
  372.     protected function loadElementById($elementId)
  373.     {
  374.         return $this->getCurrentTenantConfig()->getObjectMockupById($elementId);
  375.     }
  376.     /**
  377.      * prepares all group by values for given field names and cache them in local variable
  378.      * considers both - normal values and relation values
  379.      *
  380.      * @param string $fieldname
  381.      * @param bool $countValues
  382.      * @param bool $fieldnameShouldBeExcluded
  383.      *
  384.      * @return void
  385.      */
  386.     public function prepareGroupByValues($fieldname$countValues false$fieldnameShouldBeExcluded true)
  387.     {
  388.         // not supported with mysql tables
  389.     }
  390.     /**
  391.      * resets all set prepared group by values
  392.      *
  393.      * @return void
  394.      */
  395.     public function resetPreparedGroupByValues()
  396.     {
  397.         // not supported with mysql tables
  398.     }
  399.     /**
  400.      * prepares all group by values for given field names and cache them in local variable
  401.      * considers both - normal values and relation values
  402.      *
  403.      * @param string $fieldname
  404.      * @param bool $countValues
  405.      * @param bool $fieldnameShouldBeExcluded
  406.      *
  407.      * @return void
  408.      */
  409.     public function prepareGroupByRelationValues($fieldname$countValues false$fieldnameShouldBeExcluded true)
  410.     {
  411.         // not supported with mysql tables
  412.     }
  413.     /**
  414.      * prepares all group by values for given field names and cache them in local variable
  415.      * considers both - normal values and relation values
  416.      *
  417.      * @param string $fieldname
  418.      * @param bool $countValues
  419.      * @param bool $fieldnameShouldBeExcluded
  420.      *
  421.      * @return void
  422.      */
  423.     public function prepareGroupBySystemValues($fieldname$countValues false$fieldnameShouldBeExcluded true)
  424.     {
  425.         // not supported with mysql tables
  426.     }
  427.     /**
  428.      * loads group by values based on relation fieldname either from local variable if prepared or directly from product index
  429.      *
  430.      * @param string $fieldname
  431.      * @param bool $countValues
  432.      * @param bool $fieldnameShouldBeExcluded => set to false for and-conditions
  433.      *
  434.      * @return array
  435.      *
  436.      * @throws \Exception
  437.      */
  438.     public function getGroupBySystemValues($fieldname$countValues false$fieldnameShouldBeExcluded true)
  439.     {
  440.         // not supported with mysql tables
  441.         return [];
  442.     }
  443.     /**
  444.      * @param string $fieldname
  445.      * @param bool $countValues
  446.      * @param bool $fieldnameShouldBeExcluded => set to false for and-conditions
  447.      *
  448.      * @return array
  449.      *
  450.      * @throws \Exception
  451.      */
  452.     public function getGroupByValues($fieldname$countValues false$fieldnameShouldBeExcluded true)
  453.     {
  454.         $excludedFieldName $fieldname;
  455.         if (!$fieldnameShouldBeExcluded) {
  456.             $excludedFieldName null;
  457.         }
  458.         if ($this->conditionPriceFrom === null && $this->conditionPriceTo === null) {
  459.             return $this->resource->loadGroupByValues($fieldname$this->buildQueryFromConditions(false$excludedFieldName$this->getVariantMode()), $countValues);
  460.         } else {
  461.             throw new \Exception('Not supported yet');
  462.         }
  463.     }
  464.     /**
  465.      * @param string $fieldname
  466.      * @param bool $countValues
  467.      * @param bool $fieldnameShouldBeExcluded => set to false for and-conditions
  468.      *
  469.      * @return array
  470.      *
  471.      * @throws \Exception
  472.      */
  473.     public function getGroupByRelationValues($fieldname$countValues false$fieldnameShouldBeExcluded true)
  474.     {
  475.         $excludedFieldName $fieldname;
  476.         if (!$fieldnameShouldBeExcluded) {
  477.             $excludedFieldName null;
  478.         }
  479.         if ($this->conditionPriceFrom === null && $this->conditionPriceTo === null) {
  480.             return $this->resource->loadGroupByRelationValues($fieldname$this->buildQueryFromConditions(false$excludedFieldName), $countValues);
  481.         } else {
  482.             throw new \Exception('Not supported yet');
  483.         }
  484.     }
  485.     /**
  486.      * @param bool $excludeConditions
  487.      * @param string|null $excludedFieldname
  488.      * @param string|null $variantMode
  489.      *
  490.      * @return string
  491.      */
  492.     protected function buildQueryFromConditions($excludeConditions false$excludedFieldname null$variantMode null)
  493.     {
  494.         if ($variantMode == null) {
  495.             $variantMode $this->getVariantMode();
  496.         }
  497.         $preCondition 'active = 1 AND o_virtualProductActive = 1';
  498.         if ($this->inProductList) {
  499.             $preCondition .= ' AND inProductList = 1';
  500.         }
  501.         $tenantCondition $this->getCurrentTenantConfig()->getCondition();
  502.         if ($tenantCondition) {
  503.             $preCondition .= ' AND ' $tenantCondition;
  504.         }
  505.         if ($this->getCategory()) {
  506.             $preCondition .= " AND parentCategoryIds LIKE '%," $this->getCategory()->getId() . ",%'";
  507.         }
  508.         $condition $preCondition;
  509.         //variant handling and userspecific conditions
  510.         switch ($variantMode) {
  511.             case ProductListInterface::VARIANT_MODE_INCLUDE_PARENT_OBJECT:
  512.                 //make sure, that only variant objects are considered
  513.                 $condition .= ' AND a.o_id != o_virtualProductId ';
  514.                 break;
  515.             case ProductListInterface::VARIANT_MODE_HIDE:
  516.                 $condition .= " AND o_type != 'variant'";
  517.                 break;
  518.             case ProductListInterface::VARIANT_MODE_VARIANTS_ONLY:
  519.                 $condition .= " AND o_type = 'variant'";
  520.                 break;
  521.         }
  522.         if (!$excludeConditions) {
  523.             $userspecific $this->buildUserspecificConditions($excludedFieldname);
  524.             if ($userspecific) {
  525.                 $condition .= ' AND ' $userspecific;
  526.             }
  527.         }
  528.         if ($this->queryConditions) {
  529.             $searchstring '';
  530.             foreach ($this->queryConditions as $queryConditionPartArray) {
  531.                 foreach ($queryConditionPartArray as $queryConditionPart) {
  532.                     //check if there are any mysql special characters in query condition - if so, then quote condition
  533.                     if (str_replace(['+''-''<''>''('')''~''*'], ''$queryConditionPart) != $queryConditionPart) {
  534.                         $searchstring .= '+"' $queryConditionPart '" ';
  535.                     } else {
  536.                         $searchstring .= '+' $queryConditionPart '* ';
  537.                     }
  538.                 }
  539.             }
  540.             $condition .= ' AND ' $this->resource->buildFulltextSearchWhere($this->tenantConfig->getSearchAttributes(), $searchstring);
  541.         }
  542.         $this->logger->info('Total Condition: ' $condition);
  543.         return $condition;
  544.     }
  545.     /**
  546.      * @param string|null $excludedFieldname
  547.      *
  548.      * @return string
  549.      */
  550.     protected function buildUserspecificConditions($excludedFieldname null)
  551.     {
  552.         $condition '';
  553.         foreach ($this->relationConditions as $fieldname => $condArray) {
  554.             if ($fieldname !== $excludedFieldname) {
  555.                 foreach ($condArray as $cond) {
  556.                     if ($condition) {
  557.                         $condition .= ' AND ';
  558.                     }
  559.                     $condition .= 'a.o_id IN (SELECT DISTINCT src FROM ' $this->getCurrentTenantConfig()->getRelationTablename() . ' WHERE ' $cond ')';
  560.                 }
  561.             }
  562.         }
  563.         foreach ($this->conditions as $fieldname => $condArray) {
  564.             if ($fieldname !== $excludedFieldname) {
  565.                 foreach ($condArray as $cond) {
  566.                     if ($condition) {
  567.                         $condition .= ' AND ';
  568.                     }
  569.                     $condition .= is_array($cond)
  570.                         ? sprintf(' ( %1$s IN (%2$s) )'$fieldnameimplode(','array_map(function ($value) {
  571.                             return $this->quote($value);
  572.                         }, $cond)))
  573.                         : '(' $cond ')'
  574.                     ;
  575.                 }
  576.             }
  577.         }
  578.         $this->logger->info('User specific Condition Part: ' $condition);
  579.         return $condition;
  580.     }
  581.     protected function buildOrderBy()
  582.     {
  583.         if (!empty($this->orderKey) && $this->orderKey !== ProductListInterface::ORDERKEY_PRICE) {
  584.             $orderKeys $this->orderKey;
  585.             if (!is_array($orderKeys)) {
  586.                 $orderKeys = [$orderKeys];
  587.             }
  588.             // add sorting for primary id to prevent mysql paging problem...
  589.             $orderKeys[] = 'a.o_id';
  590.             $directionOrderKeys = [];
  591.             foreach ($orderKeys as $key) {
  592.                 if (is_array($key)) {
  593.                     $directionOrderKeys[] = $key;
  594.                 } else {
  595.                     $directionOrderKeys[] = [$key$this->order];
  596.                 }
  597.             }
  598.             $orderByStringArray = [];
  599.             foreach ($directionOrderKeys as $keyDirection) {
  600.                 $key $keyDirection[0];
  601.                 if ($key instanceof IndexFieldSelection) {
  602.                     $key $key->getField();
  603.                 }
  604.                 $direction $keyDirection[1];
  605.                 if ($this->getVariantMode() == ProductListInterface::VARIANT_MODE_INCLUDE_PARENT_OBJECT) {
  606.                     if (strtoupper($this->order) == 'DESC') {
  607.                         $orderByStringArray[] = 'max(' $key ') ' $direction;
  608.                     } else {
  609.                         $orderByStringArray[] = 'min(' $key ') ' $direction;
  610.                     }
  611.                 } else {
  612.                     $orderByStringArray[] = $key ' ' $direction;
  613.                 }
  614.             }
  615.             return implode(','$orderByStringArray);
  616.         }
  617.         return null;
  618.     }
  619.     /**
  620.      * @param mixed $value
  621.      *
  622.      * @return mixed
  623.      */
  624.     public function quote($value)
  625.     {
  626.         return $this->resource->quote($value);
  627.     }
  628.     /**
  629.      * @return MysqlConfigInterface
  630.      */
  631.     public function getCurrentTenantConfig()
  632.     {
  633.         return $this->tenantConfig;
  634.     }
  635.     /**
  636.      * returns order by statement for simularity calculations based on given fields and object ids
  637.      * returns cosine simularity calculation
  638.      *
  639.      * @param array $fields
  640.      * @param int $objectId
  641.      *
  642.      * @return string
  643.      */
  644.     public function buildSimularityOrderBy($fields$objectId)
  645.     {
  646.         return $this->resource->buildSimularityOrderBy($fields$objectId);
  647.     }
  648.     /**
  649.      * returns where statement for fulltext search index
  650.      *
  651.      * @param array $fields
  652.      * @param string $searchstring
  653.      *
  654.      * @return string
  655.      */
  656.     public function buildFulltextSearchWhere($fields$searchstring)
  657.     {
  658.         return $this->resource->buildFulltextSearchWhere($fields$searchstring);
  659.     }
  660.     /**
  661.      *  -----------------------------------------------------------------------------------------
  662.      *   Methods for Iterator
  663.      *  -----------------------------------------------------------------------------------------
  664.      */
  665.     /**
  666.      * @return int
  667.      */
  668.     #[\ReturnTypeWillChange]
  669.     public function count()// : int
  670.     {
  671.         if ($this->totalCount === null) {
  672.             $this->totalCount $this->resource->getCount($this->buildQueryFromConditions());
  673.         }
  674.         return $this->totalCount;
  675.     }
  676.     /**
  677.      * @return IndexableInterface|false
  678.      */
  679.     #[\ReturnTypeWillChange]
  680.     public function current()// : IndexableInterface|false
  681.     {
  682.         $this->getProducts();
  683.         return current($this->products);
  684.     }
  685.     /**
  686.      * Returns an collection of items for a page.
  687.      *
  688.      * @param int $offset Page offset
  689.      * @param int $itemCountPerPage Number of items per page
  690.      *
  691.      * @return array
  692.      */
  693.     public function getItems($offset$itemCountPerPage)
  694.     {
  695.         $this->setOffset($offset);
  696.         $this->setLimit($itemCountPerPage);
  697.         return $this->getProducts();
  698.     }
  699.     /**
  700.      * @return int|null
  701.      */
  702.     #[\ReturnTypeWillChange]
  703.     public function key()// : int|null
  704.     {
  705.         $this->getProducts();
  706.         return key($this->products);
  707.     }
  708.     /**
  709.      * @return void
  710.      */
  711.     #[\ReturnTypeWillChange]
  712.     public function next()// : void
  713.     {
  714.         $this->getProducts();
  715.         next($this->products);
  716.     }
  717.     /**
  718.      * @return void
  719.      */
  720.     #[\ReturnTypeWillChange]
  721.     public function rewind()// : void
  722.     {
  723.         $this->getProducts();
  724.         reset($this->products);
  725.     }
  726.     /**
  727.      * @return bool
  728.      */
  729.     #[\ReturnTypeWillChange]
  730.     public function valid()// : bool
  731.     {
  732.         return $this->current() !== false;
  733.     }
  734.     /**
  735.      * @return array
  736.      *
  737.      * @internal
  738.      */
  739.     public function __sleep()
  740.     {
  741.         $vars get_object_vars($this);
  742.         unset($vars['resource']);
  743.         unset($vars['products']);
  744.         return array_keys($vars);
  745.     }
  746.     /**
  747.      * @internal
  748.      */
  749.     public function __wakeup()
  750.     {
  751.         if (empty($this->resource)) {
  752.             $this->logger \Pimcore::getContainer()->get('monolog.logger.pimcore_ecommerce_sql');
  753.             $this->resource = new DefaultMysql\Dao($this$this->logger);
  754.         }
  755.     }
  756.     /**
  757.      * this is needed for ZF1 Paginator
  758.      *
  759.      * @return string
  760.      */
  761.     public function getCacheIdentifier()
  762.     {
  763.         return uniqid();
  764.     }
  765. }