Issues (106)

src/Infrastructure/DbAdapter.php (2 issues)

1
<?php
2
/*
3
 * This file is part of dispositif/wikibot application (@github)
4
 * 2019-2023 © Philippe M./Irønie  <[email protected]>
5
 * For the full copyright and MIT license information, view the license file.
6
 */
7
8
declare(strict_types=1);
9
10
namespace App\Infrastructure;
11
12
use App\Application\InfrastructurePorts\DbAdapterInterface;
13
use App\Domain\Models\PageOuvrageDTO;
14
use DateInterval;
15
use DateTime;
16
use Exception;
17
use Simplon\Mysql\Mysql;
18
use Simplon\Mysql\MysqlException;
19
use Simplon\Mysql\PDOConnector;
20
use Simplon\Mysql\QueryBuilder\UpdateQueryBuilder;
21
use Throwable;
22
23
/**
24
 * TODO WIP refac : return DTO !!!
25
 * Temporary SQL play. https://github.com/fightbulc/simplon_mysql .
26
 * Class DbAdapter.
27
 */
28
class DbAdapter implements DbAdapterInterface
29
{
30
    final public const OPTI_VALID_DATE = '2023-01-01 00:00:00'; // v1.0
31
    protected Mysql $db;
32
    protected $pdoConn;
33
34
    public function __construct()
35
    {
36
        $pdo = new PDOConnector(
37
            getenv('MYSQL_HOST'), getenv('MYSQL_USER'), getenv('MYSQL_PASSWORD'), getenv('MYSQL_DATABASE')
38
        );
39
        $this->pdoConn = $pdo->connect('utf8', ['port' => getenv('MYSQL_PORT')]);
40
        $this->db = new Mysql($this->pdoConn);
41
    }
42
43
    public function getOptiValidDate(): string
44
    {
45
        return self::OPTI_VALID_DATE;
46
    }
47
48
    /**
49
     * @throws Exception
50
     */
51
    public function insertPageOuvrages(array $datas): bool|array
52
    {
53
        // check if article already in db
54
        $page = $datas[0]['page'];
55
        $count = $this->db->fetchRowMany(
56
            'SELECT id from page_ouvrages WHERE page=:page',
57
            ['page' => $page]
58
        );
59
        if (null !== $count) {
60
            return false;
61
        }
62
63
        // add the citations
64
        return $this->db->insertMany('page_ouvrages', $datas);
65
    }
66
67
    /**
68
     * Get one new row (page, raw) to complete.
69
     * Order by isbn (NULL first)
70
     */
71
    public function getNewRaw(): ?PageOuvrageDTO
72
    {
73
        $pageOuvrage = null;
74
        try {
75
            $row = $this->db->fetchRow(
76
                'SELECT id,page,raw FROM page_ouvrages 
77
                WHERE raw <> "" AND (opti IS NULL OR opti = "" OR optidate IS NULL OR optidate < :validDate ) AND (edited IS NULL) AND skip=0
78
                ORDER BY priority DESC,id
79
                LIMIT 1',
80
                [
81
                    'validDate' => self::OPTI_VALID_DATE,
82
                ]
83
            );
84
            $pageOuvrage = (new PageOuvrageDTO())->fromArray($row);
0 ignored issues
show
It seems like $row can also be of type null; however, parameter $data of Simplon\Helper\Data\Data::fromArray() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

84
            $pageOuvrage = (new PageOuvrageDTO())->fromArray(/** @scrutinizer ignore-type */ $row);
Loading history...
85
        } catch (Throwable) {
86
            echo "SQL : No more queue to process \n";
87
        }
88
89
        return ($pageOuvrage instanceof PageOuvrageDTO) ? $pageOuvrage : null;
90
    }
91
92
    /**
93
     * Update DB with completed data from CompleteProcess.
94
     *
95
     * The update by column "id" is limited to one row, for a performance reason.
96
     * Indeed, the "raw" column can not be indexed (MySql), so a modification of all rows with an identical raw
97
     * explodes the query time.
98
     */
99
    public function sendCompletedData(PageOuvrageDTO $pageOuvrage): bool
100
    {
101
        try {
102
            $pageOuvrageStore = new PageOuvrageStore($this->db);
103
            $pageOuvrageStore->update(
104
                (new UpdateQueryBuilder())
105
                    ->setModel($pageOuvrage)
106
                    ->addCondition(PageOuvrageDTO::COLUMN_ID, $pageOuvrage->getId())
107
            );
108
        } catch (MysqlException $e) {
109
            print_r($e);
110
111
            return false;
112
        }
113
114
        return true;
115
    }
116
117
    //------------------------------------------------------
118
    //          EDIT QUEUE
119
    //------------------------------------------------------
120
121
    /**
122
     * TODO DTO !!
123
     * Get batch of citations(template) for edit process.
124
     *
125
     * @param int|null $limit
126
     *
127
     * @return string|null
128
     * @throws Exception
129
     */
130
    public function getAllRowsOfOneTitleToEdit(?int $limit = 100): ?string
131
    {
132
//        // ----------- TEST ----
133
//        // it works
134
//        $store = new PageOuvrageStore($this->db);
135
//        $pageOuvrageModel = $store->read(
136
//            (new ReadQueryBuilder())->addCondition(PageOuvrageDTO::COLUMN_PAGE, 'Autorail Pauline')
137
//        );
138
//        dump($pageOuvrageModel);
139
//        die('stooooop');
140
//
141
//        // ---------- end TEST ----
142
143
        $e = null;
0 ignored issues
show
The assignment to $e is dead and can be removed.
Loading history...
144
        try {
145
            $pageInfo = $this->pdoConn->query(
146
                '
147
                SELECT A.page FROM page_ouvrages A
148
                WHERE A.notcosmetic=1 AND A.opti IS NOT NULL
149
                AND NOT EXISTS
150
                    (SELECT B.* FROM page_ouvrages B
151
                    WHERE (
152
                        B.edited IS NOT NULL 
153
                        OR B.optidate < "'.self::OPTI_VALID_DATE.'" 
154
                        OR B.optidate IS NULL 
155
                        OR B.opti IS NULL
156
                        OR B.opti="" 
157
                        OR B.skip=1
158
                        OR B.raw=""
159
                        )
160
                    AND A.page = B.page
161
                    )
162
                ORDER BY A.priority DESC,A.optidate,RAND()
163
                LIMIT '.$limit.'
164
                '
165
            );
166
167
            // No page to edit
168
            $rows = $pageInfo->fetchAll();
169
            if (empty($rows)) {
170
                return '[]';
171
            }
172
173
            $page = $rows[0]['page']; // get first page to edit ?
174
175
            // todo Replace bellow with PageOuvrageDTO
176
            // Order by optidate for first version in edit commentary ?
177
            $data = $this->db->fetchRowMany(
178
                'SELECT * FROM page_ouvrages WHERE page=:page ORDER BY optidate DESC',
179
                ['page' => $page]
180
            );
181
            $json = json_encode($data, JSON_THROW_ON_ERROR);
182
        } catch (Throwable $e) {
183
            throw new Exception('SQL : No more queue to process', $e->getCode(), $e);
184
        }
185
186
        return $json;
187
    }
188
189
    public function deleteArticle(string $title): bool
190
    {
191
        try {
192
            $result = $this->db->delete(
193
                'page_ouvrages',
194
                ['page' => $title] // condition
195
            );
196
        } catch (MysqlException $e) {
197
            dump($e);
198
199
            return false;
200
        }
201
202
        return !empty($result);
203
    }
204
205
    public function skipArticle(string $title): bool
206
    {
207
        try {
208
            $result = $this->db->update(
209
                'page_ouvrages',
210
                ['page' => $title], // condition
211
                ['skip' => 1]
212
            );
213
        } catch (MysqlException $e) {
214
            dump($e);
215
216
            return false;
217
        }
218
219
        return !empty($result);
220
    }
221
222
    public function setLabel(string $title, ?int $val = 0): bool
223
    {
224
        try {
225
            $result = $this->db->update(
226
                'page_ouvrages',
227
                ['page' => $title], // condition
228
                ['label' => $val]
229
            );
230
        } catch (MysqlException $e) {
231
            dump($e);
232
233
            return false;
234
        }
235
236
        return !empty($result);
237
    }
238
239
    public function skipRow(int $id): bool
240
    {
241
        try {
242
            $result = $this->db->update(
243
                'page_ouvrages',
244
                ['id' => $id], // condition
245
                ['skip' => 1]
246
            );
247
        } catch (MysqlException $e) {
248
            dump($e);
249
250
            return false;
251
        }
252
253
        return !empty($result);
254
    }
255
256
    /**
257
     * Update DB after wiki edition.
258
     *
259
     *
260
     */
261
    public function sendEditedData(array $data): bool
262
    {
263
        try {
264
            $result = $this->db->update(
265
                'page_ouvrages',
266
                ['id' => $data['id']], // condition
267
                ['edited' => date('Y-m-d H:i:s')]
268
            );
269
        } catch (MysqlException $e) {
270
            dump($e);
271
272
            return false;
273
        }
274
275
        return !empty($result);
276
    }
277
278
    /**
279
     * Get a row to monitor edits.
280
     */
281
    public function getMonitor(): ?array
282
    {
283
        $data = null;
284
        // 2 hours ago
285
        $beforeTime = (new DateTime())->sub(new DateInterval('PT3H'));
286
287
        try {
288
            $data = $this->db->fetchRowMany(
289
                'SELECT id,page,raw,opti,optidate,edited,verify,skip FROM page_ouvrages WHERE page = (
290
                    SELECT page FROM page_ouvrages
291
                    WHERE edited IS NOT NULL 
292
                    and edited > :afterDate and edited < :beforeDate
293
                    and (verify is null or verify < :nextVerifyDate )
294
             		ORDER BY verify,edited
295
                    LIMIT 1)',
296
                [
297
                    'afterDate' => '2019-11-26 06:00:00',
298
                    'beforeDate' => $beforeTime->format('Y-m-d H:i:s'),
299
                    'nextVerifyDate' => (new DateTime())->sub(new DateInterval('P2D'))->format('Y-m-d H:i:s'),
300
                ]
301
            );
302
        } catch (Throwable) {
303
            echo "SQL : No more queue to process \n";
304
        }
305
306
        return $data;
307
    }
308
309
    public function updateMonitor(array $data): bool
310
    {
311
        if (empty($data['page'])) {
312
            throw new Exception('pas de page');
313
        }
314
315
        try {
316
            $result = $this->db->update(
317
                'page_ouvrages',
318
                ['page' => $data['page']], // condition
319
                $data
320
            );
321
        } catch (MysqlException $e) {
322
            dump($e);
323
324
            return false;
325
        }
326
327
        return !empty($result);
328
    }
329
}
330