]> git.mxchange.org Git - friendica.git/blob - src/BaseDepository.php
Merge pull request #10813 from tobiasd/20211003-lengthcounter
[friendica.git] / src / BaseDepository.php
1 <?php
2
3 namespace Friendica;
4
5 use Exception;
6 use Friendica\Capabilities\ICanCreateFromTableRow;
7 use Friendica\Database\Database;
8 use Friendica\Database\DBA;
9 use Friendica\Network\HTTPException\NotFoundException;
10 use Psr\Log\LoggerInterface;
11
12 /**
13  * Depositories are meant to store and retrieve Entities from the database.
14  *
15  * The reason why there are methods prefixed with an underscore is because PHP doesn't support generic polymorphism
16  * which means we can't direcly overload base methods and make parameters more strict (from a parent class to a child
17  * class for example)
18  *
19  * Similarly, we can't make an overloaded method return type more strict until we only support PHP version 7.4 but this
20  * is less pressing.
21  */
22 abstract class BaseDepository
23 {
24         const LIMIT = 30;
25
26         /**
27          * @var string This should be set to the main database table name the depository is using
28          */
29         protected static $table_name;
30
31         /** @var Database */
32         protected $db;
33
34         /** @var LoggerInterface */
35         protected $logger;
36
37         /** @var ICanCreateFromTableRow */
38         protected $factory;
39
40         public function __construct(Database $database, LoggerInterface $logger, ICanCreateFromTableRow $factory)
41         {
42                 $this->db      = $database;
43                 $this->logger  = $logger;
44                 $this->factory = $factory;
45         }
46
47         /**
48          * Populates the collection according to the condition. Retrieves a limited subset of entities depending on the
49          * boundaries and the limit. The total count of rows matching the condition is stored in the collection.
50          *
51          * Depends on the corresponding table featuring a numerical auto incremented column called `id`.
52          *
53          * max_id and min_id are susceptible to the query order:
54          * - min_id alone only reliably works with ASC order
55          * - max_id alone only reliably works with DESC order
56          * If the wrong order is detected in either case, we reverse the query order and the entity list order after the query
57          *
58          * Chainable.
59          *
60          * @param array    $condition
61          * @param array    $params
62          * @param int|null $min_id Retrieve models with an id no fewer than this, as close to it as possible
63          * @param int|null $max_id Retrieve models with an id no greater than this, as close to it as possible
64          * @param int      $limit
65          * @return BaseCollection
66          * @throws \Exception
67          */
68         protected function _selectByBoundaries(
69                 array $condition = [],
70                 array $params = [],
71                 int $min_id = null,
72                 int $max_id = null,
73                 int $limit = self::LIMIT
74         ): BaseCollection {
75                 $totalCount = $this->count($condition);
76
77                 $boundCondition = $condition;
78
79                 $reverseOrder = false;
80
81                 if (isset($min_id)) {
82                         $boundCondition = DBA::mergeConditions($boundCondition, ['`id` > ?', $min_id]);
83                         if (!isset($max_id) && isset($params['order']['id']) && ($params['order']['id'] === true || $params['order']['id'] === 'DESC')) {
84                                 $reverseOrder = true;
85
86                                 $params['order']['id'] = 'ASC';
87                         }
88                 }
89
90                 if (isset($max_id)) {
91                         $boundCondition = DBA::mergeConditions($boundCondition, ['`id` < ?', $max_id]);
92                         if (!isset($min_id) && (!isset($params['order']['id']) || $params['order']['id'] === false || $params['order']['id'] === 'ASC')) {
93                                 $reverseOrder = true;
94
95                                 $params['order']['id'] = 'DESC';
96                         }
97                 }
98
99                 $params['limit'] = $limit;
100
101                 $Entities = $this->_select($boundCondition, $params);
102                 if ($reverseOrder) {
103                         $Entities->reverse();
104                 }
105
106                 return new BaseCollection($Entities->getArrayCopy(), $totalCount);
107         }
108
109         /**
110          * @param array $condition
111          * @param array $params
112          * @return BaseCollection
113          * @throws Exception
114          */
115         protected function _select(array $condition, array $params = []): BaseCollection
116         {
117                 $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params);
118
119                 $Entities = new BaseCollection();
120                 foreach ($rows as $fields) {
121                         $Entities[] = $this->factory->createFromTableRow($fields);
122                 }
123
124                 return $Entities;
125         }
126
127         /**
128          * @param array $condition
129          * @param array $params
130          * @return BaseEntity
131          * @throws NotFoundException
132          */
133         protected function _selectOne(array $condition, array $params = []): BaseEntity
134         {
135                 $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params);
136                 if (!$this->db->isResult($fields)) {
137                         throw new NotFoundException();
138                 }
139
140                 return $this->factory->createFromTableRow($fields);
141         }
142
143         /**
144          * @param array $condition
145          * @param array $params
146          * @return int
147          * @throws Exception
148          */
149         public function count(array $condition, array $params = []): int
150         {
151                 return $this->db->count(static::$table_name, $condition, $params);
152         }
153
154         /**
155          * @param array $condition
156          * @return bool
157          * @throws Exception
158          */
159         public function exists(array $condition): bool
160         {
161                 return $this->db->exists(static::$table_name, $condition);
162         }
163 }