3 * @copyright Copyright (C) 2010-2021, the Friendica project
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
25 use Friendica\Capabilities\ICanCreateFromTableRow;
26 use Friendica\Database\Database;
27 use Friendica\Database\DBA;
28 use Friendica\Network\HTTPException\NotFoundException;
29 use Psr\Log\LoggerInterface;
32 * Repositories are meant to store and retrieve Entities from the database.
34 * The reason why there are methods prefixed with an underscore is because PHP doesn't support generic polymorphism
35 * which means we can't directly overload base methods and make parameters more strict (from a parent class to a child
38 * Similarly, we can't make an overloaded method return type more strict until we only support PHP version 7.4 but this
41 abstract class BaseRepository
46 * @var string This should be set to the main database table name the depository is using
48 protected static $table_name;
53 /** @var LoggerInterface */
56 /** @var ICanCreateFromTableRow */
59 public function __construct(Database $database, LoggerInterface $logger, ICanCreateFromTableRow $factory)
61 $this->db = $database;
62 $this->logger = $logger;
63 $this->factory = $factory;
67 * Populates the collection according to the condition. Retrieves a limited subset of entities depending on the
68 * boundaries and the limit. The total count of rows matching the condition is stored in the collection.
70 * Depends on the corresponding table featuring a numerical auto incremented column called `id`.
72 * max_id and min_id are susceptible to the query order:
73 * - min_id alone only reliably works with ASC order
74 * - max_id alone only reliably works with DESC order
75 * If the wrong order is detected in either case, we reverse the query order and the entity list order after the query
79 * @param array $condition
80 * @param array $params
81 * @param int|null $min_id Retrieve models with an id no fewer than this, as close to it as possible
82 * @param int|null $max_id Retrieve models with an id no greater than this, as close to it as possible
84 * @return BaseCollection
87 protected function _selectByBoundaries(
88 array $condition = [],
92 int $limit = self::LIMIT
94 $totalCount = $this->count($condition);
96 $boundCondition = $condition;
98 $reverseOrder = false;
100 if (isset($min_id)) {
101 $boundCondition = DBA::mergeConditions($boundCondition, ['`id` > ?', $min_id]);
102 if (!isset($max_id) && isset($params['order']['id']) && ($params['order']['id'] === true || $params['order']['id'] === 'DESC')) {
103 $reverseOrder = true;
105 $params['order']['id'] = 'ASC';
109 if (isset($max_id) && $max_id > 0) {
110 $boundCondition = DBA::mergeConditions($boundCondition, ['`id` < ?', $max_id]);
111 if (!isset($min_id) && (!isset($params['order']['id']) || $params['order']['id'] === false || $params['order']['id'] === 'ASC')) {
112 $reverseOrder = true;
114 $params['order']['id'] = 'DESC';
118 $params['limit'] = $limit;
120 $Entities = $this->_select($boundCondition, $params);
122 $Entities->reverse();
125 return new BaseCollection($Entities->getArrayCopy(), $totalCount);
129 * @param array $condition
130 * @param array $params
131 * @return BaseCollection
134 protected function _select(array $condition, array $params = []): BaseCollection
136 $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params);
138 $Entities = new BaseCollection();
139 foreach ($rows as $fields) {
140 $Entities[] = $this->factory->createFromTableRow($fields);
147 * @param array $condition
148 * @param array $params
150 * @throws NotFoundException
152 protected function _selectOne(array $condition, array $params = []): BaseEntity
154 $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params);
155 if (!$this->db->isResult($fields)) {
156 throw new NotFoundException();
159 return $this->factory->createFromTableRow($fields);
163 * @param array $condition
164 * @param array $params
168 public function count(array $condition, array $params = []): int
170 return $this->db->count(static::$table_name, $condition, $params);
174 * @param array $condition
178 public function exists(array $condition): bool
180 return $this->db->exists(static::$table_name, $condition);