Completed
Push — master ( e37ca9...d5b8a7 )
by Dispositif
02:39
created

OuvrageOptimize::processIsbn()   C

Complexity

Conditions 16
Paths 103

Size

Total Lines 72
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 1
Metric Value
cc 16
eloc 39
c 4
b 0
f 1
nc 103
nop 0
dl 0
loc 72
rs 5.5416

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * This file is part of dispositif/wikibot application
4
 * 2019 : Philippe M. <[email protected]>
5
 * For the full copyright and MIT license information, please view the LICENSE file.
6
 */
7
8
declare(strict_types=1);
9
10
namespace App\Domain;
11
12
use App\Domain\Enums\Language;
13
use App\Domain\Models\Wiki\GoogleLivresTemplate;
14
use App\Domain\Models\Wiki\OuvrageTemplate;
15
use App\Domain\Utils\NumberUtil;
16
use App\Domain\Utils\TextUtil;
17
use App\Domain\Utils\WikiTextUtil;
18
use App\Infrastructure\FileManager;
19
use Exception;
20
use Throwable;
21
22
use function mb_strlen;
23
24
/**
25
 * Legacy.
26
 * TODO move methods to OuvrageClean setters
27
 * TODO AbstractProcess
28
 * TODO observer/event (log, MajorEdition)
29
 * Class OuvrageProcess.
30
 */
