Complex classes like Article 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 Article, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 31 | class Article implements ArticleInterface |
||
| 32 | { |
||
| 33 | use TranslatableTrait; |
||
| 34 | use SoftDeletableTrait; |
||
| 35 | use TimestampableTrait; |
||
| 36 | use AuthorsAwareTrait; |
||
| 37 | use KeywordsAwareTrait; |
||
| 38 | use RelatedArticlesAwareTrait; |
||
| 39 | use TimestampableCancelTrait; |
||
| 40 | use SeoMetadataAwareTrait; |
||
| 41 | use MediaAwareTrait; |
||
| 42 | |||
| 43 | /** |
||
| 44 | * @var mixed |
||
| 45 | */ |
||
| 46 | protected $id; |
||
| 47 | |||
| 48 | /** |
||
| 49 | * @var string |
||
| 50 | */ |
||
| 51 | protected $title; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * @var string |
||
| 55 | */ |
||
| 56 | protected $body; |
||
| 57 | |||
| 58 | /** |
||
| 59 | * @var string |
||
| 60 | */ |
||
| 61 | protected $slug; |
||
| 62 | |||
| 63 | /** |
||
| 64 | * @var \DateTime |
||
| 65 | */ |
||
| 66 | protected $publishedAt; |
||
| 67 | |||
| 68 | /** |
||
| 69 | * @var string |
||
| 70 | */ |
||
| 71 | protected $status = ArticleInterface::STATUS_NEW; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * @var RouteInterface |
||
| 75 | */ |
||
| 76 | protected $route; |
||
| 77 | |||
| 78 | /** |
||
| 79 | * @var string |
||
| 80 | */ |
||
| 81 | protected $templateName; |
||
| 82 | |||
| 83 | /** |
||
| 84 | * @var \DateTime |
||
| 85 | */ |
||
| 86 | protected $publishStartDate; |
||
| 87 | |||
| 88 | /** |
||
| 89 | * @var \DateTime |
||
| 90 | */ |
||
| 91 | protected $publishEndDate; |
||
| 92 | |||
| 93 | /** |
||
| 94 | * @var bool |
||
| 95 | */ |
||
| 96 | protected $isPublishable; |
||
| 97 | |||
| 98 | /** |
||
| 99 | * @var array |
||
| 100 | */ |
||
| 101 | protected $metadata = []; |
||
| 102 | |||
| 103 | /** |
||
| 104 | * @var string |
||
| 105 | */ |
||
| 106 | protected $lead; |
||
| 107 | |||
| 108 | /** |
||
| 109 | * @var string |
||
| 110 | */ |
||
| 111 | protected $code; |
||
| 112 | |||
| 113 | /** |
||
| 114 | * @var Collection|ArticleSourceInterface[] |
||
| 115 | */ |
||
| 116 | protected $sources; |
||
| 117 | |||
| 118 | /** |
||
| 119 | * @var array|null |
||
| 120 | */ |
||
| 121 | protected $extra; |
||
| 122 | |||
| 123 | /** |
||
| 124 | * @var Collection|SlideshowInterface[] |
||
| 125 | */ |
||
| 126 | protected $slideshows; |
||
| 127 | |||
| 128 | /** @var Collection|ArticlePreviousRelativeUrlInterface[] * */ |
||
| 129 | protected $previousRelativeUrls; |
||
| 130 | |||
| 131 | public function __construct() |
||
| 132 | { |
||
| 133 | $this->createdAt = DateTime::getCurrentDateTime(); |
||
| 134 | $this->setPublishable(false); |
||
| 135 | $this->setMedia(new ArrayCollection()); |
||
| 136 | $this->sources = new ArrayCollection(); |
||
| 137 | $this->authors = new ArrayCollection(); |
||
| 138 | $this->keywords = new ArrayCollection(); |
||
| 139 | $this->slideshows = new ArrayCollection(); |
||
| 140 | $this->relatedArticles = new ArrayCollection(); |
||
| 141 | $this->previousRelativeUrls = new ArrayCollection(); |
||
| 142 | } |
||
| 143 | |||
| 144 | public function setPublishStartDate(\DateTime $startDate = null) |
||
| 148 | |||
| 149 | public function getPublishStartDate() |
||
| 150 | { |
||
| 151 | return $this->publishStartDate; |
||
| 152 | } |
||
| 153 | |||
| 154 | public function setPublishEndDate(\DateTime $endDate = null) |
||
| 155 | { |
||
| 156 | $this->publishEndDate = $endDate; |
||
| 157 | } |
||
| 158 | |||
| 159 | public function getPublishEndDate() |
||
| 160 | { |
||
| 161 | return $this->publishEndDate; |
||
| 162 | } |
||
| 163 | |||
| 164 | public function isPublishable() |
||
| 165 | { |
||
| 166 | return $this->isPublishable; |
||
| 167 | } |
||
| 168 | |||
| 169 | public function setPublishable($boolean) |
||
| 170 | { |
||
| 171 | $this->isPublishable = $boolean; |
||
| 172 | } |
||
| 173 | |||
| 174 | public function setIsPublishable(bool $boolean): void |
||
| 175 | { |
||
| 176 | $this->setPublishable($boolean); |
||
| 177 | } |
||
| 178 | |||
| 179 | public function isPublished() |
||
| 180 | { |
||
| 181 | return ArticleInterface::STATUS_PUBLISHED === $this->getStatus(); |
||
| 182 | } |
||
| 183 | |||
| 184 | public function setRoute(RouteInterface $route = null) |
||
| 185 | { |
||
| 186 | $this->route = $route; |
||
| 187 | } |
||
| 188 | |||
| 189 | public function getRoute() |
||
| 190 | { |
||
| 191 | return $this->route; |
||
| 192 | } |
||
| 193 | |||
| 194 | public function getId() |
||
| 195 | { |
||
| 196 | return $this->id; |
||
| 197 | } |
||
| 198 | |||
| 199 | public function getBody() |
||
| 200 | { |
||
| 201 | return $this->body; |
||
| 202 | } |
||
| 203 | |||
| 204 | public function setBody($body) |
||
| 205 | { |
||
| 206 | $this->body = \trim($body); |
||
| 207 | } |
||
| 208 | |||
| 209 | public function getTitle() |
||
| 210 | { |
||
| 211 | return $this->title; |
||
| 212 | } |
||
| 213 | |||
| 214 | public function getPlace(): ?array |
||
| 215 | { |
||
| 216 | $metadata = $this->getMetadata(); |
||
| 217 | |||
| 218 | if (isset($metadata['place']) && is_array($metadata['place']) && count($metadata['place']) > 0) { |
||
| 219 | return $metadata['place'][array_key_first($metadata['place'])]; |
||
| 220 | } |
||
| 221 | |||
| 222 | return null; |
||
| 223 | } |
||
| 224 | |||
| 225 | public function getPlaces(): array |
||
| 226 | { |
||
| 227 | $metadata = $this->getMetadata(); |
||
| 228 | |||
| 229 | if (isset($metadata['place']) && is_array($metadata['place']) && count($metadata['place']) > 0) { |
||
| 230 | return $metadata['place']; |
||
| 231 | } |
||
| 232 | |||
| 233 | return []; |
||
| 234 | } |
||
| 235 | |||
| 236 | public function setTitle($title) |
||
| 237 | { |
||
| 238 | $this->title = $title; |
||
| 239 | |||
| 240 | if (null !== $this->slug && '' !== $this->slug) { |
||
| 241 | $this->setSlug($this->slug); |
||
| 242 | |||
| 243 | return; |
||
| 244 | } |
||
| 245 | |||
| 246 | $this->setSlug($this->title); |
||
| 247 | } |
||
| 248 | |||
| 249 | public function getSlug() |
||
| 250 | { |
||
| 251 | return $this->slug; |
||
| 252 | } |
||
| 253 | |||
| 254 | public function setSlug($slug) |
||
| 255 | { |
||
| 256 | $urlizedSlug = Transliterator::urlize($slug); |
||
| 257 | |||
| 258 | if ('' === $urlizedSlug) { |
||
| 259 | $slug = str_replace('\'', '-', $slug); |
||
| 260 | $this->slug = Transliterator::transliterate($slug); |
||
| 261 | |||
| 262 | return; |
||
| 263 | } |
||
| 264 | |||
| 265 | $this->slug = $urlizedSlug; |
||
| 266 | } |
||
| 267 | |||
| 268 | public function getPublishedAt() |
||
| 269 | { |
||
| 270 | return $this->publishedAt; |
||
| 271 | } |
||
| 272 | |||
| 273 | public function setPublishedAt(\DateTime $publishedAt) |
||
| 274 | { |
||
| 275 | $this->publishedAt = $publishedAt; |
||
| 276 | } |
||
| 277 | |||
| 278 | public function getStatus() |
||
| 279 | { |
||
| 280 | return $this->status; |
||
| 281 | } |
||
| 282 | |||
| 283 | public function setStatus($status) |
||
| 284 | { |
||
| 285 | $this->status = $status; |
||
| 286 | } |
||
| 287 | |||
| 288 | public function getTemplateName() |
||
| 289 | { |
||
| 290 | return $this->templateName; |
||
| 291 | } |
||
| 292 | |||
| 293 | public function setTemplateName($templateName) |
||
| 294 | { |
||
| 295 | $this->templateName = $templateName; |
||
| 296 | } |
||
| 297 | |||
| 298 | public function getMetadata() |
||
| 299 | { |
||
| 300 | return $this->metadata; |
||
| 301 | } |
||
| 302 | |||
| 303 | public function getMetadataByKey(string $key) |
||
| 304 | { |
||
| 305 | $metadata = $this->getMetadata(); |
||
| 306 | |||
| 307 | if (isset($metadata[$key])) { |
||
| 308 | return $metadata[$key]; |
||
| 309 | } |
||
| 310 | } |
||
| 311 | |||
| 312 | public function setMetadata(array $metadata) |
||
| 313 | { |
||
| 314 | $this->metadata = ArrayHelper::sortNestedArrayAssocAlphabeticallyByKey($metadata); |
||
| 315 | } |
||
| 316 | |||
| 317 | public function getSubjectType() |
||
| 318 | { |
||
| 319 | return 'article'; |
||
| 320 | } |
||
| 321 | |||
| 322 | public function getLead() |
||
| 323 | { |
||
| 324 | return $this->lead; |
||
| 325 | } |
||
| 326 | |||
| 327 | public function setLead($lead) |
||
| 328 | { |
||
| 329 | $this->lead = $lead; |
||
| 330 | } |
||
| 331 | |||
| 332 | public function getCode(): string |
||
| 336 | |||
| 337 | public function setCode(string $code) |
||
| 341 | |||
| 342 | public function addSourceReference(ArticleSourceReferenceInterface $source) |
||
| 348 | |||
| 349 | public function removeSourceReference(ArticleSourceReferenceInterface $source) |
||
| 353 | |||
| 354 | public function hasSourceReference(ArticleSourceReferenceInterface $source): bool |
||
| 358 | |||
| 359 | public function getSources(): Collection |
||
| 373 | |||
| 374 | public function getExtra(): ?array |
||
| 378 | |||
| 379 | public function setExtra(?array $extra): void |
||
| 383 | |||
| 384 | public function getSlideshows(): Collection |
||
| 388 | |||
| 389 | public function hasSlideshow(SlideshowInterface $slideshow): bool |
||
| 393 | |||
| 394 | public function addSlideshow(SlideshowInterface $slideshow): void |
||
| 401 | |||
| 402 | public function removeSlideshow(SlideshowInterface $slideshow): void |
||
| 409 | |||
| 410 | public function getPreviousRelativeUrl(): Collection |
||
| 411 | { |
||
| 412 | return $this->previousRelativeUrls; |
||
| 413 | } |
||
| 414 | |||
| 415 | public function hasPreviousRelativeUrl(ArticlePreviousRelativeUrlInterface $previousRelativeUrl): bool |
||
| 416 | { |
||
| 417 | return $this->previousRelativeUrls->contains($previousRelativeUrl); |
||
| 418 | } |
||
| 419 | |||
| 420 | public function addPreviousRelativeUrl(ArticlePreviousRelativeUrlInterface $previousRelativeUrl): void |
||
| 421 | { |
||
| 422 | if (!$this->hasPreviousRelativeUrl($previousRelativeUrl)) { |
||
| 423 | $previousRelativeUrl->setArticle($this); |
||
| 424 | $this->previousRelativeUrls->add($previousRelativeUrl); |
||
| 425 | } |
||
| 426 | } |
||
| 427 | |||
| 428 | public function removePreviousRelativeUrl(ArticlePreviousRelativeUrlInterface $previousRelativeUrl): void |
||
| 429 | { |
||
| 430 | if ($this->hasPreviousRelativeUrl($previousRelativeUrl)) { |
||
| 431 | $previousRelativeUrl->setArticle(null); |
||
| 432 | $this->previousRelativeUrls->removeElement($previousRelativeUrl); |
||
| 433 | } |
||
| 434 | } |
||
| 435 | } |
||
| 436 |