Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like Filler 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
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 Filler, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 23 | class Filler extends FillerPlugin |
||
| 24 | { |
||
| 25 | /** |
||
| 26 | * Name. |
||
| 27 | * |
||
| 28 | * @var string |
||
| 29 | */ |
||
| 30 | const NAME = 'world-art'; |
||
| 31 | |||
| 32 | /** |
||
| 33 | * Title. |
||
| 34 | * |
||
| 35 | * @var string |
||
| 36 | */ |
||
| 37 | const TITLE = 'World-Art.ru'; |
||
| 38 | |||
| 39 | /** |
||
| 40 | * XPath for fill item. |
||
| 41 | * |
||
| 42 | * @var string |
||
| 43 | */ |
||
| 44 | const XPATH_FOR_FILL = '//center/table[@height="58%"]/tr/td/table[1]/tr/td'; |
||
| 45 | |||
| 46 | /** |
||
| 47 | * Item type animation. |
||
| 48 | * |
||
| 49 | * @var string |
||
| 50 | */ |
||
| 51 | const ITEM_TYPE_ANIMATION = 'animation'; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * Item type cinema. |
||
| 55 | * |
||
| 56 | * @var string |
||
| 57 | */ |
||
| 58 | const ITEM_TYPE_CINEMA = 'cinema'; |
||
| 59 | |||
| 60 | /** |
||
| 61 | * Browser. |
||
| 62 | * |
||
| 63 | * @var \AnimeDb\Bundle\WorldArtFillerBundle\Service\Browser |
||
| 64 | */ |
||
| 65 | protected $browser; |
||
| 66 | |||
| 67 | /** |
||
| 68 | * Doctrine. |
||
| 69 | * |
||
| 70 | * @var \Doctrine\Bundle\DoctrineBundle\Registry |
||
| 71 | */ |
||
| 72 | protected $doctrine; |
||
| 73 | |||
| 74 | /** |
||
| 75 | * Downloader. |
||
| 76 | * |
||
| 77 | * @var \AnimeDb\Bundle\AppBundle\Service\Downloader |
||
| 78 | */ |
||
| 79 | protected $downloader; |
||
| 80 | |||
| 81 | /** |
||
| 82 | * World-Art genres. |
||
| 83 | * |
||
| 84 | * @var array |
||
| 85 | */ |
||
| 86 | protected $genres = [ |
||
| 87 | 'боевик' => 'Action', |
||
| 88 | 'фильм действия' => 'Action', |
||
| 89 | 'боевые искусства' => 'Martial arts', |
||
| 90 | 'вампиры' => 'Vampire', |
||
| 91 | 'война' => 'War', |
||
| 92 | 'детектив' => 'Detective', |
||
| 93 | 'для детей' => 'Kids', |
||
| 94 | 'дзёсэй' => 'Josei', |
||
| 95 | 'драма' => 'Drama', |
||
| 96 | 'история' => 'History', |
||
| 97 | 'киберпанк' => 'Cyberpunk', |
||
| 98 | 'комедия' => 'Comedy', |
||
| 99 | 'махо-сёдзё' => 'Mahoe shoujo', |
||
| 100 | 'меха' => 'Mecha', |
||
| 101 | 'мистерия' => 'Mystery', |
||
| 102 | 'мистика' => 'Mystery', |
||
| 103 | 'музыкальный' => 'Music', |
||
| 104 | 'образовательный' => 'Educational', |
||
| 105 | 'пародия' => 'Parody', |
||
| 106 | 'cтимпанк' => 'Steampunk', |
||
| 107 | 'паропанк' => 'Steampunk', |
||
| 108 | 'повседневность' => 'Slice of life', |
||
| 109 | 'полиция' => 'Police', |
||
| 110 | 'постапокалиптика' => 'Apocalyptic fiction', |
||
| 111 | 'приключения' => 'Adventure', |
||
| 112 | 'приключенческий фильм' => 'Adventure', |
||
| 113 | 'психология' => 'Psychological', |
||
| 114 | 'романтика' => 'Romance', |
||
| 115 | 'самурайский боевик' => 'Samurai', |
||
| 116 | 'сёдзё' => 'Shoujo', |
||
| 117 | 'сёдзё-ай' => 'Shoujo-ai', |
||
| 118 | 'сёнэн' => 'Shounen', |
||
| 119 | 'сёнэн-ай' => 'Shounen-ai', |
||
| 120 | 'сказка' => 'Fable', |
||
| 121 | 'спорт' => 'Sport', |
||
| 122 | 'сэйнэн' => 'Senen', |
||
| 123 | 'триллер' => 'Thriller', |
||
| 124 | 'школа' => 'School', |
||
| 125 | 'фантастика' => 'Sci-fi', |
||
| 126 | 'кинофантазия' => 'Fantastic', |
||
| 127 | 'фэнтези' => 'Fantasy', |
||
| 128 | 'эротика' => 'Erotica', |
||
| 129 | 'этти' => 'Ecchi', |
||
| 130 | 'ужасы' => 'Horror', |
||
| 131 | 'хентай' => 'Hentai', |
||
| 132 | 'юри' => 'Yuri', |
||
| 133 | 'яой' => 'Yaoi', |
||
| 134 | ]; |
||
| 135 | |||
| 136 | /** |
||
| 137 | * World-Art types. |
||
| 138 | * |
||
| 139 | * @var array |
||
| 140 | */ |
||
| 141 | protected $types = [ |
||
| 142 | 'ТВ' => 'tv', |
||
| 143 | 'ТВ-спэшл' => 'special', |
||
| 144 | 'OVA' => 'ova', |
||
| 145 | 'ONA' => 'ona', |
||
| 146 | 'OAV' => 'ova', |
||
| 147 | 'полнометражный фильм' => 'feature', |
||
| 148 | 'короткометражный фильм' => 'featurette', |
||
| 149 | 'музыкальное видео' => 'music', |
||
| 150 | 'рекламный ролик' => 'commercial', |
||
| 151 | ]; |
||
| 152 | |||
| 153 | /** |
||
| 154 | * World-Art studios. |
||
| 155 | * |
||
| 156 | * @var array |
||
| 157 | */ |
||
| 158 | protected $studios = [ |
||
| 159 | 1 => 'Studio Ghibli', |
||
| 160 | 3 => 'Gainax', |
||
| 161 | 4 => 'AIC', |
||
| 162 | 6 => 'KSS', |
||
| 163 | 14 => 'TMS Entertainment', |
||
| 164 | 20 => 'Bones', |
||
| 165 | 21 => 'Clamp', |
||
| 166 | 22 => 'Studio DEEN', |
||
| 167 | 24 => 'J.C.Staff', |
||
| 168 | 25 => 'Madhouse', |
||
| 169 | 26 => 'animate', |
||
| 170 | 29 => 'OLM, Inc.', |
||
| 171 | 30 => 'Tezuka Productions', |
||
| 172 | 31 => 'Production I.G', |
||
| 173 | 32 => 'Gonzo', |
||
| 174 | 34 => 'Sunrise', |
||
| 175 | 37 => 'Agent 21', |
||
| 176 | 41 => 'Toei Animation', |
||
| 177 | 44 => 'APPP', |
||
| 178 | 54 => 'Radix', |
||
| 179 | 56 => 'Pierrot', |
||
| 180 | 59 => 'XEBEC', |
||
| 181 | 64 => 'Satelight', |
||
| 182 | 74 => 'Oh! Production', |
||
| 183 | 78 => 'Triangle Staff', |
||
| 184 | 82 => 'Bee Train', |
||
| 185 | 84 => 'Animax', |
||
| 186 | 87 => 'Daume', |
||
| 187 | 89 => 'Kitty Films', |
||
| 188 | 92 => 'Ajia-do', |
||
| 189 | 96 => 'Studio 4°C', |
||
| 190 | 106 => 'CoMix Wave Inc.', |
||
| 191 | 116 => 'Fox Animation Studios', |
||
| 192 | 117 => 'Blue Sky Studios', |
||
| 193 | 118 => 'Pacific Data Images', |
||
| 194 | 120 => 'Pixar', |
||
| 195 | 152 => 'Mushi Production', |
||
| 196 | 154 => 'Aardman Animations', |
||
| 197 | 159 => 'DR Movie', |
||
| 198 | 171 => 'Tatsunoko Productions', |
||
| 199 | 178 => 'Paramount Animation', |
||
| 200 | 193 => 'Hal Film Maker', |
||
| 201 | 198 => 'Studio Fantasia', |
||
| 202 | 210 => 'Arms Corporation', |
||
| 203 | 212 => 'Green Bunny', |
||
| 204 | 236 => 'Pink Pineapple', |
||
| 205 | 244 => 'Production Reed', |
||
| 206 | // reverse links |
||
| 207 | 250 => 'Melnitsa Animation Studio', |
||
| 208 | 252 => 'Nippon Animation', |
||
| 209 | 255 => 'Artland', |
||
| 210 | 267 => 'SHAFT', |
||
| 211 | 278 => 'March Entertainment', |
||
| 212 | 296 => 'Gallop', |
||
| 213 | 315 => 'DreamWorks Animation', |
||
| 214 | 351 => 'TNK', |
||
| 215 | 398 => 'A.C.G.T.', |
||
| 216 | 436 => 'Kyoto Animation', |
||
| 217 | 439 => 'Studio Comet', |
||
| 218 | 463 => 'Magic Bus', |
||
| 219 | 639 => 'Industrial Light & Magic', |
||
| 220 | 689 => 'ZEXCS', |
||
| 221 | 724 => 'Six Point Harness', |
||
| 222 | 753 => 'Pentamedia Graphics', |
||
| 223 | 795 => 'Rough Draft Studios', |
||
| 224 | 802 => 'Shin-Ei Animation', |
||
| 225 | 821 => 'Warner Bros. Animation', |
||
| 226 | 1066 => 'Animal Logic', |
||
| 227 | 1161 => 'Marvel Animation Studios', |
||
| 228 | 1168 => 'Klasky Csupo', |
||
| 229 | 1654 => 'Digital Frontier', |
||
| 230 | 1663 => 'Mac Guff', |
||
| 231 | 1689 => 'Manglobe', |
||
| 232 | 1778 => 'CinéGroupe', |
||
| 233 | 1889 => 'Film Roman, Inc.', |
||
| 234 | 1890 => 'AKOM', |
||
| 235 | 1901 => 'Brain\'s Base', |
||
| 236 | 1961 => 'feel.', |
||
| 237 | 2058 => 'Eiken', |
||
| 238 | 2229 => 'Studio Hibari', |
||
| 239 | 2370 => 'IMAGIN', |
||
| 240 | 2379 => 'Folimage', |
||
| 241 | 2381 => 'DisneyToon Studios', |
||
| 242 | 2491 => 'ufotable', |
||
| 243 | 3058 => 'Asahi Production', |
||
| 244 | 3096 => 'Mook Animation', |
||
| 245 | 3113 => 'Walt Disney Television Animation', |
||
| 246 | 3420 => 'Metro-Goldwyn-Mayer Animation', |
||
| 247 | 3530 => 'Seven Arcs', |
||
| 248 | 3742 => 'Nomad', |
||
| 249 | 3748 => 'Dygra Films', |
||
| 250 | 3773 => 'Dogakobo', |
||
| 251 | 3816 => 'EMation', |
||
| 252 | 4013 => 'Toon City', |
||
| 253 | 5423 => 'O Entertainment/Omation Animation Studio', |
||
| 254 | 6081 => 'Sony Pictures Animation', |
||
| 255 | 6474 => 'Wang Film Productions', |
||
| 256 | 6475 => 'Creative Capers Entertainment', |
||
| 257 | 6701 => 'Arc Productions', |
||
| 258 | 7092 => 'Millimages', |
||
| 259 | 7194 => 'Mondo TV', |
||
| 260 | 7298 => 'A-1 Pictures Inc.', |
||
| 261 | 7372 => 'Diomedea', |
||
| 262 | 7388 => 'Williams Street Studios', |
||
| 263 | 7801 => 'National Film Board of Canada', |
||
| 264 | 7933 => 'Titmouse', |
||
| 265 | 8590 => 'Rhythm and Hues Studios', |
||
| 266 | 8639 => 'Bagdasarian Productions', |
||
| 267 | 9298 => 'Toonz', |
||
| 268 | 9900 => 'Savage Studios Ltd.', |
||
| 269 | 10664 => 'A. Film', |
||
| 270 | 11077 => 'Vanguard Animation', |
||
| 271 | 11213 => 'bolexbrothers', |
||
| 272 | 11827 => 'Zinkia Entertainment', |
||
| 273 | 12209 => 'P.A. Works', |
||
| 274 | 12268 => 'Universal Animation Studios', |
||
| 275 | 12280 => 'Reel FX', |
||
| 276 | 12281 => 'Walt Disney Animation Studios', |
||
| 277 | 12299 => 'LAIKA', |
||
| 278 | 12825 => 'White Fox', |
||
| 279 | 13269 => 'David Production', |
||
| 280 | 13301 => 'Silver Link', |
||
| 281 | 13329 => 'Kinema Citrus', |
||
| 282 | 13906 => 'GoHands', |
||
| 283 | 13957 => 'Khara', |
||
| 284 | 14617 => 'Ordet', |
||
| 285 | 15102 => 'TYO Animations', |
||
| 286 | 15334 => 'Dong Woo Animation', |
||
| 287 | 16112 => 'Studio Gokumi', |
||
| 288 | 16433 => 'Nickelodeon Animation Studios', |
||
| 289 | 16961 => 'Renegade Animation', |
||
| 290 | 17049 => 'Curious Pictures', |
||
| 291 | 17235 => 'Trigger', |
||
| 292 | 17322 => 'Wit Studio', |
||
| 293 | ]; |
||
| 294 | |||
| 295 | /** |
||
| 296 | * Construct. |
||
| 297 | * |
||
| 298 | * @param \AnimeDb\Bundle\WorldArtFillerBundle\Service\Browser $browser |
||
| 299 | * @param \Doctrine\Bundle\DoctrineBundle\Registry $doctrine |
||
| 300 | * @param \AnimeDb\Bundle\AppBundle\Service\Downloader $downloader |
||
| 301 | */ |
||
| 302 | public function __construct(Browser $browser, Registry $doctrine, Downloader $downloader) |
||
| 308 | |||
| 309 | /** |
||
| 310 | * Get name. |
||
| 311 | * |
||
| 312 | * @return string |
||
| 313 | */ |
||
| 314 | public function getName() |
||
| 318 | |||
| 319 | /** |
||
| 320 | * Get title. |
||
| 321 | * |
||
| 322 | * @return string |
||
| 323 | */ |
||
| 324 | public function getTitle() |
||
| 328 | |||
| 329 | /** |
||
| 330 | * Get form. |
||
| 331 | * |
||
| 332 | * @return \AnimeDb\Bundle\WorldArtFillerBundle\Form\Type\Filler |
||
| 333 | */ |
||
| 334 | public function getForm() |
||
| 338 | |||
| 339 | /** |
||
| 340 | * Build menu for plugin. |
||
| 341 | * |
||
| 342 | * @param \Knp\Menu\ItemInterface $item |
||
| 343 | * |
||
| 344 | * @return \Knp\Menu\ItemInterface |
||
| 345 | */ |
||
| 346 | public function buildMenu(ItemInterface $item) |
||
| 351 | |||
| 352 | /** |
||
| 353 | * Fill item from source. |
||
| 354 | * |
||
| 355 | * @param array $data |
||
| 356 | * |
||
| 357 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item|null |
||
| 358 | */ |
||
| 359 | public function fill(array $data) |
||
| 439 | |||
| 440 | /** |
||
| 441 | * Get element attributes as array. |
||
| 442 | * |
||
| 443 | * @param \DOMElement $element |
||
| 444 | * |
||
| 445 | * @return array |
||
| 446 | */ |
||
| 447 | private function getAttrAsArray(\DOMElement $element) |
||
| 448 | { |
||
| 449 | $return = []; |
||
| 450 | for ($i = 0; $i < $element->attributes->length; ++$i) { |
||
| 451 | $return[$element->attributes->item($i)->nodeName] = $element->attributes->item($i)->nodeValue; |
||
| 452 | } |
||
| 453 | |||
| 454 | return $return; |
||
| 455 | } |
||
| 456 | |||
| 457 | /** |
||
| 458 | * Get cover from source id. |
||
| 459 | * |
||
| 460 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
| 461 | * @param string $id |
||
| 462 | * @param string $type |
||
| 463 | * |
||
| 464 | * @return bool |
||
| 465 | */ |
||
| 466 | private function setCover(Item $item, $id, $type) |
||
| 467 | { |
||
| 468 | $item->setCover(self::NAME.'/'.$id.'/1.jpg'); |
||
| 469 | |||
| 470 | return $this->uploadImage($this->getCoverUrl($id, $type), $item); |
||
| 471 | } |
||
| 472 | |||
| 473 | /** |
||
| 474 | * Fill head data. |
||
| 475 | * |
||
| 476 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
| 477 | * @param \DOMXPath $xpath |
||
| 478 | * @param \DOMElement $head |
||
| 479 | * |
||
| 480 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item |
||
| 481 | */ |
||
| 482 | private function fillHeadData(Item $item, \DOMXPath $xpath, \DOMElement $head) |
||
| 483 | { |
||
| 484 | /* @var $data \DOMElement */ |
||
| 485 | $data = $xpath->query('font', $head)->item(0); |
||
| 486 | $length = $data->childNodes->length; |
||
| 487 | for ($i = 0; $i < $length; ++$i) { |
||
| 488 | if ($data->childNodes->item($i)->nodeName == 'b') { |
||
| 489 | switch ($data->childNodes->item($i)->nodeValue) { |
||
| 490 | // set country |
||
| 491 | case 'Производство': |
||
| 492 | $j = 1; |
||
| 493 | do { |
||
| 494 | if ($data->childNodes->item($i + $j)->nodeName == 'a') { |
||
| 495 | $country_name = trim($data->childNodes->item($i + $j)->nodeValue); |
||
| 496 | if ($country_name && $country = $this->getCountryByName($country_name)) { |
||
| 497 | $item->setCountry($country); |
||
| 498 | } |
||
| 499 | break; |
||
| 500 | } |
||
| 501 | ++$j; |
||
| 502 | } while ($data->childNodes->item($i + $j)->nodeName != 'br'); |
||
| 503 | $i += $j; |
||
| 504 | break; |
||
| 505 | // add genre |
||
| 506 | case 'Жанр': |
||
| 507 | $j = 2; |
||
| 508 | do { |
||
| 509 | if ($data->childNodes->item($i + $j)->nodeName == 'a' && |
||
| 510 | ($genre = $this->getGenreByName($data->childNodes->item($i + $j)->nodeValue)) |
||
| 511 | ) { |
||
| 512 | $item->addGenre($genre); |
||
| 513 | } |
||
| 514 | ++$j; |
||
| 515 | } while ($data->childNodes->item($i + $j)->nodeName != 'br'); |
||
| 516 | $i += $j; |
||
| 517 | break; |
||
| 518 | // set type and add file info |
||
| 519 | case 'Тип': |
||
| 520 | $type = $data->childNodes->item($i + 1)->nodeValue; |
||
| 521 | if (preg_match('/(?<type>[\w\s]+)(?: \((?:(?<episodes_number>>?\d+) эп.)?(?<file_info>.*)\))?(, (?<duration>\d{1,3}) мин\.)?$/u', $type, $match)) { |
||
| 522 | // add type |
||
| 523 | if ($type = $this->getTypeByName(trim($match['type']))) { |
||
| 524 | $item->setType($type); |
||
| 525 | } |
||
| 526 | // add duration |
||
| 527 | if (!empty($match['duration'])) { |
||
| 528 | $item->setDuration((int) $match['duration']); |
||
| 529 | } |
||
| 530 | // add number of episodes |
||
| 531 | if (!empty($match['episodes_number'])) { |
||
| 532 | if ($match['episodes_number'][0] == '>') { |
||
| 533 | $item->setEpisodesNumber(substr($match['episodes_number'], 1).'+'); |
||
| 534 | } else { |
||
| 535 | $item->setEpisodesNumber((int) $match['episodes_number']); |
||
| 536 | } |
||
| 537 | } elseif ($item->getType()->getId() != 'tv') { |
||
| 538 | // everything except the TV series consist of a single episode |
||
| 539 | $item->setEpisodesNumber(1); |
||
| 540 | } |
||
| 541 | // add file info |
||
| 542 | if (!empty($match['file_info'])) { |
||
| 543 | $file_info = $item->getFileInfo(); |
||
| 544 | $item->setFileInfo(($file_info ? $file_info."\n" : '').trim($match['file_info'])); |
||
| 545 | } |
||
| 546 | } |
||
| 547 | ++$i; |
||
| 548 | break; |
||
| 549 | // set date premiere and date end if exists |
||
| 550 | case 'Премьера': |
||
| 551 | case 'Выпуск': |
||
| 552 | $j = 1; |
||
| 553 | $date = ''; |
||
| 554 | do { |
||
| 555 | $date .= $data->childNodes->item($i + $j)->nodeValue; |
||
| 556 | ++$j; |
||
| 557 | } while ($length > $i + $j && $data->childNodes->item($i + $j)->nodeName != 'br'); |
||
| 558 | $i += $j; |
||
| 559 | |||
| 560 | $reg = '/(?<start>(?:(?:\d{2})|(?:\?\?)).\d{2}.\d{4})'. |
||
| 561 | '(?:.*(?<end>(?:(?:\d{2})|(?:\?\?)).\d{2}.\d{4}))?/'; |
||
| 562 | if (preg_match($reg, $date, $match)) { |
||
| 563 | $item->setDatePremiere(new \DateTime(str_replace('??', '01', $match['start']))); |
||
| 564 | if (isset($match['end'])) { |
||
| 565 | $item->setDateEnd(new \DateTime($match['end'])); |
||
| 566 | } |
||
| 567 | } |
||
| 568 | break; |
||
| 569 | case 'Хронометраж': |
||
| 570 | if (preg_match('/(?<duration>\d+)/', $data->childNodes->item($i + 1)->nodeValue, $match)) { |
||
| 571 | $item->setDuration((int) $match['duration']); |
||
| 572 | } |
||
| 573 | break; |
||
| 574 | case 'Кол-во серий': |
||
| 575 | $number = trim($data->childNodes->item($i + 1)->nodeValue, ' :'); |
||
| 576 | if (strpos($number, '>') !== false) { |
||
| 577 | $number = str_replace('>', '', $number).'+'; |
||
| 578 | } |
||
| 579 | $item->setEpisodesNumber($number); |
||
| 580 | break; |
||
| 581 | } |
||
| 582 | } |
||
| 583 | } |
||
| 584 | } |
||
| 585 | |||
| 586 | /** |
||
| 587 | * Fill body data. |
||
| 588 | * |
||
| 589 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
| 590 | * @param \DOMXPath $xpath |
||
| 591 | * @param \DOMElement $body |
||
| 592 | * @param int $id |
||
| 593 | * @param bool $frames |
||
| 594 | * @param string $type |
||
| 595 | * |
||
| 596 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item |
||
| 597 | */ |
||
| 598 | private function fillBodyData(Item $item, \DOMXPath $xpath, \DOMElement $body, $id, $frames, $type) |
||
| 599 | { |
||
| 600 | for ($i = 0; $i < $body->childNodes->length; ++$i) { |
||
| 601 | if ($value = trim($body->childNodes->item($i)->nodeValue)) { |
||
| 602 | switch ($value) { |
||
| 603 | // get summary |
||
| 604 | case 'Краткое содержание:': |
||
| 605 | $summary = $xpath->query('tr/td/p[1]', $body->childNodes->item($i + 2)); |
||
| 606 | if ($summary->length) { |
||
| 607 | $item->setSummary($this->getNodeValueAsText($summary->item(0))); |
||
| 608 | } |
||
| 609 | $i += 2; |
||
| 610 | break; |
||
| 611 | // get episodes |
||
| 612 | case 'Эпизоды:': |
||
| 613 | if (!trim($body->childNodes->item($i + 1)->nodeValue)) { // simple list |
||
| 614 | $item->setEpisodes($this->getNodeValueAsText($body->childNodes->item($i + 2))); |
||
| 615 | $i += 2; |
||
| 616 | } else { // episodes in table |
||
| 617 | $rows = $xpath->query('tr/td[2]', $body->childNodes->item($i + 1)); |
||
| 618 | $episodes = ''; |
||
| 619 | for ($j = 1; $j < $rows->length; ++$j) { |
||
| 620 | $episode = $xpath->query('font', $rows->item($j)); |
||
| 621 | $episodes .= $j.'. '.$episode->item(0)->nodeValue; |
||
| 622 | if ($rows->length > 1) { |
||
| 623 | $episodes .= ' ('.$episode->item(1)->nodeValue.')'; |
||
| 624 | } |
||
| 625 | $episodes .= "\n"; |
||
| 626 | } |
||
| 627 | $item->setEpisodes($episodes); |
||
| 628 | ++$i; |
||
| 629 | } |
||
| 630 | break; |
||
| 631 | // get date premiere |
||
| 632 | case 'Даты премьер и релизов': |
||
| 633 | $rows = $xpath->query('tr/td/table/tr/td[3]', $body->childNodes->item($i + 1)); |
||
| 634 | foreach ($rows as $row) { |
||
| 635 | if (preg_match('/\d{4}\.\d{2}\.\d{2}/', $row->nodeValue, $match)) { |
||
| 636 | $date = new \DateTime(str_replace('.', '-', $match[0])); |
||
| 637 | if (!$item->getDatePremiere() || $item->getDatePremiere() > $date) { |
||
| 638 | $item->setDatePremiere($date); |
||
| 639 | } |
||
| 640 | } |
||
| 641 | } |
||
| 642 | break; |
||
| 643 | default: |
||
| 644 | // get frames |
||
| 645 | if ( |
||
| 646 | ( |
||
| 647 | strpos($value, 'кадры из аниме') !== false || |
||
| 648 | strpos($value, 'Кадры из фильма') !== false |
||
| 649 | ) && $id && $frames |
||
| 650 | ) { |
||
| 651 | foreach ($this->getFrames($id, $type) as $frame) { |
||
| 652 | $item->addImage($frame); |
||
| 653 | } |
||
| 654 | } |
||
| 655 | } |
||
| 656 | } |
||
| 657 | } |
||
| 658 | } |
||
| 659 | |||
| 660 | /** |
||
| 661 | * Upload image from url. |
||
| 662 | * |
||
| 663 | * @param string $url |
||
| 664 | * @param \AnimeDb\Bundle\AppBundle\Service\Downloader\Entity\EntityInterface $entity |
||
| 665 | * |
||
| 666 | * @return bool |
||
| 667 | */ |
||
| 668 | public function uploadImage($url, EntityInterface $entity) |
||
| 669 | { |
||
| 670 | return $this->downloader->image($url, $this->downloader->getRoot().$entity->getWebPath()); |
||
| 671 | } |
||
| 672 | |||
| 673 | /** |
||
| 674 | * Get real country by name. |
||
| 675 | * |
||
| 676 | * @param string $name |
||
| 677 | * |
||
| 678 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Country|null |
||
| 679 | */ |
||
| 680 | private function getCountryByName($name) |
||
| 681 | { |
||
| 682 | $name = str_replace('Южная Корея', 'Республика Корея', $name); |
||
| 683 | $rep = $this->doctrine->getRepository('AnimeDbCatalogBundle:CountryTranslation'); |
||
| 684 | if ($country = $rep->findOneBy(['locale' => 'ru', 'content' => $name])) { |
||
| 685 | return $country->getObject(); |
||
| 686 | } |
||
| 687 | } |
||
| 688 | |||
| 689 | /** |
||
| 690 | * Get real genre by name. |
||
| 691 | * |
||
| 692 | * @param string $name |
||
| 693 | * |
||
| 694 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Genre|null |
||
| 695 | */ |
||
| 696 | private function getGenreByName($name) |
||
| 697 | { |
||
| 698 | if (isset($this->genres[$name])) { |
||
| 699 | return $this->doctrine |
||
| 700 | ->getRepository('AnimeDbCatalogBundle:Genre') |
||
| 701 | ->findOneByName($this->genres[$name]); |
||
| 702 | } |
||
| 703 | } |
||
| 704 | |||
| 705 | /** |
||
| 706 | * Get real type by name. |
||
| 707 | * |
||
| 708 | * @param string $name |
||
| 709 | * |
||
| 710 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Type|null |
||
| 711 | */ |
||
| 712 | private function getTypeByName($name) |
||
| 720 | |||
| 721 | /** |
||
| 722 | * Get item frames. |
||
| 723 | * |
||
| 724 | * @param int $id |
||
| 725 | * @param string $type |
||
| 726 | * |
||
| 727 | * @return array |
||
| 728 | */ |
||
| 729 | public function getFrames($id, $type) |
||
| 762 | |||
| 763 | /** |
||
| 764 | * Get node value as text. |
||
| 765 | * |
||
| 766 | * @param \DOMNode $node |
||
| 767 | * |
||
| 768 | * @return string |
||
| 769 | */ |
||
| 770 | private function getNodeValueAsText(\DOMNode $node) |
||
| 777 | |||
| 778 | /** |
||
| 779 | * Get item studio. |
||
| 780 | * |
||
| 781 | * @param \DOMXPath $xpath |
||
| 782 | * @param \DOMNode $body |
||
| 783 | * |
||
| 784 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Studio|null |
||
| 785 | */ |
||
| 786 | private function getStudio(\DOMXPath $xpath, \DOMNode $body) |
||
| 800 | |||
| 801 | /** |
||
| 802 | * Get item type by URL. |
||
| 803 | * |
||
| 804 | * @param string $url |
||
| 805 | * |
||
| 806 | * @return string |
||
| 807 | */ |
||
| 808 | public function getItemType($url) |
||
| 818 | |||
| 819 | /** |
||
| 820 | * Fill names for Animation type. |
||
| 821 | * |
||
| 822 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
| 823 | * @param \DOMXPath $xpath |
||
| 824 | * @param \DOMElement $head |
||
| 825 | * |
||
| 826 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item |
||
| 827 | */ |
||
| 828 | protected function fillAnimationNames(Item $item, \DOMXPath $xpath, \DOMElement $head) |
||
| 849 | |||
| 850 | /** |
||
| 851 | * Fill names for Cinema type. |
||
| 852 | * |
||
| 853 | * @param \AnimeDb\Bundle\CatalogBundle\Entity\Item $item |
||
| 854 | * @param \DOMXPath $xpath |
||
| 855 | * @param \DOMElement $head |
||
| 856 | * |
||
| 857 | * @return \AnimeDb\Bundle\CatalogBundle\Entity\Item |
||
| 858 | */ |
||
| 859 | protected function fillCinemaNames(Item $item, \DOMXPath $xpath, \DOMElement $head) |
||
| 881 | |||
| 882 | /** |
||
| 883 | * Get cover URL. |
||
| 884 | * |
||
| 885 | * @param string $id |
||
| 886 | * @param string $type |
||
| 887 | * |
||
| 888 | * @return string|null |
||
| 889 | */ |
||
| 890 | public function getCoverUrl($id, $type) |
||
| 901 | |||
| 902 | /** |
||
| 903 | * Is supported URL. |
||
| 904 | * |
||
| 905 | * @param string $url |
||
| 906 | * |
||
| 907 | * @return bool |
||
| 908 | */ |
||
| 909 | public function isSupportedUrl($url) |
||
| 913 | } |
||
| 914 |
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.
Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.