• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dragomano / Light-Portal / 27081723386

07 Jun 2026 03:38AM UTC coverage: 60.809%. First build
27081723386

Pull #316

github

web-flow
Merge d8d131f54 into 35fdf9249
Pull Request #316: Update to 3.0

147 of 236 new or added lines in 49 files covered. (62.29%)

6211 of 10214 relevant lines covered (60.81%)

4.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.67
/src/Sources/LightPortal/Repositories/AbstractRepository.php
1
<?php declare(strict_types=1);
2

3
/**
4
 * @package Light Portal
5
 * @link https://dragomano.ru/mods/light-portal
6
 * @author Bugo <bugo@dragomano.ru>
7
 * @copyright 2019-2026 Bugo
8
 * @license https://spdx.org/licenses/GPL-3.0-or-later.html GPL-3.0-or-later
9
 *
10
 * @version 3.0
11
 */
12

13
namespace LightPortal\Repositories;
14

15
use Bugo\Compat\Config;
16
use Bugo\Compat\ErrorHandler;
17
use Bugo\Compat\Parser;
18
use Bugo\Compat\User;
19
use Bugo\Compat\Utils;
20
use Exception;
21
use Laminas\Db\Extra\Sql\TransactionInterface;
22
use Laminas\Db\Sql\Predicate\Expression;
23
use LightPortal\Database\PortalSqlInterface;
24
use LightPortal\Enums\ContentType;
25
use LightPortal\Events\EventDispatcherInterface;
26
use LightPortal\Utils\Language;
27
use LightPortal\Utils\Traits\HasCache;
28
use LightPortal\Utils\Traits\HasParamJoins;
29
use LightPortal\Utils\Traits\HasRequest;
30
use LightPortal\Utils\Traits\HasResponse;
31
use LightPortal\Utils\Traits\HasSession;
32
use LightPortal\Utils\Traits\HasTranslationJoins;
33

34
if (! defined('SMF'))
35
        die('No direct access...');
36

