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 Translatable 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 Translatable, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
12 | trait Translatable |
||
13 | { |
||
14 | protected static $autoloadTranslations = null; |
||
15 | |||
16 | protected $defaultLocale; |
||
17 | |||
18 | /** |
||
19 | * Alias for getTranslation(). |
||
20 | * |
||
21 | * @param string|null $locale |
||
22 | * @param bool $withFallback |
||
23 | * |
||
24 | * @return \Illuminate\Database\Eloquent\Model|null |
||
25 | */ |
||
26 | public function translate($locale = null, $withFallback = false) |
||
30 | |||
31 | /** |
||
32 | * Alias for getTranslation(). |
||
33 | * |
||
34 | * @param string $locale |
||
35 | * |
||
36 | * @return \Illuminate\Database\Eloquent\Model|null |
||
37 | */ |
||
38 | public function translateOrDefault($locale = null) |
||
42 | |||
43 | /** |
||
44 | * Alias for getTranslationOrNew(). |
||
45 | * |
||
46 | * @param string $locale |
||
47 | * |
||
48 | * @return \Illuminate\Database\Eloquent\Model|null |
||
49 | */ |
||
50 | public function translateOrNew($locale = null) |
||
54 | |||
55 | /** |
||
56 | * @param string|null $locale |
||
57 | * @param bool $withFallback |
||
58 | * |
||
59 | * @return \Illuminate\Database\Eloquent\Model|null |
||
60 | */ |
||
61 | public function getTranslation($locale = null, $withFallback = null) |
||
82 | |||
83 | /** |
||
84 | * @param string|null $locale |
||
85 | * |
||
86 | * @return bool |
||
87 | */ |
||
88 | public function hasTranslation($locale = null) |
||
100 | |||
101 | /** |
||
102 | * @return string |
||
103 | */ |
||
104 | public function getTranslationModelName() |
||
108 | |||
109 | /** |
||
110 | * @return string |
||
111 | */ |
||
112 | public function getTranslationModelNameDefault() |
||
122 | |||
123 | /** |
||
124 | * @return string|null |
||
125 | */ |
||
126 | public function getTranslationModelNamespace() |
||
130 | |||
131 | /** |
||
132 | * @return string |
||
133 | */ |
||
134 | public function getRelationKey() |
||
146 | |||
147 | /** |
||
148 | * @return string |
||
149 | */ |
||
150 | public function getLocaleKey() |
||
154 | |||
155 | /** |
||
156 | * @return \Illuminate\Database\Eloquent\Relations\HasMany |
||
157 | */ |
||
158 | public function translations() |
||
162 | |||
163 | /** |
||
164 | * @return bool |
||
165 | */ |
||
166 | private function usePropertyFallback() |
||
170 | |||
171 | /** |
||
172 | * Returns the attribute value from fallback translation if value of attribute |
||
173 | * is empty and the property fallback is enabled in the configuration. |
||
174 | * in model. |
||
175 | * @param $locale |
||
176 | * @param $attribute |
||
177 | * @return mixed |
||
178 | */ |
||
179 | private function getAttributeOrFallback($locale, $attribute) |
||
199 | |||
200 | /** |
||
201 | * @param string $key |
||
202 | * |
||
203 | * @return mixed |
||
204 | */ |
||
205 | public function getAttribute($key) |
||
228 | |||
229 | /** |
||
230 | * @param string $key |
||
231 | * @param mixed $value |
||
232 | * |
||
233 | * @return $this |
||
234 | */ |
||
235 | public function setAttribute($key, $value) |
||
247 | |||
248 | /** |
||
249 | * @param array $options |
||
250 | * |
||
251 | * @return bool |
||
252 | */ |
||
253 | public function save(array $options = []) |
||
285 | |||
286 | /** |
||
287 | * @param string $locale |
||
288 | * |
||
289 | * @return \Illuminate\Database\Eloquent\Model |
||
290 | */ |
||
291 | protected function getTranslationOrNew($locale = null) |
||
301 | |||
302 | /** |
||
303 | * @param array $attributes |
||
304 | * |
||
305 | * @throws \Illuminate\Database\Eloquent\MassAssignmentException |
||
306 | * @return $this |
||
307 | */ |
||
308 | public function fill(array $attributes) |
||
325 | |||
326 | /** |
||
327 | * @param string $key |
||
328 | */ |
||
329 | private function getTranslationByLocaleKey($key) |
||
339 | |||
340 | /** |
||
341 | * @param null $locale |
||
342 | * |
||
343 | * @return string |
||
344 | */ |
||
345 | private function getFallbackLocale($locale = null) |
||
355 | |||
356 | /** |
||
357 | * @param $locale |
||
358 | * |
||
359 | * @return bool |
||
360 | */ |
||
361 | private function isLocaleCountryBased($locale) |
||
365 | |||
366 | /** |
||
367 | * @param $locale |
||
368 | * |
||
369 | * @return string |
||
370 | */ |
||
371 | private function getLanguageFromCountryBasedLocale($locale) |
||
377 | |||
378 | /** |
||
379 | * @return bool|null |
||
380 | */ |
||
381 | private function useFallback() |
||
389 | |||
390 | /** |
||
391 | * @param string $key |
||
392 | * |
||
393 | * @return bool |
||
394 | */ |
||
395 | public function isTranslationAttribute($key) |
||
399 | |||
400 | /** |
||
401 | * @param string $key |
||
402 | * |
||
403 | * @throws \Dimsav\Translatable\Exception\LocalesNotDefinedException |
||
404 | * @return bool |
||
405 | */ |
||
406 | protected function isKeyALocale($key) |
||
412 | |||
413 | /** |
||
414 | * @throws \Dimsav\Translatable\Exception\LocalesNotDefinedException |
||
415 | * @return array |
||
416 | */ |
||
417 | protected function getLocales() |
||
440 | |||
441 | /** |
||
442 | * @return string |
||
443 | */ |
||
444 | protected function getLocaleSeparator() |
||
448 | |||
449 | /** |
||
450 | * @return bool |
||
451 | */ |
||
452 | protected function saveTranslations() |
||
468 | |||
469 | /** |
||
470 | * @param array |
||
471 | * |
||
472 | * @return \Illuminate\Database\Eloquent\Model |
||
473 | */ |
||
474 | public function replicateWithTranslations(array $except = null) |
||
486 | |||
487 | /** |
||
488 | * @param \Illuminate\Database\Eloquent\Model $translation |
||
489 | * |
||
490 | * @return bool |
||
491 | */ |
||
492 | protected function isTranslationDirty(Model $translation) |
||
499 | |||
500 | /** |
||
501 | * @param string $locale |
||
502 | * |
||
503 | * @return \Illuminate\Database\Eloquent\Model |
||
504 | */ |
||
505 | public function getNewTranslation($locale) |
||
514 | |||
515 | /** |
||
516 | * @param $key |
||
517 | * |
||
518 | * @return bool |
||
519 | */ |
||
520 | public function __isset($key) |
||
524 | |||
525 | /** |
||
526 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
527 | * @param string $locale |
||
528 | * |
||
529 | * @return \Illuminate\Database\Eloquent\Builder|static |
||
530 | */ |
||
531 | View Code Duplication | public function scopeTranslatedIn(Builder $query, $locale = null) |
|
539 | |||
540 | /** |
||
541 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
542 | * @param string $locale |
||
543 | * |
||
544 | * @return \Illuminate\Database\Eloquent\Builder|static |
||
545 | */ |
||
546 | View Code Duplication | public function scopeNotTranslatedIn(Builder $query, $locale = null) |
|
554 | |||
555 | /** |
||
556 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
557 | * |
||
558 | * @return \Illuminate\Database\Eloquent\Builder|static |
||
559 | */ |
||
560 | public function scopeTranslated(Builder $query) |
||
564 | |||
565 | /** |
||
566 | * Adds scope to get a list of translated attributes, using the current locale. |
||
567 | * Example usage: Country::listsTranslations('name')->get()->toArray() |
||
568 | * Will return an array with items: |
||
569 | * [ |
||
570 | * 'id' => '1', // The id of country |
||
571 | * 'name' => 'Griechenland' // The translated name |
||
572 | * ]. |
||
573 | * |
||
574 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
575 | * @param string $translationField |
||
576 | */ |
||
577 | public function scopeListsTranslations(Builder $query, $translationField) |
||
601 | |||
602 | /** |
||
603 | * This scope eager loads the translations for the default and the fallback locale only. |
||
604 | * We can use this as a shortcut to improve performance in our application. |
||
605 | * |
||
606 | * @param Builder $query |
||
607 | */ |
||
608 | public function scopeWithTranslation(Builder $query) |
||
624 | |||
625 | /** |
||
626 | * This scope filters results by checking the translation fields. |
||
627 | * |
||
628 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
629 | * @param string $key |
||
630 | * @param string $value |
||
631 | * @param string $locale |
||
632 | * |
||
633 | * @return \Illuminate\Database\Eloquent\Builder|static |
||
634 | */ |
||
635 | View Code Duplication | public function scopeWhereTranslation(Builder $query, $key, $value, $locale = null) |
|
644 | |||
645 | /** |
||
646 | * This scope filters results by checking the translation fields. |
||
647 | * |
||
648 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
649 | * @param string $key |
||
650 | * @param string $value |
||
651 | * @param string $locale |
||
652 | * |
||
653 | * @return \Illuminate\Database\Eloquent\Builder|static |
||
654 | */ |
||
655 | View Code Duplication | public function scopeOrWhereTranslation(Builder $query, $key, $value, $locale = null) |
|
664 | |||
665 | /** |
||
666 | * This scope filters results by checking the translation fields. |
||
667 | * |
||
668 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
669 | * @param string $key |
||
670 | * @param string $value |
||
671 | * @param string $locale |
||
672 | * |
||
673 | * @return \Illuminate\Database\Eloquent\Builder|static |
||
674 | */ |
||
675 | View Code Duplication | public function scopeWhereTranslationLike(Builder $query, $key, $value, $locale = null) |
|
684 | |||
685 | /** |
||
686 | * This scope filters results by checking the translation fields. |
||
687 | * |
||
688 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
689 | * @param string $key |
||
690 | * @param string $value |
||
691 | * @param string $locale |
||
692 | * |
||
693 | * @return \Illuminate\Database\Eloquent\Builder|static |
||
694 | */ |
||
695 | View Code Duplication | public function scopeOrWhereTranslationLike(Builder $query, $key, $value, $locale = null) |
|
704 | |||
705 | /** |
||
706 | * This scope sorts results by the given translation field. |
||
707 | * |
||
708 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
709 | * @param string $key |
||
710 | * @param string $sortmethod |
||
711 | * |
||
712 | * @return \Illuminate\Database\Eloquent\Builder|static |
||
713 | */ |
||
714 | public function scopeOrderByTranslation(Builder $query, $key, $sortmethod = 'asc') |
||
731 | |||
732 | /** |
||
733 | * @return array |
||
734 | */ |
||
735 | public function attributesToArray() |
||
758 | |||
759 | /** |
||
760 | * @return array |
||
761 | */ |
||
762 | public function getTranslationsArray() |
||
774 | |||
775 | /** |
||
776 | * @return string |
||
777 | */ |
||
778 | private function getTranslationsTable() |
||
782 | |||
783 | /** |
||
784 | * @return string |
||
785 | */ |
||
786 | protected function locale() |
||
795 | |||
796 | /** |
||
797 | * Set the default locale on the model. |
||
798 | * |
||
799 | * @param $locale |
||
800 | * |
||
801 | * @return $this |
||
802 | */ |
||
803 | public function setDefaultLocale($locale) |
||
809 | |||
810 | /** |
||
811 | * Get the default locale on the model. |
||
812 | * |
||
813 | * @return mixed |
||
814 | */ |
||
815 | public function getDefaultLocale() |
||
819 | |||
820 | /** |
||
821 | * Deletes all translations for this model. |
||
822 | * |
||
823 | * @param string|array|null $locales The locales to be deleted (array or single string) |
||
824 | * (e.g., ["en", "de"] would remove these translations). |
||
825 | */ |
||
826 | public function deleteTranslations($locales = null) |
||
842 | |||
843 | /** |
||
844 | * @param $key |
||
845 | * |
||
846 | * @return array |
||
847 | */ |
||
848 | private function getAttributeAndLocale($key) |
||
856 | |||
857 | /** |
||
858 | * @return bool |
||
859 | */ |
||
860 | private function toArrayAlwaysLoadsTranslations() |
||
864 | |||
865 | public static function enableAutoloadTranslations() |
||
869 | |||
870 | public static function defaultAutoloadTranslations() |
||
874 | |||
875 | public static function disableAutoloadTranslations() |
||
879 | } |
||
880 |
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.
If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.