| Total Complexity | 73 |
| Total Lines | 454 |
| Duplicated Lines | 0 % |
| Coverage | 87.88% |
| Changes | 8 | ||
| Bugs | 0 | Features | 0 |
Complex classes like OuvrageComplete often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use OuvrageComplete, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 26 | class OuvrageComplete |
||
| 27 | { |
||
| 28 | const WIKI_LANGUAGE = 'fr'; |
||
| 29 | |||
| 30 | /** |
||
| 31 | * @var OuvrageTemplate |
||
| 32 | */ |
||
| 33 | private $origin; |
||
| 34 | |||
| 35 | private $book; |
||
| 36 | |||
| 37 | public $major = false; |
||
| 38 | |||
| 39 | public $notCosmetic = false; |
||
| 40 | |||
| 41 | private $summaryLog = []; |
||
| 42 | |||
| 43 | //todo: injection référence base ou mapping ? (Google |
||
| 44 | /** |
||
| 45 | * @var LoggerInterface|NullLogger |
||
| 46 | */ |
||
| 47 | private $log; |
||
| 48 | |||
| 49 | 18 | public function __construct(OuvrageTemplate $origin, OuvrageTemplate $book, ?LoggerInterface $log = null) |
|
| 50 | { |
||
| 51 | 18 | $this->origin = clone $origin; |
|
| 52 | 18 | $this->book = $book; |
|
| 53 | 18 | $this->log = $log ?? new NullLogger(); |
|
| 54 | 18 | } |
|
| 55 | |||
| 56 | public function getSummaryLog(): array |
||
| 57 | { |
||
| 58 | return $this->summaryLog; |
||
| 59 | } |
||
| 60 | |||
| 61 | /** |
||
| 62 | * @return OuvrageTemplate |
||
| 63 | * @throws Exception |
||
| 64 | */ |
||
| 65 | 16 | public function getResult() |
|
| 66 | { |
||
| 67 | 16 | $this->complete(); |
|
| 68 | |||
| 69 | 16 | return $this->origin; |
|
| 70 | } |
||
| 71 | |||
| 72 | /** |
||
| 73 | * @return bool |
||
| 74 | * @throws Exception |
||
| 75 | */ |
||
| 76 | 16 | private function complete() |
|
| 77 | { |
||
| 78 | // si livre suspect, on stoppe |
||
| 79 | 16 | $sameBook = $this->predictSameBook(); |
|
| 80 | 16 | if (!$sameBook) { |
|
| 81 | $this->log->info('not same book'); |
||
| 82 | |||
| 83 | return false; |
||
| 84 | } |
||
| 85 | |||
| 86 | $skipParam = [ |
||
| 87 | 16 | 'isbn invalide', |
|
| 88 | 'auteurs', |
||
| 89 | 'auteur1', |
||
| 90 | 'prénom1', |
||
| 91 | 'nom1', |
||
| 92 | 'auteur2', |
||
| 93 | 'prénom2', |
||
| 94 | 'nom2', |
||
| 95 | 'auteur3', |
||
| 96 | 'prénom3', |
||
| 97 | 'nom3', |
||
| 98 | 'auteur4', |
||
| 99 | 'prénom4', |
||
| 100 | 'nom4', |
||
| 101 | 'lire en ligne', |
||
| 102 | 'présentation en ligne', |
||
| 103 | 'date', |
||
| 104 | 'sous-titre', |
||
| 105 | 'lien auteur1', |
||
| 106 | 'lien auteur2', |
||
| 107 | ]; |
||
| 108 | |||
| 109 | // completion automatique |
||
| 110 | 16 | foreach ($this->book->toArray() as $param => $value) { |
|
| 111 | 16 | if (!$this->origin->hasParamValue($param)) { |
|
|
1 ignored issue
–
show
|
|||
| 112 | 14 | if (in_array($param, $skipParam)) { |
|
| 113 | 12 | continue; |
|
| 114 | } |
||
| 115 | // skip 'année' if 'date' not empty |
||
| 116 | 4 | if ('année' === $param && $this->origin->hasParamValue('date')) { |
|
|
1 ignored issue
–
show
|
|||
| 117 | 1 | continue; |
|
| 118 | } |
||
| 119 | |||
| 120 | 3 | $this->origin->setParam($param, $value); |
|
| 121 | |||
| 122 | 3 | if ('langue' === $param && static::WIKI_LANGUAGE === $value) { |
|
| 123 | //$this->log('fr'.$param); |
||
| 124 | 1 | continue; |
|
| 125 | } |
||
| 126 | |||
| 127 | 2 | $this->log('++'.$param); |
|
| 128 | 2 | $this->major = true; |
|
| 129 | 2 | $this->notCosmetic = true; |
|
| 130 | } |
||
| 131 | } |
||
| 132 | |||
| 133 | 16 | $this->processLienAuteur(); |
|
| 134 | 16 | $this->googleBookProcess(); |
|
| 135 | 16 | $this->processSousTitre(); |
|
| 136 | |||
| 137 | 16 | if ($this->notCosmetic && 'BnF' === $this->book->getDataSource()) { |
|
| 138 | $this->log('@BnF'); |
||
| 139 | } |
||
| 140 | |||
| 141 | 16 | return true; |
|
| 142 | } |
||
| 143 | |||
| 144 | 8 | private function log(string $string): void |
|
| 145 | { |
||
| 146 | 8 | if (!empty($string)) { |
|
| 147 | 8 | $this->summaryLog[] = trim($string); |
|
| 148 | } |
||
| 149 | 8 | } |
|
| 150 | |||
| 151 | /** |
||
| 152 | * Complétion 'lien auteur1' d'après Wikidata et BnF. |
||
| 153 | * Logique : faut pas confondre auteur1/auteur2 pour le lien auteur1. |
||
| 154 | * |
||
| 155 | * @throws Exception |
||
| 156 | */ |
||
| 157 | 16 | private function processLienAuteur() |
|
| 158 | { |
||
| 159 | 16 | $lienAuteur1 = $this->book->getParam('lien auteur1'); |
|
| 160 | 16 | if (empty($lienAuteur1)) { |
|
| 161 | 14 | return; |
|
| 162 | } |
||
| 163 | 2 | if ($this->origin->hasParamValue('lien auteur1')) { |
|
|
1 ignored issue
–
show
|
|||
| 164 | $this->log->debug("lien auteur1 existe déjà\n"); |
||
| 165 | |||
| 166 | return; |
||
| 167 | } |
||
| 168 | |||
| 169 | 2 | $originAuteur1 = $this->concatParamsAuteur1($this->origin); |
|
| 170 | 2 | $bookAuteur1 = $this->concatParamsAuteur1($this->book); |
|
| 171 | |||
| 172 | // Check if wikilink in any of the author param |
||
| 173 | 2 | if (WikiTextUtil::isWikify($originAuteur1)) { |
|
| 174 | $this->log->debug("lien auteur1 existe déjà\n"); |
||
| 175 | |||
| 176 | return; |
||
| 177 | } |
||
| 178 | |||
| 179 | // WP:"Paul Durand" — Bnf "Paul Durand,..." |
||
| 180 | 2 | if (!empty($bookAuteur1) && !empty($originAuteur1) |
|
| 181 | 2 | && (mb_strtolower($bookAuteur1) === mb_strtolower($originAuteur1) |
|
| 182 | 2 | || strpos($originAuteur1, $this->book->getParam('nom1')) !== false) |
|
| 183 | ) { |
||
| 184 | 2 | $this->origin->setParam('lien auteur1', $lienAuteur1); |
|
| 185 | 2 | $this->log('+lien auteur1'); |
|
| 186 | 2 | $this->notCosmetic = true; |
|
| 187 | 2 | $this->major = true; |
|
| 188 | } else { |
||
| 189 | $this->log->debug('auteur1 pas identifié\n'); |
||
| 190 | } |
||
| 191 | // todo: gérer "not same book" avec inversion auteur1/2 avant d'implémenter +lien auteur2 |
||
| 192 | 2 | } |
|
| 193 | |||
| 194 | /** |
||
| 195 | * Concaténation auteur/prénom/nom pour comparaison de wiki-modèles. |
||
| 196 | * |
||
| 197 | * @param OuvrageTemplate $ouvrage |
||
| 198 | * @param int|null $num |
||
| 199 | * |
||
| 200 | * @return string|null |
||
| 201 | * @throws Exception |
||
| 202 | */ |
||
| 203 | 2 | private function concatParamsAuteur1(OuvrageTemplate $ouvrage, ?int $num = 1): ?string |
|
| 204 | { |
||
| 205 | 2 | $auteur = $ouvrage->getParam('auteur'.$num) ?? ''; |
|
| 206 | 2 | $prenom = $ouvrage->getParam('prénom'.$num) ?? ''; |
|
| 207 | 2 | $nom = $ouvrage->getParam('nom'.$num) ?? ''; |
|
| 208 | |||
| 209 | 2 | return trim($auteur.' '.$prenom.' '.$nom); |
|
| 210 | } |
||
| 211 | |||
| 212 | /** |
||
| 213 | * Complétion lire/présentation en ligne, si vide. |
||
| 214 | * Passe Google Book en accès partiel en 'lire en ligne' (sondage) |
||
| 215 | * |
||
| 216 | * @throws Exception |
||
| 217 | */ |
||
| 218 | 16 | private function googleBookProcess() |
|
| 219 | { |
||
| 220 | // si déjà lire/présentation en ligne => on touche à rien |
||
| 221 | 16 | if ($this->origin->hasParamValue('lire en ligne') |
|
|
1 ignored issue
–
show
|
|||
| 222 | 16 | || $this->origin->hasParamValue('présentation en ligne') |
|
|
1 ignored issue
–
show
|
|||
| 223 | ) { |
||
| 224 | return; |
||
| 225 | } |
||
| 226 | |||
| 227 | // completion basique |
||
| 228 | 16 | $booklire = $this->book->getParam('lire en ligne'); |
|
| 229 | 16 | if ($booklire) { |
|
| 230 | 1 | $this->origin->setParam('lire en ligne', $booklire); |
|
| 231 | 1 | $this->log('+lire en ligne'); |
|
| 232 | 1 | $this->notCosmetic = true; |
|
| 233 | 1 | $this->major = true; |
|
| 234 | |||
| 235 | 1 | return; |
|
| 236 | } |
||
| 237 | |||
| 238 | 15 | $presentation = $this->book->getParam('présentation en ligne') ?? false; |
|
| 239 | // Ajout du partial Google => mis en lire en ligne |
||
| 240 | // plutôt que 'présentation en ligne' selon sondage |
||
| 241 | 15 | if (!empty($presentation) && GoogleLivresTemplate::isGoogleBookValue($presentation)) { |
|
| 242 | 1 | $this->origin->setParam('lire en ligne', $presentation); |
|
| 243 | 1 | $this->log('+lire en ligne'); |
|
| 244 | 1 | $this->notCosmetic = true; |
|
| 245 | 1 | $this->major = true; |
|
| 246 | } |
||
| 247 | 15 | } |
|
| 248 | |||
| 249 | /** |
||
| 250 | * @return bool |
||
| 251 | * @throws Exception |
||
| 252 | */ |
||
| 253 | 16 | private function predictSameBook() |
|
| 254 | { |
||
| 255 | 16 | if ($this->hasSameISBN() && ($this->hasSameBookTitles() || $this->hasSameAuthors())) { |
|
| 256 | 2 | return true; |
|
| 257 | } |
||
| 258 | 14 | if ($this->hasSameBookTitles() && $this->hasSameAuthors()) { |
|
| 259 | 14 | return true; |
|
| 260 | } |
||
| 261 | |||
| 262 | return false; |
||
| 263 | } |
||
| 264 | |||
| 265 | /** |
||
| 266 | * @return bool |
||
| 267 | * @throws Exception |
||
| 268 | */ |
||
| 269 | 16 | public function hasSameAuthors(): bool |
|
| 270 | { |
||
| 271 | 16 | if ($this->authorsFromBook($this->origin) === $this->authorsFromBook($this->book)) { |
|
| 272 | 15 | return true; |
|
| 273 | } |
||
| 274 | |||
| 275 | // if there is only 2 char of difference (i.e. typo error) |
||
| 276 | 1 | if (levenshtein($this->authorsFromBook($this->origin), $this->authorsFromBook($this->book)) <= 2) { |
|
| 277 | $this->log('typo auteurs?'); |
||
| 278 | |||
| 279 | return true; |
||
| 280 | } |
||
| 281 | |||
| 282 | // Si auteur manquant sur wikipedia |
||
| 283 | 1 | if (empty($this->authorsFromBook($this->origin))) { |
|
| 284 | return true; |
||
| 285 | } |
||
| 286 | |||
| 287 | 1 | return false; |
|
| 288 | } |
||
| 289 | |||
| 290 | /** |
||
| 291 | * concatenation of parameters (firstname, lastname...) from every authors. |
||
| 292 | * Todo: return array for comparing mixed authors (bob henri == henri bob). |
||
| 293 | * |
||
| 294 | * @param OuvrageTemplate $ouv |
||
| 295 | * |
||
| 296 | * @return string |
||
| 297 | * @throws Exception |
||
| 298 | */ |
||
| 299 | 16 | private function authorsFromBook(OuvrageTemplate $ouv) |
|
| 300 | { |
||
| 301 | 16 | $text = ''; |
|
| 302 | $paramAuteurs = [ |
||
| 303 | 16 | 'auteurs', |
|
| 304 | 'auteur1', |
||
| 305 | 'prénom1', |
||
| 306 | 'nom1', |
||
| 307 | 'auteur2', |
||
| 308 | 'prénom2', |
||
| 309 | 'nom2', |
||
| 310 | 'auteur3', |
||
| 311 | 'prénom3', |
||
| 312 | 'nom3', |
||
| 313 | 'auteur4', |
||
| 314 | 'prénom4', |
||
| 315 | 'nom4', |
||
| 316 | ]; |
||
| 317 | 16 | foreach ($paramAuteurs as $param) { |
|
| 318 | 16 | $value = str_replace(['.', ','], '', $ouv->getParam($param)); |
|
| 319 | // retire wikilien sur auteur |
||
| 320 | 16 | if (!empty($value)) { |
|
| 321 | 4 | $text .= WikiTextUtil::unWikify($value); |
|
| 322 | } |
||
| 323 | } |
||
| 324 | |||
| 325 | 16 | return $this->stripAll($text); |
|
| 326 | } |
||
| 327 | |||
| 328 | /** |
||
| 329 | * @return bool |
||
| 330 | * @throws Exception |
||
| 331 | */ |
||
| 332 | 16 | private function hasSameISBN(): bool |
|
| 333 | { |
||
| 334 | 16 | if (!$this->origin->hasParamValue('isbn') || !$this->book->hasParamValue('isbn')) { |
|
|
1 ignored issue
–
show
|
|||
| 335 | 14 | return false; |
|
| 336 | } |
||
| 337 | // TODO replace with calcul isbn13 |
||
| 338 | 2 | $isbn1 = IsbnFacade::isbn2ean($this->origin->getParam('isbn')); |
|
| 339 | 2 | $isbn2 = IsbnFacade::isbn2ean($this->book->getParam('isbn')); |
|
| 340 | |||
| 341 | 2 | if ($isbn1 === $isbn2) { |
|
| 342 | 2 | return true; |
|
| 343 | } |
||
| 344 | |||
| 345 | return false; |
||
| 346 | } |
||
| 347 | |||
| 348 | /** |
||
| 349 | * Add or extract subtitle like in second book. |
||
| 350 | * |
||
| 351 | * @throws Exception |
||
| 352 | */ |
||
| 353 | 16 | private function processSousTitre() |
|
| 391 | } |
||
| 392 | } |
||
| 393 | 1 | } |
|
| 394 | |||
| 395 | /** |
||
| 396 | * @return bool |
||
| 397 | * @throws Exception |
||
| 398 | */ |
||
| 399 | 16 | private function hasSameBookTitles(): bool |
|
| 400 | { |
||
| 401 | 16 | $originBigTitle = $this->charsFromBigTitle($this->origin); |
|
| 402 | 16 | $bookBigTitle = $this->charsFromBigTitle($this->book); |
|
| 403 | |||
| 404 | 16 | if ($originBigTitle === $bookBigTitle) { |
|
| 405 | 8 | return true; |
|
| 406 | } |
||
| 407 | |||
| 408 | // if there is only 2 chars of difference (i.e. typo error) |
||
| 409 | // strlen for resource management |
||
| 410 | 8 | if (strlen($originBigTitle) < 40 && strlen($bookBigTitle) < 40 |
|
| 411 | 8 | && levenshtein($originBigTitle, $bookBigTitle) <= 2 |
|
| 412 | ) { |
||
| 413 | // $this->log('typo titre?'); // TODO Normalize:: text from external API |
||
| 414 | |||
| 415 | return true; |
||
| 416 | } |
||
| 417 | |||
| 418 | // si l'un des ouvrages ne comporte pas le sous-titre |
||
| 419 | 8 | if ($this->stripAll($this->origin->getParam('titre')) === $this->stripAll($this->book->getParam('titre'))) { |
|
| 420 | 6 | return true; |
|
| 421 | } |
||
| 422 | |||
| 423 | // sous-titre inclus dans le titre |
||
| 424 | // "Loiret : un département à l'élégance naturelle" <=> "Loiret" |
||
| 425 | 2 | if ($this->stripAll($this->mainBookTitle($this->origin->getParam('titre'))) === $this->stripAll( |
|
| 426 | 2 | $this->mainBookTitle($this->origin->getParam('titre')) |
|
| 427 | ) |
||
| 428 | ) { |
||
| 429 | 2 | return true; |
|
| 430 | } |
||
| 431 | // titre manquant sur wiki |
||
| 432 | if (empty($originBigTitle)) { |
||
| 433 | return true; |
||
| 434 | } |
||
| 435 | |||
| 436 | return false; |
||
| 437 | } |
||
| 438 | |||
| 439 | /** |
||
| 440 | * Give string before ":" (or same string if no ":"). |
||
| 441 | * |
||
| 442 | * @param string $str |
||
| 443 | * |
||
| 444 | * @return string |
||
| 445 | */ |
||
| 446 | 2 | private function mainBookTitle(string $str) |
|
| 453 | } |
||
| 454 | |||
| 455 | /** |
||
| 456 | * @param OuvrageTemplate $ouvrage |
||
| 457 | * |
||
| 458 | * @return string |
||
| 459 | * @throws Exception |
||
| 460 | */ |
||
| 461 | 16 | private function charsFromBigTitle(OuvrageTemplate $ouvrage): string |
|
| 462 | { |
||
| 463 | 16 | $text = $ouvrage->getParam('titre').$ouvrage->getParam('sous-titre'); |
|
| 464 | |||
| 465 | 16 | return $this->stripAll(Normalizer::normalize($text)); |
|
| 466 | } |
||
| 467 | |||
| 468 | /** |
||
| 469 | * @param string $text |
||
| 470 | * |
||
| 471 | * @return string |
||
| 472 | */ |
||
| 473 | 18 | private function stripAll(string $text): string |
|
| 480 | } |
||
| 481 | } |
||
| 482 |
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.