vendor/doctrine/dbal/lib/Doctrine/DBAL/Cache/ResultCacheStatement.php line 161

Open in your IDE?
  1. <?php
  2. namespace Doctrine\DBAL\Cache;
  3. use ArrayIterator;
  4. use Doctrine\Common\Cache\Cache;
  5. use Doctrine\DBAL\Driver\Exception;
  6. use Doctrine\DBAL\Driver\FetchUtils;
  7. use Doctrine\DBAL\Driver\Result;
  8. use Doctrine\DBAL\Driver\ResultStatement;
  9. use Doctrine\DBAL\Driver\Statement;
  10. use Doctrine\DBAL\FetchMode;
  11. use InvalidArgumentException;
  12. use IteratorAggregate;
  13. use PDO;
  14. use ReturnTypeWillChange;
  15. use function array_map;
  16. use function array_merge;
  17. use function array_values;
  18. use function assert;
  19. use function reset;
  20. /**
  21.  * Cache statement for SQL results.
  22.  *
  23.  * A result is saved in multiple cache keys, there is the originally specified
  24.  * cache key which is just pointing to result rows by key. The following things
  25.  * have to be ensured:
  26.  *
  27.  * 1. lifetime of the original key has to be longer than that of all the individual rows keys
  28.  * 2. if any one row key is missing the query has to be re-executed.
  29.  *
  30.  * Also you have to realize that the cache will load the whole result into memory at once to ensure 2.
  31.  * This means that the memory usage for cached results might increase by using this feature.
  32.  *
  33.  * @deprecated
  34.  */
  35. class ResultCacheStatement implements IteratorAggregateResultStatementResult
  36. {
  37.     /** @var Cache */
  38.     private $resultCache;
  39.     /** @var string */
  40.     private $cacheKey;
  41.     /** @var string */
  42.     private $realKey;
  43.     /** @var int */
  44.     private $lifetime;
  45.     /** @var ResultStatement */
  46.     private $statement;
  47.     /** @var array<int,array<string,mixed>>|null */
  48.     private $data;
  49.     /** @var int */
  50.     private $defaultFetchMode FetchMode::MIXED;
  51.     /**
  52.      * @param string $cacheKey
  53.      * @param string $realKey
  54.      * @param int    $lifetime
  55.      */
  56.     public function __construct(ResultStatement $stmtCache $resultCache$cacheKey$realKey$lifetime)
  57.     {
  58.         $this->statement   $stmt;
  59.         $this->resultCache $resultCache;
  60.         $this->cacheKey    $cacheKey;
  61.         $this->realKey     $realKey;
  62.         $this->lifetime    $lifetime;
  63.     }
  64.     /**
  65.      * {@inheritdoc}
  66.      *
  67.      * @deprecated Use free() instead.
  68.      */
  69.     public function closeCursor()
  70.     {
  71.         $this->free();
  72.         return true;
  73.     }
  74.     /**
  75.      * {@inheritdoc}
  76.      */
  77.     public function columnCount()
  78.     {
  79.         return $this->statement->columnCount();
  80.     }
  81.     /**
  82.      * {@inheritdoc}
  83.      *
  84.      * @deprecated Use one of the fetch- or iterate-related methods.
  85.      */
  86.     public function setFetchMode($fetchMode$arg2 null$arg3 null)
  87.     {
  88.         $this->defaultFetchMode $fetchMode;
  89.         return true;
  90.     }
  91.     /**
  92.      * {@inheritdoc}
  93.      *
  94.      * @deprecated Use iterateNumeric(), iterateAssociative() or iterateColumn() instead.
  95.      */
  96.     #[ReturnTypeWillChange]
  97.     public function getIterator()
  98.     {
  99.         $data $this->fetchAll();
  100.         return new ArrayIterator($data);
  101.     }
  102.     /**
  103.      * Be warned that you will need to call this method until no rows are
  104.      * available for caching to happen.
  105.      *
  106.      * {@inheritdoc}
  107.      *
  108.      * @deprecated Use fetchNumeric(), fetchAssociative() or fetchOne() instead.
  109.      */
  110.     public function fetch($fetchMode null$cursorOrientation PDO::FETCH_ORI_NEXT$cursorOffset 0)
  111.     {
  112.         if ($this->data === null) {
  113.             $this->data = [];
  114.         }
  115.         $row $this->statement->fetch(FetchMode::ASSOCIATIVE);
  116.         if ($row) {
  117.             $this->data[] = $row;
  118.             $fetchMode $fetchMode ?: $this->defaultFetchMode;
  119.             if ($fetchMode === FetchMode::ASSOCIATIVE) {
  120.                 return $row;
  121.             }
  122.             if ($fetchMode === FetchMode::NUMERIC) {
  123.                 return array_values($row);
  124.             }
  125.             if ($fetchMode === FetchMode::MIXED) {
  126.                 return array_merge($rowarray_values($row));
  127.             }
  128.             if ($fetchMode === FetchMode::COLUMN) {
  129.                 return reset($row);
  130.             }
  131.             throw new InvalidArgumentException('Invalid fetch-style given for caching result.');
  132.         }
  133.         $this->saveToCache();
  134.         return false;
  135.     }
  136.     /**
  137.      * {@inheritdoc}
  138.      *
  139.      * @deprecated Use fetchAllNumeric(), fetchAllAssociative() or fetchFirstColumn() instead.
  140.      */
  141.     public function fetchAll($fetchMode null$fetchArgument null$ctorArgs null)
  142.     {
  143.         $data $this->statement->fetchAll(FetchMode::ASSOCIATIVE$fetchArgument$ctorArgs);
  144.         $this->data $data;
  145.         $this->saveToCache();
  146.         if ($fetchMode === FetchMode::NUMERIC) {
  147.             foreach ($data as $i => $row) {
  148.                 $data[$i] = array_values($row);
  149.             }
  150.         } elseif ($fetchMode === FetchMode::MIXED) {
  151.             foreach ($data as $i => $row) {
  152.                 $data[$i] = array_merge($rowarray_values($row));
  153.             }
  154.         } elseif ($fetchMode === FetchMode::COLUMN) {
  155.             foreach ($data as $i => $row) {
  156.                 $data[$i] = reset($row);
  157.             }
  158.         }
  159.         return $data;
  160.     }
  161.     /**
  162.      * Be warned that you will need to call this method until no rows are
  163.      * available for caching to happen.
  164.      *
  165.      * {@inheritdoc}
  166.      *
  167.      * @deprecated Use fetchOne() instead.
  168.      */
  169.     public function fetchColumn($columnIndex 0)
  170.     {
  171.         $row $this->fetch(FetchMode::NUMERIC);
  172.         // TODO: verify that return false is the correct behavior
  173.         return $row[$columnIndex] ?? false;
  174.     }
  175.     /**
  176.      * Be warned that you will need to call this method until no rows are
  177.      * available for caching to happen.
  178.      *
  179.      * {@inheritdoc}
  180.      */
  181.     public function fetchNumeric()
  182.     {
  183.         $row $this->doFetch();
  184.         if ($row === false) {
  185.             return false;
  186.         }
  187.         return array_values($row);
  188.     }
  189.     /**
  190.      * Be warned that you will need to call this method until no rows are
  191.      * available for caching to happen.
  192.      *
  193.      * {@inheritdoc}
  194.      */
  195.     public function fetchAssociative()
  196.     {
  197.         return $this->doFetch();
  198.     }
  199.     /**
  200.      * Be warned that you will need to call this method until no rows are
  201.      * available for caching to happen.
  202.      *
  203.      * {@inheritdoc}
  204.      */
  205.     public function fetchOne()
  206.     {
  207.         return FetchUtils::fetchOne($this);
  208.     }
  209.     /**
  210.      * {@inheritdoc}
  211.      */
  212.     public function fetchAllNumeric(): array
  213.     {
  214.         if ($this->statement instanceof Result) {
  215.             $data $this->statement->fetchAllAssociative();
  216.         } else {
  217.             $data $this->statement->fetchAll(FetchMode::ASSOCIATIVE);
  218.         }
  219.         $this->data $data;
  220.         $this->saveToCache();
  221.         return array_map('array_values'$data);
  222.     }
  223.     /**
  224.      * {@inheritdoc}
  225.      */
  226.     public function fetchAllAssociative(): array
  227.     {
  228.         if ($this->statement instanceof Result) {
  229.             $data $this->statement->fetchAllAssociative();
  230.         } else {
  231.             $data $this->statement->fetchAll(FetchMode::ASSOCIATIVE);
  232.         }
  233.         $this->data $data;
  234.         $this->saveToCache();
  235.         return $data;
  236.     }
  237.     /**
  238.      * {@inheritdoc}
  239.      */
  240.     public function fetchFirstColumn(): array
  241.     {
  242.         return FetchUtils::fetchFirstColumn($this);
  243.     }
  244.     /**
  245.      * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement
  246.      * executed by the corresponding object.
  247.      *
  248.      * If the last SQL statement executed by the associated Statement object was a SELECT statement,
  249.      * some databases may return the number of rows returned by that statement. However,
  250.      * this behaviour is not guaranteed for all databases and should not be
  251.      * relied on for portable applications.
  252.      *
  253.      * @return int|string The number of rows.
  254.      */
  255.     public function rowCount()
  256.     {
  257.         assert($this->statement instanceof Statement);
  258.         return $this->statement->rowCount();
  259.     }
  260.     public function free(): void
  261.     {
  262.         $this->data null;
  263.     }
  264.     /**
  265.      * @return array<string,mixed>|false
  266.      *
  267.      * @throws Exception
  268.      */
  269.     private function doFetch()
  270.     {
  271.         if ($this->data === null) {
  272.             $this->data = [];
  273.         }
  274.         if ($this->statement instanceof Result) {
  275.             $row $this->statement->fetchAssociative();
  276.         } else {
  277.             $row $this->statement->fetch(FetchMode::ASSOCIATIVE);
  278.         }
  279.         if ($row !== false) {
  280.             $this->data[] = $row;
  281.             return $row;
  282.         }
  283.         $this->saveToCache();
  284.         return false;
  285.     }
  286.     private function saveToCache(): void
  287.     {
  288.         if ($this->data === null) {
  289.             return;
  290.         }
  291.         $data $this->resultCache->fetch($this->cacheKey);
  292.         if (! $data) {
  293.             $data = [];
  294.         }
  295.         $data[$this->realKey] = $this->data;
  296.         $this->resultCache->save($this->cacheKey$data$this->lifetime);
  297.     }
  298. }