vendor/pimcore/pimcore/lib/Db/PimcoreExtensionsTrait.php line 92

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\Db;
  15. use Doctrine\DBAL\Cache\CacheException;
  16. use Doctrine\DBAL\Cache\QueryCacheProfile;
  17. use Doctrine\DBAL\Driver\Exception as DriverException;
  18. use Doctrine\DBAL\Driver\Result;
  19. use Doctrine\DBAL\Driver\ResultStatement;
  20. use Doctrine\DBAL\Exception as DBALException;
  21. use Pimcore\Model\Element\ValidationException;
  22. /**
  23.  * @property \Doctrine\DBAL\Driver\Connection $_conn
  24.  *
  25.  * @deprecated will be removed in Pimcore 11
  26.  */
  27. trait PimcoreExtensionsTrait
  28. {
  29.     /**
  30.      * Specifies whether the connection automatically quotes identifiers.
  31.      * If true, the methods insert(), update() apply identifier quoting automatically.
  32.      * If false, developer must quote identifiers themselves by calling quoteIdentifier().
  33.      *
  34.      * @var bool
  35.      */
  36.     protected $autoQuoteIdentifiers true;
  37.     /**
  38.      * @var array
  39.      */
  40.     private static array $tablePrimaryKeyCache = [];
  41.     /**
  42.      * @see \Doctrine\DBAL\Connection::executeQuery
  43.      *
  44.      * @return ResultStatement
  45.      *
  46.      * @throws DBALException
  47.      */
  48.     public function query(...$params)
  49.     {
  50.         trigger_deprecation(
  51.             'pimcore/pimcore',
  52.             '10.5.0',
  53.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Doctrine\DBAL\Connection::executeQuery() instead.'__METHOD__)
  54.         );
  55.         // compatibility layer for additional parameters in the 2nd argument
  56.         // eg. $db->query("UPDATE myTest SET date = ? WHERE uri = ?", [time(), $uri]);
  57.         if (func_num_args() === 2) {
  58.             if (is_array($params[1])) {
  59.                 return parent::executeQuery($params[0], $params[1]);
  60.             }
  61.         }
  62.         if (count($params) > 0) {
  63.             $params[0] = $this->normalizeQuery($params[0], [], true);
  64.         }
  65.         return parent::executeQuery(...$params);
  66.     }
  67.     /**
  68.      * @see \Doctrine\DBAL\Connection::executeQuery
  69.      *
  70.      * @param string $query The SQL query to execute.
  71.      * @param array $params The parameters to bind to the query, if any.
  72.      * @param array $types The types the previous parameters are in.
  73.      * @param QueryCacheProfile|null $qcp The query cache profile, optional.
  74.      *
  75.      * @return ResultStatement The executed statement.
  76.      *
  77.      * @throws DBALException
  78.      */
  79.     public function executeQuery($query, array $params = [], $types = [], QueryCacheProfile $qcp null)
  80.     {
  81.         list($query$params) = $this->normalizeQuery($query$params);
  82.         return parent::executeQuery($query$params$types$qcp);
  83.     }
  84.     /**
  85.      * @deprecated
  86.      * @see \Doctrine\DBAL\Connection::executeUpdate
  87.      *
  88.      * @param string $query The SQL query.
  89.      * @param array $params The query parameters.
  90.      * @param array $types The parameter types.
  91.      *
  92.      * @return int The number of affected rows.
  93.      *
  94.      * @throws DBALException
  95.      */
  96.     public function executeUpdate($query, array $params = [], array $types = [])
  97.     {
  98.         trigger_deprecation(
  99.             'pimcore/pimcore',
  100.             '10.5.0',
  101.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Doctrine\DBAL\Connection::executeStatement() instead.'__METHOD__)
  102.         );
  103.         list($query$params) = $this->normalizeQuery($query$params);
  104.         return parent::executeStatement($query$params$types);
  105.     }
  106.     /**
  107.      * @see \Doctrine\DBAL\Connection::executeCacheQuery
  108.      *
  109.      * @param string $query The SQL query to execute.
  110.      * @param array $params The parameters to bind to the query, if any.
  111.      * @param array $types The types the previous parameters are in.
  112.      * @param QueryCacheProfile $qcp The query cache profile.
  113.      *
  114.      * @return ResultStatement
  115.      *
  116.      * @throws CacheException
  117.      */
  118.     public function executeCacheQuery($query$params$typesQueryCacheProfile $qcp)
  119.     {
  120.         list($query$params) = $this->normalizeQuery($query$params);
  121.         return parent::executeCacheQuery($query$params$types$qcp);
  122.     }
  123.     /**
  124.      * @param string $query
  125.      * @param array $params
  126.      * @param bool $onlyQuery
  127.      *
  128.      * @return array|string
  129.      */
  130.     private function normalizeQuery($query, array $params = [], $onlyQuery false)
  131.     {
  132.         if ($onlyQuery) {
  133.             return $query;
  134.         }
  135.         return [$query$params];
  136.     }
  137.     /**
  138.      * @see \Doctrine\DBAL\Connection::update
  139.      *
  140.      * @param string $tableExpression  The expression of the table to update quoted or unquoted.
  141.      * @param array  $data       An associative array containing column-value pairs.
  142.      * @param array  $identifier The update criteria. An associative array containing column-value pairs.
  143.      * @param array  $types      Types of the merged $data and $identifier arrays in that order.
  144.      *
  145.      * @return int The number of affected rows.
  146.      *
  147.      * @throws DBALException
  148.      */
  149.     public function update($tableExpression, array $data, array $identifier, array $types = [])
  150.     {
  151.         $data $this->quoteDataIdentifiers($data);
  152.         $identifier $this->quoteDataIdentifiers($identifier);
  153.         return parent::update($tableExpression$data$identifier$types);
  154.     }
  155.     /**
  156.      * @see \Doctrine\DBAL\Connection::insert
  157.      *
  158.      * @param string $tableExpression The expression of the table to insert data into, quoted or unquoted.
  159.      * @param array  $data      An associative array containing column-value pairs.
  160.      * @param array  $types     Types of the inserted data.
  161.      *
  162.      * @return int The number of affected rows.
  163.      *
  164.      * @throws DBALException
  165.      */
  166.     public function insert($tableExpression, array $data, array $types = [])
  167.     {
  168.         $data $this->quoteDataIdentifiers($data);
  169.         return parent::insert($tableExpression$data$types);
  170.     }
  171.     /**
  172.      * Deletes table rows based on a custom WHERE clause.
  173.      *
  174.      * @deprecated
  175.      *
  176.      * @param  string        $table The table to update.
  177.      * @param  string        $where DELETE WHERE clause(s).
  178.      *
  179.      * @return int          The number of affected rows.
  180.      *
  181.      * @throws DBALException
  182.      */
  183.     public function deleteWhere($table$where '')
  184.     {
  185.         trigger_deprecation(
  186.             'pimcore/pimcore',
  187.             '10.5.0',
  188.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Doctrine\DBAL\Connection::executeStatement() instead.'__METHOD__)
  189.         );
  190.         $sql 'DELETE FROM ' $table;
  191.         if ($where) {
  192.             $sql .= ' WHERE ' $where;
  193.         }
  194.         return $this->executeStatement($sql);
  195.     }
  196.     /**
  197.      * Updates table rows with specified data based on a custom WHERE clause.
  198.      *
  199.      * @deprecated
  200.      *
  201.      * @param  string        $table The table to update.
  202.      * @param  array        $data  Column-value pairs.
  203.      * @param  string        $where UPDATE WHERE clause(s).
  204.      *
  205.      * @return int          The number of affected rows.
  206.      *
  207.      * @throws DBALException
  208.      */
  209.     public function updateWhere($table, array $data$where '')
  210.     {
  211.         trigger_deprecation(
  212.             'pimcore/pimcore',
  213.             '10.5.0',
  214.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Doctrine\DBAL\Connection::executeStatement() instead.'__METHOD__)
  215.         );
  216.         $set = [];
  217.         $paramValues = [];
  218.         foreach ($data as $columnName => $value) {
  219.             $set[] = $this->quoteIdentifier($columnName) . ' = ?';
  220.             $paramValues[] = $value;
  221.         }
  222.         $sql 'UPDATE ' $table ' SET ' implode(', '$set);
  223.         if ($where) {
  224.             $sql .= ' WHERE ' $where;
  225.         }
  226.         return $this->executeStatement($sql$paramValues);
  227.     }
  228.     /**
  229.      * Fetches the first row of the SQL result.
  230.      *
  231.      * @deprecated
  232.      *
  233.      * @param string $sql
  234.      * @param array|scalar $params
  235.      * @param array $types
  236.      *
  237.      * @return mixed
  238.      *
  239.      * @throws DBALException
  240.      */
  241.     public function fetchRow($sql$params = [], $types = [])
  242.     {
  243.         trigger_deprecation(
  244.             'pimcore/pimcore',
  245.             '10.5.0',
  246.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Doctrine\DBAL\Connection::fetchAssociative() instead.'__METHOD__)
  247.         );
  248.         $params $this->prepareParams($params);
  249.         return $this->fetchAssociative($sql$params$types);
  250.     }
  251.     /**
  252.      * Fetches the first column of all SQL result rows as an array.
  253.      *
  254.      * @deprecated
  255.      *
  256.      * @param string $sql
  257.      * @param array|scalar $params
  258.      * @param array $types
  259.      *
  260.      * @return array
  261.      *
  262.      * @throws DBALException
  263.      * @throws DriverException
  264.      */
  265.     public function fetchCol($sql$params = [], $types = [])
  266.     {
  267.         trigger_deprecation(
  268.             'pimcore/pimcore',
  269.             '10.5.0',
  270.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Doctrine\DBAL\Connection::fetchFirstColumn() instead.'__METHOD__)
  271.         );
  272.         $params $this->prepareParams($params);
  273.         // unfortunately Mysqli driver doesn't support \PDO::FETCH_COLUMN, so we have to do it manually
  274.         $stmt $this->executeQuery($sql$params$types);
  275.         $data = [];
  276.         if ($stmt instanceof Result) {
  277.             $row $stmt->fetchOne();
  278.             while (false !== $row) {
  279.                 $data[] = $row;
  280.                 $row $stmt->fetchOne();
  281.             }
  282.             $stmt->free();
  283.         }
  284.         return $data;
  285.     }
  286.     /**
  287.      * Fetches the first column of the first row of the SQL result.
  288.      *
  289.      * @param string $sql
  290.      * @param array|scalar $params
  291.      * @param array $types
  292.      *
  293.      * @return mixed
  294.      *
  295.      * @throws DBALException
  296.      */
  297.     public function fetchOne($sql$params = [], $types = [])
  298.     {
  299.         $params $this->prepareParams($params);
  300.         // unfortunately Mysqli driver doesn't support \PDO::FETCH_COLUMN, so we have to use $this->fetchColumn() instead
  301.         return parent::fetchOne($sql$params$types);
  302.     }
  303.     /**
  304.      * Fetches all SQL result rows as an array of key-value pairs.
  305.      *
  306.      * The first column is the key, the second column is the
  307.      * value.
  308.      *
  309.      * @deprecated
  310.      *
  311.      * @param string $sql
  312.      * @param array $params
  313.      * @param array $types
  314.      *
  315.      * @return array
  316.      *
  317.      * @throws DBALException
  318.      * @throws DriverException
  319.      */
  320.     public function fetchPairs($sql, array $params = [], $types = [])
  321.     {
  322.         trigger_deprecation(
  323.             'pimcore/pimcore',
  324.             '10.5.0',
  325.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Pimcore\Db\Helper::fetchPairs() instead.'__METHOD__)
  326.         );
  327.         $params $this->prepareParams($params);
  328.         $stmt $this->executeQuery($sql$params$types);
  329.         $data = [];
  330.         if ($stmt instanceof Result) {
  331.             while ($row $stmt->fetchNumeric()) {
  332.                 $data[$row[0]] = $row[1];
  333.             }
  334.         }
  335.         return $data;
  336.     }
  337.     /**
  338.      * @deprecated
  339.      *
  340.      * @param string $table
  341.      * @param array $data
  342.      *
  343.      * @return int
  344.      *
  345.      * @throws DBALException
  346.      */
  347.     public function insertOrUpdate($table, array $data)
  348.     {
  349.         trigger_deprecation(
  350.             'pimcore/pimcore',
  351.             '10.5.0',
  352.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Pimcore\Db\Helper::upsert() instead.'__METHOD__)
  353.         );
  354.         // get the field name of the primary key
  355.         $fieldsPrimaryKey self::$tablePrimaryKeyCache[$table] ??= $this->getPrimaryKeyColumns($table);
  356.         // extract and quote col names from the array keys
  357.         $i 0;
  358.         $bind = [];
  359.         $cols = [];
  360.         $vals = [];
  361.         $set = [];
  362.         foreach ($data as $col => $val) {
  363.             $cols[] = $this->quoteIdentifier($col);
  364.             $bind[':col' $i] = $val;
  365.             $vals[] = ':col' $i;
  366.             if (!($val === null && in_array($col$fieldsPrimaryKey))) {
  367.                 $set[] = sprintf('%s = %s'$this->quoteIdentifier($col), ':col' $i);
  368.             }
  369.             $i++;
  370.         }
  371.         $sql sprintf(
  372.             'INSERT INTO %s (%s) VALUES (%s) ON DUPLICATE KEY UPDATE %s;',
  373.             $this->quoteIdentifier($table),
  374.             implode(', '$cols),
  375.             implode(', '$vals),
  376.             implode(', '$set)
  377.         );
  378.         return $this->executeStatement($sql$bind);
  379.     }
  380.     /**
  381.      * Quotes a value and places into a piece of text at a placeholder.
  382.      *
  383.      * The placeholder is a question-mark; all placeholders will be replaced
  384.      * with the quoted value.   For example:
  385.      *
  386.      * <code>
  387.      * $text = "WHERE date < ?";
  388.      * $date = "2005-01-02";
  389.      * $safe = $sql->quoteInto($text, $date);
  390.      * // $safe = "WHERE date < '2005-01-02'"
  391.      * </code>
  392.      *
  393.      * @deprecated
  394.      *
  395.      * @param string $text The text with a placeholder.
  396.      * @param mixed $value The value to quote.
  397.      * @param string|null $type OPTIONAL SQL datatype
  398.      * @param int|null $count OPTIONAL count of placeholders to replace
  399.      *
  400.      * @return string An SQL-safe quoted value placed into the original text.
  401.      */
  402.     public function quoteInto($text$value$type null$count null)
  403.     {
  404.         trigger_deprecation(
  405.             'pimcore/pimcore',
  406.             '10.5.0',
  407.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Pimcore\Db\Helper::quoteInto() instead.'__METHOD__)
  408.         );
  409.         if ($count === null) {
  410.             return str_replace('?'$this->quote($value$type), $text);
  411.         }
  412.         return implode($this->quote($value$type), explode('?'$text$count 1));
  413.     }
  414.     /**
  415.      * Quote a column identifier and alias.
  416.      *
  417.      * @deprecated
  418.      *
  419.      * @param string|array $ident The identifier or expression.
  420.      * @param string|null $alias An alias for the column.
  421.      *
  422.      * @return string The quoted identifier and alias.
  423.      */
  424.     public function quoteColumnAs($ident$alias null)
  425.     {
  426.         trigger_deprecation(
  427.             'pimcore/pimcore',
  428.             '10.5.0',
  429.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Doctrine\DBAL\Connection::quoteIdentifier() instead.'__METHOD__)
  430.         );
  431.         return $this->_quoteIdentifierAs($ident$alias);
  432.     }
  433.     /**
  434.      * Quote a table identifier and alias.
  435.      *
  436.      * @deprecated
  437.      *
  438.      * @param string|array $ident The identifier or expression.
  439.      * @param string|null $alias An alias for the table.
  440.      *
  441.      * @return string The quoted identifier and alias.
  442.      */
  443.     public function quoteTableAs($ident$alias null)
  444.     {
  445.         trigger_deprecation(
  446.             'pimcore/pimcore',
  447.             '10.5.0',
  448.             sprintf('%s is deprecated and will be removed in Pimcore 11.'__METHOD__)
  449.         );
  450.         return $this->_quoteIdentifierAs($ident$alias);
  451.     }
  452.     /**
  453.      * Quote an identifier and an optional alias.
  454.      *
  455.      * @deprecated
  456.      *
  457.      * @param string|array $ident The identifier or expression.
  458.      * @param string|null $alias An optional alias.
  459.      * @param bool $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
  460.      * @param string $as The string to add between the identifier/expression and the alias.
  461.      *
  462.      * @return string The quoted identifier and alias.
  463.      */
  464.     protected function _quoteIdentifierAs($ident$alias null$auto false$as ' AS ')
  465.     {
  466.         if (is_string($ident)) {
  467.             $ident explode('.'$ident);
  468.         }
  469.         if (is_array($ident)) {
  470.             $segments = [];
  471.             foreach ($ident as $segment) {
  472.                 $segments[] = $this->_quoteIdentifier($segment$auto);
  473.             }
  474.             if ($alias !== null && end($ident) == $alias) {
  475.                 $alias null;
  476.             }
  477.             $quoted implode('.'$segments);
  478.         } else {
  479.             $quoted $this->_quoteIdentifier($ident$auto);
  480.         }
  481.         if ($alias !== null) {
  482.             $quoted .= $as $this->_quoteIdentifier($alias$auto);
  483.         }
  484.         return $quoted;
  485.     }
  486.     /**
  487.      * Quote an identifier.
  488.      *
  489.      * @deprecated
  490.      *
  491.      * @param string $value The identifier or expression.
  492.      * @param bool $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
  493.      *
  494.      * @return string The quoted identifier and alias.
  495.      */
  496.     protected function _quoteIdentifier($value$auto false)
  497.     {
  498.         if ($auto === false) {
  499.             $q '`';
  500.             return $q str_replace((string) $q"$q$q"$value) . $q;
  501.         }
  502.         return $value;
  503.     }
  504.     /**
  505.      * Adds an adapter-specific LIMIT clause to the SELECT statement.
  506.      *
  507.      * @deprecated
  508.      *
  509.      * @param string $sql
  510.      * @param int $count
  511.      * @param int $offset OPTIONAL
  512.      *
  513.      * @throws \Exception
  514.      *
  515.      * @return string
  516.      */
  517.     public function limit($sql$count$offset 0)
  518.     {
  519.         trigger_deprecation(
  520.             'pimcore/pimcore',
  521.             '10.5.0',
  522.             sprintf('%s is deprecated and will be removed in Pimcore 11.'__METHOD__)
  523.         );
  524.         $count = (int) $count;
  525.         if ($count <= 0) {
  526.             throw new \Exception("LIMIT argument count=$count is not valid");
  527.         }
  528.         $offset = (int) $offset;
  529.         if ($offset 0) {
  530.             throw new \Exception("LIMIT argument offset=$offset is not valid");
  531.         }
  532.         $sql .= " LIMIT $count";
  533.         if ($offset 0) {
  534.             $sql .= " OFFSET $offset";
  535.         }
  536.         return $sql;
  537.     }
  538.     /**
  539.      * @deprecated
  540.      *
  541.      * @param string $sql
  542.      * @param array $exclusions
  543.      *
  544.      * @return ResultStatement|null
  545.      *
  546.      * @throws ValidationException
  547.      */
  548.     public function queryIgnoreError($sql$exclusions = [])
  549.     {
  550.         trigger_deprecation(
  551.             'pimcore/pimcore',
  552.             '10.5.0',
  553.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Pimcore\Db\Helper::queryIgnoreError() instead.'__METHOD__)
  554.         );
  555.         try {
  556.             return $this->executeQuery($sql);
  557.         } catch (\Exception $e) {
  558.             foreach ($exclusions as $exclusion) {
  559.                 if ($e instanceof $exclusion) {
  560.                     throw new ValidationException($e->getMessage(), 0$e);
  561.                 }
  562.             }
  563.             // we simply ignore the error
  564.         }
  565.         return null;
  566.     }
  567.     /**
  568.      * @deprecated
  569.      *
  570.      * @param array|scalar $params
  571.      *
  572.      * @return array
  573.      */
  574.     protected function prepareParams($params)
  575.     {
  576.         if (!is_array($params)) {
  577.             trigger_deprecation(
  578.                 'pimcore/pimcore',
  579.                 '10.5.0',
  580.                 'DB query params must be an array in Pimcore 11.'
  581.             );
  582.             $params = [$params];
  583.         }
  584.         return $params;
  585.     }
  586.     /**
  587.      * @deprecated
  588.      *
  589.      * @param array $data
  590.      *
  591.      * @return array
  592.      */
  593.     protected function quoteDataIdentifiers($data)
  594.     {
  595.         if (!$this->autoQuoteIdentifiers) {
  596.             return $data;
  597.         }
  598.         $newData = [];
  599.         foreach ($data as $key => $value) {
  600.             $newData[$this->quoteIdentifier($key)] = $value;
  601.         }
  602.         return $newData;
  603.     }
  604.     /**
  605.      * @deprecated
  606.      *
  607.      * @param bool $autoQuoteIdentifiers
  608.      */
  609.     public function setAutoQuoteIdentifiers($autoQuoteIdentifiers)
  610.     {
  611.         $this->autoQuoteIdentifiers $autoQuoteIdentifiers;
  612.     }
  613.     /**
  614.      * @deprecated
  615.      *
  616.      * @param string $table
  617.      * @param string $idColumn
  618.      * @param string $where
  619.      */
  620.     public function selectAndDeleteWhere($table$idColumn 'id'$where '')
  621.     {
  622.         trigger_deprecation(
  623.             'pimcore/pimcore',
  624.             '10.5.0',
  625.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Pimcore\Db\Helper::selectAndDeleteWhere() instead.'__METHOD__)
  626.         );
  627.         $sql 'SELECT ' $this->quoteIdentifier($idColumn) . '  FROM ' $table;
  628.         if ($where) {
  629.             $sql .= ' WHERE ' $where;
  630.         }
  631.         $idsForDeletion $this->fetchFirstColumn($sql);
  632.         if (!empty($idsForDeletion)) {
  633.             $chunks array_chunk($idsForDeletion1000);
  634.             foreach ($chunks as $chunk) {
  635.                 $idString implode(','array_map([$this'quote'], $chunk));
  636.                 $this->deleteWhere($table$idColumn ' IN (' $idString ')');
  637.             }
  638.         }
  639.     }
  640.     /**
  641.      * @deprecated
  642.      *
  643.      * @param string $like
  644.      *
  645.      * @return string
  646.      */
  647.     public function escapeLike(string $like): string
  648.     {
  649.         trigger_deprecation(
  650.             'pimcore/pimcore',
  651.             '10.5.0',
  652.             sprintf('%s is deprecated and will be removed in Pimcore 11. Use Pimcore\Db\Helper::escapeLike() instead.'__METHOD__)
  653.         );
  654.         return str_replace(['_''%'], ['\\_''\\%'], $like);
  655.     }
  656.     /**
  657.      * @param string $table
  658.      *
  659.      * @return string[]
  660.      */
  661.     private function getPrimaryKeyColumns(string $table): array
  662.     {
  663.         try {
  664.             return $this->getSchemaManager()->listTableDetails($table)->getPrimaryKeyColumns();
  665.         } catch (DBALException) {
  666.             return [];
  667.         }
  668.     }
  669. }