31
class OuvrageOptimize
32
{
33
    const CONVERT_GOOGLEBOOK_TEMPLATE = false; // change OuvrageOptimizeTest !!
34
35
    const WIKI_LANGUAGE = 'fr';
36
37
    protected $original;
38
39
    private $wikiPageTitle;
40
41
    private $log = [];
42
43
    public $notCosmetic = false;
44
45
    public $major = false;
46
47
    private $ouvrage;
48
49
    private $currentTask;
50
51
    // todo inject TextUtil + ArticleVersion ou WikiRef
52
    public function __construct(OuvrageTemplate $ouvrage, $wikiPageTitle = null)
53
    {
54
        $this->original = $ouvrage;
55
        $this->ouvrage = clone $ouvrage;
56
        $this->wikiPageTitle = ($wikiPageTitle) ?? null;
57
    }
58
59
    public function doTasks(): self
60
    {
61
        $this->cleanAndPredictErrorParameters();
62
63
        $this->processAuthors();
64
65
        $this->processTitle();
66
        $this->processEditeur();
67
        $this->processDates();
68
        $this->externalTemplates();
69
        $this->predictFormatByPattern();
70
71
        $this->convertRoman('tome');
72
        $this->convertRoman('volume');
73
74
        $this->processIsbn();
75
        $this->processBnf();
76
77
        $this->processLang();
78
        $this->processLocation(); // 'lieu'
79
80
        $this->GoogleBookURL('lire en ligne');
81
        $this->GoogleBookURL('présentation en ligne');
82
83
        return $this;
84
    }
85
86
    /**
87
     * Todo: injection dep.
88
     * Todo : "[s. l.]" sans lieu "s.l.n.d." sans lieu ni date.
89
     *
90
     * @throws Exception
91
     */
92
    private function processLocation()
93
    {
94
        $location = $this->getParam('lieu');
95
        if (empty($location)) {
96
            return;
97
        }
98
99
        // typo and unwikify
100
        $memo = $location;
101
        $location = WikiTextUtil::unWikify($location);
102
        $location = TextUtil::mb_ucfirst($location);
103
        if ($memo !== $location) {
104
            $this->setParam('lieu', $location);
105
            $this->log('±lieu');
106
            $this->notCosmetic = true;
107
        }
108
109
        // french translation : "London"->"Londres"
110
        $manager = new FileManager();
111
        $row = $manager->findCSVline(__DIR__.'/resources/traduction_ville.csv', $location);
112
        if (!empty($row) && !empty($row[1])) {
113
            $this->setParam('lieu', $row[1]);
114
            $this->log('lieu francisé');
115
            $this->notCosmetic = true;
116
        }
117
    }
118
119
    private function processBnf()
120
    {
121
        $bnf = $this->getParam('bnf');
122
        if (!$bnf) {
123
            return;
124
        }
125
        $bnf = str_ireplace('FRBNF', '', $bnf);
126
        $this->setParam('bnf', $bnf);
127
    }
128
129
    private function convertRoman(string $param): void
130
    {
131
        $value = $this->getParam($param);
132
        // note : strval() condition because intval('4c') = 4
133
        if ($value && intval($value) > 0 && strval(intval($value)) === $value) {
134
            $number = abs(intval($value));
135
            $roman = NumberUtil::arab2roman($number);
0 ignored issues
show
Bug introduced by
It seems like $number can also be of type double; however, parameter $number of App\Domain\Utils\NumberUtil::arab2roman() does only seem to accept integer, 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

135
            $roman = NumberUtil::arab2roman(/** @scrutinizer ignore-type */ $number);
Loading history...
136
            if ($number > 10) {
137
                $roman = '{{'.$roman.'}}';
138
            }
139
            $this->setParam($param, $roman);
140
            $this->log('romain');
141
            $this->notCosmetic = true;
142
        }
143
    }
144
145
    /**
146
     * @throws Exception
147
     */
148
    private function processAuthors()
149
    {
150
        $this->distinguishAuthors();
151
        //$this->fusionFirstNameAndName(); // desactived : no consensus
152
    }
153
154
    /**
155
     * Detect and correct multiple authors in same parameter.
156
     * Like "auteurs=J. M. Waller, M. Bigger, R. J. Hillocks".
157
     *
158
     * @throws Exception
159
     */
160
    private function distinguishAuthors()
161
    {
162
        // merge params of author 1
163
        $auteur1 = $this->getParam('auteur') ?? '';
164
        $auteur1 .= $this->getParam('auteurs') ?? '';
165
        $auteur1 .= $this->getParam('prénom1') ?? '';
166
        $auteur1 .= ' '.$this->getParam('nom1') ?? '';
167
        $auteur1 = trim($auteur1);
168
        // of authors 2
169
        $auteur2 = $this->getParam('auteur2') ?? '';
170
        $auteur2 .= $this->getParam('prénom2') ?? '';
171
        $auteur2 .= ' '.$this->getParam('nom2') ?? '';
172
        $auteur2 = trim($auteur2);
173
174
        // skip if wikilink in author
175
        if (empty($auteur1) || WikiTextUtil::isWikify($auteur1)) {
176
            return;
177
        }
178
179
        $machine = new PredictAuthors();
180
        $res = $machine->predictAuthorNames($auteur1);
181
182
        if (1 === count($res)) {
183
            // auteurs->auteur?
184
            return;
185
        }
186
        // Many authors... and empty "auteur2"
187
        if (count($res) >= 2 && empty($auteur2)) {
188
            // delete author-params
189
            array_map(
190
                function ($param) {
191
                    $this->unsetParam($param);
192
                },
193
                ['auteur', 'auteurs', 'prénom1', 'nom1']
194
            );
195
            // iterate and edit new values
196
            for ($i = 0; $i < count($res); ++$i) {
1 ignored issue
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
197
                $this->setParam(sprintf('auteur%s', $i + 1), $res[$i]);
198
            }
199
            $this->log('distinction auteurs');
200
            $this->major = true;
201
            $this->notCosmetic = true;
202
        }
203
    }
204
205
    /**
206
     * todo: move/implement.
207
     *
208
     * @throws Exception
209
     */
210
    private function processLang()
211
    {
212
        $lang = $this->getParam('langue') ?? null;
213
214
        if ($lang) {
215
            $lang2 = Language::all2wiki($lang);
216
217
            if ($lang2 && $lang !== $lang2) {
218
                $this->setParam('langue', $lang2);
219
                if (self::WIKI_LANGUAGE !== $lang2) {
220
                    $this->log('±langue');
221
                }
222
            }
223
        }
224
    }
225
226
    /**
227
     * Validate or correct ISBN.
228
     *
229
     * @throws Exception
230
     */
231
    private function processIsbn()
232
    {
233
        $isbn = $this->getParam('isbn') ?? '';
234
235
        if (empty($isbn)) {
236
            return;
237
        }
238
239
        $isbnMachine = new IsbnFacade($isbn);
240
241
        try {
242
            $isbnMachine->validate();
243
            $isbn13 = $isbnMachine->format('ISBN-13');
244
        } catch (Throwable $e) {
245
            // ISBN not validated
246
            // TODO : bot ISBN invalide (queue, message PD...)
247
            $this->setParam(
248
                'isbn invalide',
249
                sprintf('%s %s', $isbn, $e->getMessage() ?? '')
250
            );
251
            $this->log(sprintf('ISBN invalide: %s', $e->getMessage()));
252
            $this->notCosmetic = true;
253
254
            // TODO log file ISBNinvalide
255
            return;
256
        }
257
258
        // Si 'isbn2' correspond à ISBN-13 => suppression
259
        if (isset($isbn13)
260
            && $this->getParam('isbn2')
261
            && $this->stripIsbn($this->getParam('isbn2')) === $this->stripIsbn($isbn13)
0 ignored issues
show
Bug introduced by
It seems like $this->getParam('isbn2') can also be of type null; however, parameter $isbn of App\Domain\OuvrageOptimize::stripIsbn() does only seem to accept string, 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

261
            && $this->stripIsbn(/** @scrutinizer ignore-type */ $this->getParam('isbn2')) === $this->stripIsbn($isbn13)
Loading history...
262
        ) {
263
            $this->unsetParam('isbn2');
264
        }
265
266
267
        // ISBN-10 ?
268
        $stripIsbn = $this->stripIsbn($isbn);
269
        if (10 === mb_strlen($stripIsbn)) {
270
            // ajout des tirets
271
            $isbn10pretty = $isbn;
1 ignored issue
show
Unused Code introduced by
The assignment to $isbn10pretty is dead and can be removed.
Loading history...
272
            try {
273
                $isbn10pretty = $isbnMachine->format('ISBN-10');
274
                if ($isbn10pretty !== $isbn) {
275
                    $this->notCosmetic = true;
276
                }
277
            } catch (\Throwable $e) {
278
                unset($e);
279
            }
280
281
            // archivage ISBN-10 dans 'isbn2'
282
            if (!$this->getParam('isbn2')) {
283
                $this->setParam('isbn2', $isbn10pretty);
284
            }
285
            // sinon dans 'isbn3'
286
            if (!empty($this->getParam('isbn2'))
287
                && $this->stripIsbn($this->getParam('isbn2')) !== $stripIsbn
288
                && empty($this->getParam('isbn3'))
289
            ) {
290
                $this->setParam('isbn3', $isbn10pretty);
291
            }
292
            // delete 'isbn10' (en attendant modification modèle)
293
            if (!empty($this->getParam('isbn10')) && $this->stripIsbn($this->getParam('isbn10')) === $stripIsbn) {
294
                $this->unsetParam('isbn10');
295
            }
296
        }
297
298
        // ISBN correction
299
        if ($isbn13 !== $isbn) {
300
            $this->setParam('isbn', $isbn13);
301
            $this->log('ISBN');
302
            $this->notCosmetic = true;
303
        }
304
    }
305
306
    private function stripIsbn(string $isbn): string
307
    {
308
        return trim(preg_replace('#[^0-9Xx]#', '', $isbn));
309
    }
310
311
    private function processTitle()
312
    {
313
        $this->currentTask = 'titres';
314
315
        $oldtitre = $this->getParam('titre');
316
        $this->langInTitle();
317
        $this->deWikifyExternalLink('titre');
318
        $this->upperCaseFirstLetter('titre');
319
        $this->typoDeuxPoints('titre');
320
321
        $this->extractSubTitle();
322
323
        // 20-11-2019 : Retiré majuscule à sous-titre
324
325
        if ($this->getParam('titre') !== $oldtitre) {
326
            $this->log('±titre');
327
        }
328
329
        $this->currentTask = 'titre chapitre';
330
        $this->valideNumeroChapitre();
331
        $this->deWikifyExternalLink('titre chapitre');
332
        $this->upperCaseFirstLetter('titre chapitre');
333
        $this->typoDeuxPoints('titre chapitre');
334
    }
335
336
    private function detectColon($param): bool
337
    {
338
        // > 0 don't count a starting colon ":bla"
339
        if (!empty($this->getParam($param)) && mb_strrpos($this->getParam('titre'), ':') > 0) {
340
            return true;
341
        }
342
343
        return false;
344
    }
345
346
    private function extractSubTitle(): void
347
    {
348
        // FIXED bug [[fu:bar]]
349
        if (!$this->getParam('titre') || WikiTextUtil::isWikify($this->getParam('titre'))) {
1 ignored issue
show
Bug introduced by
It seems like $this->getParam('titre') can also be of type null; however, parameter $text of App\Domain\Utils\WikiTextUtil::isWikify() does only seem to accept string, 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

349
        if (!$this->getParam('titre') || WikiTextUtil::isWikify(/** @scrutinizer ignore-type */ $this->getParam('titre'))) {
Loading history...
350
            return;
351
        }
352
353
        if (!$this->detectColon('titre')) {
354
            return;
355
        }
356
        // Que faire si déjà un sous-titre ?
357
        if (!empty($this->getParam('sous-titre'))) {
358
            return;
359
        }
360
361
        // titre>5 and sous-titre>5 and sous-titre<40
362
        if (preg_match('#^(?<titre>[^:]{5,}):(?<st>.{5,40})$#', $this->getParam('titre'), $matches) > 0) {
363
            $this->setParam('titre', trim($matches['titre']));
364
            $this->setParam('sous-titre', trim($matches['st']));
365
            $this->log('>sous-titre');
366
        }
367
    }
368
369
    /**
370
     * Normalize a Google Book links.
371
     * Clean the useless URL parameters or transform into wiki-template.
372
     *
373
     * @param $param
374
     *
375
     * @throws Exception
376
     */
377
    private function googleBookUrl(string $param): void
378
    {
379
        $url = $this->getParam($param);
380
        if (empty($url)
381
            || !GoogleLivresTemplate::isGoogleBookURL($url)
382
        ) {
383
            return;
384
        }
385
386
        if (self::CONVERT_GOOGLEBOOK_TEMPLATE) {
387
            $template = GoogleLivresTemplate::createFromURL($url);
388
            if ($template) {
1 ignored issue
show
introduced by
$template is of type App\Domain\Models\Wiki\GoogleLivresTemplate, thus it always evaluated to true.
Loading history...
389
                $this->setParam($param, $template->serialize());
390
                $this->log('{Google}');
391
                $this->notCosmetic = true;
392
393
                return;
394
            }
395
        }
396
397
        $goo = GoogleLivresTemplate::simplifyGoogleUrl($url);
398
        if (!empty($goo)) {
399
            $this->setParam($param, $goo);
400
            $this->log('Google');
401
            $this->notCosmetic = true;
402
        }
403
    }
404
405
    /**
406
     * - {{lang|...}} dans titre => langue=... puis titre nettoyé
407
     *  langue=L’utilisation de ce paramètre permet aussi aux synthétiseurs vocaux de reconnaître la langue du titre de
408
     * l’ouvrage.
409
     * Il est possible d'afficher plusieurs langues, en saisissant le nom séparé par des espaces ou des virgules. La première langue doit être celle du titre.
410
     *
411
     * @throws Exception
412
     */
413
    private function langInTitle()
414
    {
415
        if (preg_match(
416
                '#^{{ ?(?:lang|langue) ?\| ?([a-z-]{2,5}) ?\| ?(?:texte=)?([^{}=]+)(?:\|dir=rtl)?}}$#i',
417
                $this->getParam('titre'),
418
                $matches
419
            ) > 0
420
        ) {
421
            $lang = trim($matches[1]);
422
            $newtitre = str_replace($matches[0], trim($matches[2]), $this->getParam('titre'));
423
            $this->setParam('titre', $newtitre);
424
            $this->log('°titre');
425
            if (self::WIKI_LANGUAGE !== $lang && empty($this->getParam('langue'))) {
426
                $this->setParam('langue', $lang);
427
                $this->log('+langue='.$lang);
428
            }
429
        }
430
    }
431
432
    private function processDates()
433
    {
434
        // dewikification
435
        $params = ['date', 'année', 'mois', 'jour'];
436
        foreach ($params as $param) {
437
            if (WikiTextUtil::isWikify(' '.$this->getParam($param))) {
438
                $this->setParam($param, WikiTextUtil::unWikify($this->getParam($param)));
1 ignored issue
show
Bug introduced by
It seems like $this->getParam($param) can also be of type null; however, parameter $text of App\Domain\Utils\WikiTextUtil::unWikify() does only seem to accept string, 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

438
                $this->setParam($param, WikiTextUtil::unWikify(/** @scrutinizer ignore-type */ $this->getParam($param)));
Loading history...
439
            }
440
        }
441
442
        try {
443
            $this->moveDate2Year();
444
        } catch (Exception $e) {
445
            dump($e);
446
        }
447
    }
448
449
    /**
450
     * todo: move to AbstractWikiTemplate ?
451
     * Correction des parametres rejetés à l'hydratation données.
452
     *
453
     * @throws Exception
454
     */
455
    private function cleanAndPredictErrorParameters()
456
    {
457
        if (empty($this->ouvrage->parametersErrorFromHydrate)) {
458
            return;
459
        }
460
        $allParamsAndAlias = $this->ouvrage->getParamsAndAlias();
461
462
        foreach ($this->ouvrage->parametersErrorFromHydrate as $name => $value) {
463
            if (!is_string($name)) {
464
                // example : 1 => "ouvrage collectif" from |ouvrage collectif|
465
                continue;
466
            }
467
468
            // delete error parameter if no value
469
            if (empty($value)) {
470
                unset($this->ouvrage->parametersErrorFromHydrate[$name]);
471
472
                continue;
473
            }
474
475
            $maxDistance = 1;
476
            if (mb_strlen($name) >= 4) {
477
                $maxDistance = 2;
478
            }
479
            if (mb_strlen($name) >= 8) {
480
                $maxDistance = 3;
481
            }
482
483
            $predName = TextUtil::predictCorrectParam($name, $allParamsAndAlias, $maxDistance);
484
            if ($predName && mb_strlen($name) >= 5) {
485
                if (empty($this->getParam($predName))) {
486
                    $predName = $this->ouvrage->getAliasParam($predName);
487
                    $this->setParam($predName, $value);
488
                    $this->log(sprintf('%s⇒%s ?', $name, $predName));
489
                    $this->notCosmetic = true;
490
                    unset($this->ouvrage->parametersErrorFromHydrate[$name]);
491
                }
492
            }
493
        }
494
    }
495
496
    /**
497
     * TODO : return "" instead of null ?
498
     *
499
     * @param $name
500
     *
501
     * @return string|null
502
     * @throws Exception
503
     */
504
    private function getParam(string $name): ?string
505
    {
506
        return $this->ouvrage->getParam($name);
507
    }
508
509
    private function setParam($name, $value)
510
    {
511
        // todo : overwrite setParam() ?
512
        if (!empty($value) || $this->ouvrage->getParam($name)) {
513
            $this->ouvrage->setParam($name, $value);
514
        }
515
    }
516
517
    private function log(string $string): void
518
    {
519
        if (!empty($string)) {
520
            $this->log[] = trim($string);
521
        }
522
    }
523
524
    /**
525
     * Bool ?
526
     * déwikification du titre : consensus Bistro 27 août 2011
527
     * idem  'titre chapitre'.
528
     *
529
     * @param string $param
530
     *
531
     * @throws Exception
532
     */
533
    private function deWikifyExternalLink(string $param): void
534
    {
535
        if (empty($this->getParam($param))) {
536
            return;
537
        }
538
        if (preg_match('#^\[(http[^ \]]+) ([^]]+)]#i', $this->getParam($param), $matches) > 0) {
539
            $this->setParam($param, str_replace($matches[0], $matches[2], $this->getParam($param)));
540
            $this->log('±'.$param);
541
542
            if (in_array($param, ['titre', 'titre chapitre'])) {
543
                if (empty($this->getParam('lire en ligne'))) {
544
                    $this->setParam('lire en ligne', $matches[1]);
545
                    $this->log('+lire en ligne');
546
547
                    return;
548
                }
549
                $this->log('autre lien externe: '.$matches[1]);
550
            }
551
        }
552
    }
553
554
    private function upperCaseFirstLetter($param)
555
    {
556
        if (empty($this->getParam($param))) {
557
            return;
558
        }
559
        $newValue = TextUtil::mb_ucfirst(trim($this->getParam($param)));
560
        $this->setParam($param, $newValue);
561
    }
562
563
    /**
564
     * Typo internationale 'titre : sous-titre'.
565
     * Fix fantasy typo of subtitle with '. ' or ' - '.
566
     * International Standard Bibliographic Description :
567
     * https://fr.wikipedia.org/wiki/Wikip%C3%A9dia:Le_Bistro/13_janvier_2016#Modif_du_mod%C3%A8le:Ouvrage.
568
     *
569
     * @param $param
570
     *
571
     * @throws Exception
572
     */
573
    private function typoDeuxPoints($param)
574
    {
575
        $origin = $this->getParam($param) ?? '';
576
        if (empty($origin)) {
577
            return;
578
        }
579
        // FIXED bug [[fu:bar]]
580
        if (WikiTextUtil::isWikify($origin)) {
581
            return;
582
        }
583
584
        $origin = TextUtil::replaceNonBreakingSpaces($origin);
585
586
        $strTitle = $origin;
587
588
        // CORRECTING TYPO FANTASY OF SUBTITLE
589
590
        // Replace first '.' by ':' if no ': ' and no numbers around (as PHP 7.3)
591
        // exlude pattern "blabla... blabla"
592
        // TODO: statistics
593
594
        // Replace ' - ' or ' / ' (spaced!) by ' : ' if no ':' and no numbers after (as PHP 7.3 or 1939-1945)
595
        if (!mb_strpos(':', $strTitle) && preg_match('#.{6,} ?[-/] ?[^0-9)]{6,}#', $strTitle) > 0) {
596
            $strTitle = preg_replace('#(.{6,}) [-/] ([^0-9)]{6,})#', '$1 : $2', $strTitle);
597
        }
598
599
        // international typo style " : " (first occurrence)
600
        $strTitle = preg_replace('#[ ]*:[ ]*#', ' : ', $strTitle);
601
602
        if ($strTitle !== $origin) {
603
            $this->setParam($param, $strTitle);
604
            $this->log(sprintf(':%s', $param));
605
        }
606
    }
607
608
    private function valideNumeroChapitre()
609
    {
610
        $value = $this->getParam('numéro chapitre');
611
        if (empty($value)) {
612
            return;
613
        }
614
        // "12" ou "VI", {{II}}, II:3
615
        if (preg_match('#^[0-9IVXL\-.:{}]+$#i', $value) > 0) {
616
            return;
617
        }
618
        // déplace vers "titre chapitre" ?
619
        if (!$this->getParam('titre chapitre')) {
620
            $this->unsetParam('numéro chapitre');
621
            $this->setParam('titre chapitre', $value);
622
        }
623
        $this->log('≠numéro chapitre');
624
    }
625
626
    private function unsetParam($name)
627
    {
628
        $this->ouvrage->unsetParam($name);
629
    }
630
631
    /**
632
     * TODO move+refac
633
     * TODO PlumeTemplate CommentaireBiblioTemplate  ExtraitTemplate
634
     * Probleme {{commentaire biblio}} <> {{commentaire biblio SRL}}
635
     * Generate supplementary templates from obsoletes params.
636
     *
637
     * @throws Exception
638
     */
639
    protected function externalTemplates()
640
    {
641
        // "plume=bla" => {{plume}}
642
        // =oui selon doc, mais testé OK avec "non"
643
        // todo detect duplication ouvrage/plume dans externalTemplate ?
644
        if (!empty($this->getParam('plume'))) {
645
            $plumeValue = $this->getParam('plume');
646
            $this->ouvrage->externalTemplates[] = (object)[
647
                'template' => 'plume',
648
                '1' => $plumeValue,
649
                'raw' => '{{nobr|. {{plume}}}}',
650
            ];
651
            $this->unsetParam('plume');
652
            $this->log('{plume}');
653
        }
654
655
        // "extrait=bla" => {{citation bloc|bla}}
656
        if (!empty($this->getParam('extrait'))) {
657
            $extrait = $this->getParam('extrait');
658
            // todo bug {{citation bloc}} si "=" ou "|" dans texte de citation
659
            // Legacy : use {{début citation}} ... {{fin citation}}
660
            if (preg_match('#[=|]#', $extrait) > 0) {
661
                $this->ouvrage->externalTemplates[] = (object)[
662
                    'template' => 'début citation',
663
                    '1' => '',
664
                    'raw' => '{{début citation}}'.$extrait.'{{fin citation}}',
665
                ];
666
                $this->log('{début citation}');
667
                $this->notCosmetic = true;
668
            } else {
669
                // StdClass
670
                $this->ouvrage->externalTemplates[] = (object)[
671
                    'template' => 'citation bloc',
672
                    '1' => $extrait,
673
                    'raw' => '{{extrait|'.$extrait.'}}',
674
                ];
675
                $this->log('{extrait}');
676
                $this->notCosmetic = true;
677
            }
678
679
            $this->unsetParam('extrait');
680
            $this->notCosmetic = true;
681
        }
682
683
        // "commentaire=bla" => {{Commentaire biblio|1=bla}}
684
        if (!empty($this->getParam('commentaire'))) {
685
            $commentaire = $this->getParam('commentaire');
686
            $this->ouvrage->externalTemplates[] = (object)[
687
                'template' => 'commentaire biblio',
688
                '1' => $commentaire,
689
                'raw' => '{{commentaire biblio|'.$commentaire.'}}',
690
            ];
691
            $this->unsetParam('commentaire');
692
            $this->log('{commentaire}');
693
            $this->notCosmetic = true;
694
        }
695
    }
696
697
    // ----------------------
698
    // ----------------------
699
    // ----------------------
700
701
    /**
702
     * Date->année (nécessaire pour OuvrageComplete).
703
     *
704
     * @throws Exception
705
     */
706
    private function moveDate2Year()
707
    {
708
        $date = $this->getParam('date') ?? false;
709
        if ($date) {
710
            if (preg_match('#^-?[12][0-9][0-9][0-9]$#', $date)) {
711
                $this->setParam('année', $date);
712
                $this->unsetParam('date');
713
                //$this->log('>année');
714
            }
715
        }
716
    }
717
718
    private function predictFormatByPattern()
719
    {
720
        if (($value = $this->getParam('format'))) {
721
            // predict if 'format électronique'
722
            // format electronique lié au champ 'lire en ligne'
723
            // 2015 https://fr.wikipedia.org/wiki/Discussion_mod%C3%A8le:Ouvrage#format,_format_livre,_format_%C3%A9lectronique
724
            //            if (preg_match('#(pdf|epub|html|kindle|audio|\{\{aud|jpg)#i', $value) > 0) {
725
            //
726
            //                $this->setParam('format électronique', $value);
727
            //                $this->unsetParam('format');
728
            //                $this->log('format:électronique?');
729
            //
730
            //                return;
731
            //            }
732
            if (preg_match(
733
                    '#(ill\.|couv\.|in-[0-9]|in-fol|poche|broché|relié|{{unité|{{Dunité|[0-9]{2} ?cm|\|cm}}|vol\.|A4)#i',
734
                    $value
735
                ) > 0
736
            ) {
737
                $this->setParam('format livre', $value);
738
                $this->unsetParam('format');
739
                $this->log('format:livre?');
740
                $this->notCosmetic = true;
741
            }
742
            // Certainement 'format électronique'...
743
        }
744
    }
745
746
    /**
747
     * @return bool
748
     * @throws Exception
749
     */
750
    public function checkMajorEdit(): bool
751
    {
752
        // Correction paramètre
753
        if ($this->ouvrage->parametersErrorFromHydrate !== $this->original->parametersErrorFromHydrate) {
754
            return true;
755
        }
756
        // Complétion langue ?
757
        if (!empty($this->getParam('langue')) && empty($this->original->getParam('langue'))
758
            && self::WIKI_LANGUAGE !== $this->getParam('langue')
759
        ) {
760
            return true;
761
        }
762
        // TODO replace conditions ci-dessous par event flagMajor()
763
        // Retire le param/value 'langue' (pas major si conversion nom langue)
764
        $datOuvrage = $this->ouvrage->toArray();
765
        $datOriginal = $this->original->toArray();
766
        unset($datOriginal['langue'], $datOuvrage['langue']);
767
768
        // Modification données
769
        if ($datOriginal !== $datOuvrage) {
770
            return true;
771
        }
772
773
        return false;
774
    }
775
776
    /**
777
     * @return array
778
     */
779
    public function getLog(): array
780
    {
781
        return $this->log;
782
    }
783
784
    /**
785
     * @return OuvrageTemplate
786
     */
787
    public function getOuvrage(): OuvrageTemplate
788
    {
789
        return $this->ouvrage;
790
    }
791
792
    /**
793
     * todo : vérif lien rouge
794
     * todo 'lien éditeur' affiché 1x par page
795
     * opti : Suppression lien éditeur si c'est l'article de l'éditeur.
796
     *
797
     * @throws Exception
798
     */
799
    private function processEditeur()
800
    {
801
        $editeur = $this->getParam('éditeur');
802
        if (empty($editeur)) {
803
            return;
804
        }
805
806
        // FIX bug "GEO Art ([[Prisma Media]]) ; [[Le Monde]]"
807
        if (preg_match('#\[.*\[.*\[#', $editeur) > 0) {
808
            return;
809
        }
810
        // FIX bug "[[Fu|Bar]] bla" => [[Fu|Bar bla]]
811
        if (preg_match('#(.+\[\[|\]\].+)#', $editeur) > 0) {
812
            return;
813
        }
814
815
        // [[éditeur]]
816
        if (preg_match('#\[\[([^|]+)]]#', $editeur, $matches) > 0) {
817
            $editeurUrl = $matches[1];
818
        }
819
        // [[bla|éditeur]]
820
        if (preg_match('#\[\[([^]|]+)\|.+]]#', $editeur, $matches) > 0) {
821
            $editeurUrl = $matches[1];
822
        }
823
824
        // abréviations communes
825
        // ['éd. de ', 'éd. du ', 'éd.', 'ed.', 'Éd. de ', 'Éd.', 'édit.', 'Édit.', '(éd.)', '(ed.)', 'Ltd.']
826
827
        $editeurStr = WikiTextUtil::unWikify($editeur);
828
        // On garde minuscule sur éditeur, pour nuance Éditeur/éditeur permettant de supprimer "éditeur"
829
        // ex: "éditions Milan" => "Milan"
830
831
        //        $editeurStr = TextUtil::mb_ucfirst($editeurStr);
832
833
        // Déconseillé : 'lien éditeur' (obsolete 2019)
834
        if (!empty($this->getParam('lien éditeur'))) {
835
            if (empty($editeurUrl)) {
836
                $editeurUrl = $this->getParam('lien éditeur');
837
            }
838
            $this->unsetParam('lien éditeur');
839
        }
840
841
        //        if (isset($editeurUrl)) {
842
        //            $editeurUrl = TextUtil::mb_ucfirst($editeurUrl);
843
        //        }
844
        $newEditeur = $editeurStr;
845
        if (isset($editeurUrl) && $editeurUrl !== $editeurStr) {
846
            $newEditeur = '[['.$editeurUrl.'|'.$editeurStr.']]';
847
        }
848
        if (isset($editeurUrl) && $editeurUrl === $editeurStr) {
849
            $newEditeur = '[['.$editeurStr.']]';
850
        }
851
852
        if ($newEditeur !== $editeur) {
853
            $this->setParam('éditeur', $newEditeur);
854
            $this->log('±éditeur');
855
            $this->notCosmetic = true;
856
        }
857
    }
858
}
859