| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 | 
							- <?php
 
- /**
 
-  * Copyright © Magento, Inc. All rights reserved.
 
-  * See COPYING.txt for license details.
 
-  */
 
- namespace Magento\Rule\Model\Condition\Sql;
 
- use Magento\Framework\App\ObjectManager;
 
- use Magento\Framework\DB\Select;
 
- use Magento\Framework\Exception\NoSuchEntityException;
 
- use Magento\Rule\Model\Condition\AbstractCondition;
 
- use Magento\Rule\Model\Condition\Combine;
 
- use Magento\Eav\Api\AttributeRepositoryInterface;
 
- use Magento\Catalog\Model\Product;
 
- use Magento\Eav\Model\Entity\Collection\AbstractCollection;
 
- /**
 
-  * Class SQL Builder
 
-  */
 
- class Builder
 
- {
 
-     /**
 
-      * @var \Magento\Framework\DB\Adapter\AdapterInterface
 
-      */
 
-     protected $_connection;
 
-     /**
 
-      * @var array
 
-      */
 
-     protected $_conditionOperatorMap = [
 
-         '=='    => ':field = ?',
 
-         '!='    => ':field <> ?',
 
-         '>='    => ':field >= ?',
 
-         '>=' => ':field >= ?',
 
-         '>'     => ':field > ?',
 
-         '>'  => ':field > ?',
 
-         '<='    => ':field <= ?',
 
-         '<=' => ':field <= ?',
 
-         '<'     => ':field < ?',
 
-         '<'  => ':field < ?',
 
-         '{}'    => ':field IN (?)',
 
-         '!{}'   => ':field NOT IN (?)',
 
-         '()'    => ':field IN (?)',
 
-         '!()'   => ':field NOT IN (?)',
 
-     ];
 
-     /**
 
-      * @var array
 
-      */
 
-     private $stringConditionOperatorMap = [
 
-         '{}' => ':field LIKE ?',
 
-         '!{}' => ':field NOT LIKE ?',
 
-     ];
 
-     /**
 
-      * @var \Magento\Rule\Model\Condition\Sql\ExpressionFactory
 
-      */
 
-     protected $_expressionFactory;
 
-     /**
 
-      * @var AttributeRepositoryInterface
 
-      */
 
-     private $attributeRepository;
 
-     /**
 
-      * @param ExpressionFactory $expressionFactory
 
-      * @param AttributeRepositoryInterface|null $attributeRepository
 
-      */
 
-     public function __construct(
 
-         ExpressionFactory $expressionFactory,
 
-         AttributeRepositoryInterface $attributeRepository = null
 
-     ) {
 
-         $this->_expressionFactory = $expressionFactory;
 
-         $this->attributeRepository = $attributeRepository ?:
 
-             ObjectManager::getInstance()->get(AttributeRepositoryInterface::class);
 
-     }
 
-     /**
 
-      * Get tables to join for given conditions combination
 
-      *
 
-      * @param Combine $combine
 
-      * @return array
 
-      */
 
-     protected function _getCombineTablesToJoin(Combine $combine)
 
-     {
 
-         $tables = $this->_getChildCombineTablesToJoin($combine);
 
-         return $tables;
 
-     }
 
-     /**
 
-      * Get child for given conditions combination
 
-      *
 
-      * @param Combine $combine
 
-      * @param array $tables
 
-      * @return array
 
-      */
 
-     protected function _getChildCombineTablesToJoin(Combine $combine, $tables = [])
 
-     {
 
-         foreach ($combine->getConditions() as $condition) {
 
-             if ($condition->getConditions()) {
 
-                 $tables = $this->_getChildCombineTablesToJoin($condition);
 
-             } else {
 
-                 /** @var $condition AbstractCondition */
 
-                 foreach ($condition->getTablesToJoin() as $alias => $table) {
 
-                     if (!isset($tables[$alias])) {
 
-                         $tables[$alias] = $table;
 
-                     }
 
-                 }
 
-             }
 
-         }
 
-         return $tables;
 
-     }
 
-     /**
 
-      * Join tables from conditions combination to collection
 
-      *
 
-      * @param AbstractCollection $collection
 
-      * @param Combine $combine
 
-      * @return $this
 
-      */
 
-     protected function _joinTablesToCollection(
 
-         AbstractCollection $collection,
 
-         Combine $combine
 
-     ): Builder {
 
-         foreach ($this->_getCombineTablesToJoin($combine) as $alias => $joinTable) {
 
-             /** @var $condition AbstractCondition */
 
-             $collection->getSelect()->joinLeft(
 
-                 [$alias => $collection->getResource()->getTable($joinTable['name'])],
 
-                 $joinTable['condition'],
 
-                 isset($joinTable['columns']) ? $joinTable['columns'] : '*'
 
-             );
 
-         }
 
-         return $this;
 
-     }
 
-     /**
 
-      * Returns sql expression based on rule condition.
 
-      *
 
-      * @param AbstractCondition $condition
 
-      * @param string $value
 
-      * @param bool $isDefaultStoreUsed no longer used because caused an issue about not existing table alias
 
-      * @return string
 
-      * @throws \Magento\Framework\Exception\LocalizedException
 
-      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 
-      */
 
-     protected function _getMappedSqlCondition(
 
-         AbstractCondition $condition,
 
-         string $value = '',
 
-         bool $isDefaultStoreUsed = true
 
-     ): string {
 
-         $argument = $condition->getMappedSqlField();
 
-         // If rule hasn't valid argument - create negative expression to prevent incorrect rule behavior.
 
-         if (empty($argument)) {
 
-             return $this->_expressionFactory->create(['expression' => '1 = -1']);
 
-         }
 
-         $conditionOperator = $condition->getOperatorForValidate();
 
-         if (!isset($this->_conditionOperatorMap[$conditionOperator])) {
 
-             throw new \Magento\Framework\Exception\LocalizedException(__('Unknown condition operator'));
 
-         }
 
-         $defaultValue = 0;
 
-         //operator 'contains {}' is mapped to 'IN()' query that cannot work with substrings
 
-         // adding mapping to 'LIKE %%'
 
-         if ($condition->getInputType() === 'string'
 
-             && in_array($conditionOperator, array_keys($this->stringConditionOperatorMap), true)
 
-         ) {
 
-             $sql = str_replace(
 
-                 ':field',
 
-                 $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), $defaultValue),
 
-                 $this->stringConditionOperatorMap[$conditionOperator]
 
-             );
 
-             $bindValue = $condition->getBindArgumentValue();
 
-             $expression = $value . $this->_connection->quoteInto($sql, "%$bindValue%");
 
-         } else {
 
-             $sql = str_replace(
 
-                 ':field',
 
-                 $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), $defaultValue),
 
-                 $this->_conditionOperatorMap[$conditionOperator]
 
-             );
 
-             $bindValue = $condition->getBindArgumentValue();
 
-             $expression = $value . $this->_connection->quoteInto($sql, $bindValue);
 
-         }
 
-         // values for multiselect attributes can be saved in comma-separated format
 
-         // below is a solution for matching such conditions with selected values
 
-         if (is_array($bindValue) && \in_array($conditionOperator, ['()', '{}'], true)) {
 
-             foreach ($bindValue as $item) {
 
-                 $expression .= $this->_connection->quoteInto(
 
-                     " OR (FIND_IN_SET (?, {$this->_connection->quoteIdentifier($argument)}) > 0)",
 
-                     $item
 
-                 );
 
-             }
 
-         }
 
-         return $this->_expressionFactory->create(
 
-             ['expression' => $expression]
 
-         );
 
-     }
 
-     /**
 
-      * Get mapped sql combination.
 
-      *
 
-      * @param Combine $combine
 
-      * @param string $value
 
-      * @param bool $isDefaultStoreUsed
 
-      * @return string
 
-      * @SuppressWarnings(PHPMD.NPathComplexity)
 
-      * @throws \Magento\Framework\Exception\LocalizedException
 
-      */
 
-     protected function _getMappedSqlCombination(
 
-         Combine $combine,
 
-         string $value = '',
 
-         bool $isDefaultStoreUsed = true
 
-     ): string {
 
-         $out = (!empty($value) ? $value : '');
 
-         $value = ($combine->getValue() ? '' : ' NOT ');
 
-         $getAggregator = $combine->getAggregator();
 
-         $conditions = $combine->getConditions();
 
-         foreach ($conditions as $key => $condition) {
 
-             /** @var $condition AbstractCondition|Combine */
 
-             $con = ($getAggregator == 'any' ? Select::SQL_OR : Select::SQL_AND);
 
-             $con = (isset($conditions[$key+1]) ? $con : '');
 
-             if ($condition instanceof Combine) {
 
-                 $out .= $this->_getMappedSqlCombination($condition, $value, $isDefaultStoreUsed);
 
-             } else {
 
-                 $out .= $this->_getMappedSqlCondition($condition, $value, $isDefaultStoreUsed);
 
-             }
 
-             $out .=  $out ? (' ' . $con) : '';
 
-         }
 
-         return $this->_expressionFactory->create(['expression' => $out]);
 
-     }
 
-     /**
 
-      * Attach conditions filter to collection
 
-      *
 
-      * @param AbstractCollection $collection
 
-      * @param Combine $combine
 
-      * @return void
 
-      */
 
-     public function attachConditionToCollection(
 
-         AbstractCollection $collection,
 
-         Combine $combine
 
-     ): void {
 
-         $this->_connection = $collection->getResource()->getConnection();
 
-         $this->_joinTablesToCollection($collection, $combine);
 
-         $whereExpression = (string)$this->_getMappedSqlCombination($combine);
 
-         if (!empty($whereExpression)) {
 
-             if (!empty($combine->getConditions())) {
 
-                 $conditions = '';
 
-                 $attributeField = '';
 
-                 foreach ($combine->getConditions() as $condition) {
 
-                     if ($condition->getData('attribute') === \Magento\Catalog\Api\Data\ProductInterface::SKU) {
 
-                         $conditions = $condition->getData('value');
 
-                         $attributeField = $condition->getMappedSqlField();
 
-                     }
 
-                 }
 
-                 $collection->getSelect()->where($whereExpression);
 
-                 if (!empty($conditions) && !empty($attributeField)) {
 
-                     $conditions = explode(',', $conditions);
 
-                     foreach ($conditions as &$condition) {
 
-                         $condition = "'" . trim($condition) . "'";
 
-                     }
 
-                     $conditions = implode(', ', $conditions);
 
-                     $collection->getSelect()->order("FIELD($attributeField, $conditions)");
 
-                 }
 
-             } else {
 
-                 // Select ::where method adds braces even on empty expression
 
-                 $collection->getSelect()->where($whereExpression);
 
-             }
 
-         }
 
-     }
 
- }
 
 
  |