37
abstract class AbstractRepository implements RepositoryInterface
38
{
39
        use HasCache;
40
        use HasParamJoins;
41
        use HasRequest;
42
        use HasResponse;
43
        use HasSession;
44
        use HasTranslationJoins;
45

46
        protected string $entity;
47

48
        protected TransactionInterface $transaction;
49

50
        public function __construct(protected PortalSqlInterface $sql, protected EventDispatcherInterface $dispatcher)
51
        {
52
                $this->transaction = $this->sql->getTransaction();
81✔
53
        }
54

55
        public function toggleStatus(mixed $items = []): void
56
        {
57
                $items = (array) $items;
1✔
58

59
                if ($items === [])
1✔
60
                        return;
×
61

62
                $table = match ($this->entity) {
1✔
63
                        'category' => 'categories',
1✔
64
                        default    => $this->entity . 's',
×
65
                };
1✔
66

67
                $tableName = 'lp_' . $table;
1✔
68

69
                $caseExpression = "CASE status WHEN 1 THEN 0 WHEN 0 THEN 1 WHEN 2 THEN 1 WHEN 3 THEN 0 ELSE status END";
1✔
70

71
                $update = $this->sql->update($tableName);
1✔
72
                $update->set(['status' => new Expression($caseExpression)]);
1✔
73
                $update->where->in($this->entity . '_id', $items);
1✔
74

75
                $this->sql->execute($update);
1✔
76

77
                $this->session('lp')->free('active_' . $table);
1✔
78
        }
79

80
        protected function prepareBbcContent(array &$entity): void
81
        {
NEW
82
                if ($entity['type'] !== ContentType::BBC->value)
×
83
                        return;
×
84

85
                $entity['content'] = Utils::htmlspecialchars($entity['content'], ENT_QUOTES);
×
86
                $entity['content'] = Parser::sanitize($entity['content']);
×
87
        }
88

89
        protected function saveTranslations(array $data, bool $replace = false): void
90
        {
91
                $values = [
3✔
92
                        'item_id'     => $data['id'],
3✔
93
                        'type'        => $this->entity,
3✔
94
                        'lang'        => User::$me->language,
3✔
95
                        'title'       => $data['title'] ?? '',
3✔
96
                        'content'     => $data['content'] ?? '',
3✔
97
                        'description' => Utils::htmlspecialchars($data['description'] ?? ''),
3✔
98
                ];
3✔
99

100
                $sqlObject = $replace
3✔
101
                        ? $this->sql->replace('lp_translations')->setConflictKeys(['item_id', 'type', 'lang'])->values($values)
1✔
102
                        : $this->sql->insert('lp_translations')->values($values);
2✔
103

104
                if (! Language::isDefault()) {
3✔
105
                        $default = $this->getDefaultTranslations($data['id']);
×
106

107
                        foreach (['title', 'content', 'description'] as $field) {
×
108
                                if ($values[$field] === $default[$field]) {
×
109
                                        unset($values[$field]);
×
110
                                }
111
                        }
112
                }
113

114
                $this->sql->execute($sqlObject);
3✔
115
        }
116

117
        protected function saveOptions(array $data, bool $replace = false): void
118
        {
119
                if (empty($data['options']))
1✔
120
                        return;
×
121

122
                $rows = [];
1✔
123
                foreach ($data['options'] as $name => $value) {
1✔
124
                        $value = is_array($value) ? implode(',', $value) : $value;
1✔
125
                        $rows[] = [
1✔
126
                                'item_id' => $data['id'],
1✔
127
                                'type'    => $this->entity,
1✔
128
                                'name'    => $name,
1✔
129
                                'value'   => $value,
1✔
130
                        ];
1✔
131
                }
132

133
                if ($rows === [])
1✔
134
                        return;
×
135

136
                $sqlObject = $replace
1✔
137
                        ? $this->sql->replace('lp_params')->setConflictKeys(['item_id', 'type'])->batch($rows)
×
138
                        : $this->sql->insert('lp_params')->batch($rows);
1✔
139

140
                $this->sql->execute($sqlObject);
1✔
141
        }
142

143
        protected function executeInTransaction(callable $callback): int
144
        {
145
                try {
146
                        $this->transaction->begin();
2✔
147

148
                        $result = $callback();
2✔
149

150
                        $this->transaction->commit();
2✔
151

152
                        return $result ?? 0;
2✔
153
                } catch (Exception $e) {
×
154
                        $this->transaction->rollback();
×
155

156
                        ErrorHandler::fatal($e->getMessage(), false);
×
157

158
                        return 0;
×
159
                }
160
        }
161

162
        protected function deleteRelatedData(array $items): void
163
        {
164
                $deleteTranslations = $this->sql->delete('lp_translations');
2✔
165
                $deleteTranslations->where->in('item_id', $items);
2✔
166
                $deleteTranslations->where->equalTo('type', $this->entity);
2✔
167
                $this->sql->execute($deleteTranslations);
2✔
168

169
                $deleteParams = $this->sql->delete('lp_params');
2✔
170
                $deleteParams->where->in('item_id', $items);
2✔
171
                $deleteParams->where->equalTo('type', $this->entity);
2✔
172
                $this->sql->execute($deleteParams);
2✔
173
        }
174

175
        private function getDefaultTranslations(int $item): array
176
        {
177
                $select = $this->sql->select('lp_translations')
×
178
                        ->columns(['title', 'content', 'description'])
×
179
                        ->where([
×
180
                                'item_id = ?' => $item,
×
181
                                'type = ?'    => $this->entity,
×
182
                                'lang = ?'    => Config::$language,
×
183
                        ]);
×
184

185
                $result = $this->sql->execute($select)->current();
×
186

187
                return $result ?: ['title' => null, 'content' => null, 'description' => null];
×
188
        }
189
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc