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 BelongsToMany 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 BelongsToMany, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
34 | class BelongsToMany extends Association |
||
35 | { |
||
36 | |||
37 | use ExternalAssociationTrait { |
||
38 | _options as _externalOptions; |
||
39 | _buildQuery as _buildBaseQuery; |
||
40 | } |
||
41 | |||
42 | /** |
||
43 | * Saving strategy that will only append to the links set |
||
44 | * |
||
45 | * @var string |
||
46 | */ |
||
47 | const SAVE_APPEND = 'append'; |
||
48 | |||
49 | /** |
||
50 | * Saving strategy that will replace the links with the provided set |
||
51 | * |
||
52 | * @var string |
||
53 | */ |
||
54 | const SAVE_REPLACE = 'replace'; |
||
55 | |||
56 | /** |
||
57 | * The type of join to be used when adding the association to a query |
||
58 | * |
||
59 | * @var string |
||
60 | */ |
||
61 | protected $_joinType = 'INNER'; |
||
62 | |||
63 | /** |
||
64 | * The strategy name to be used to fetch associated records. |
||
65 | * |
||
66 | * @var string |
||
67 | */ |
||
68 | protected $_strategy = self::STRATEGY_SELECT; |
||
69 | |||
70 | /** |
||
71 | * Junction table instance |
||
72 | * |
||
73 | * @var \Cake\ORM\Table |
||
74 | */ |
||
75 | protected $_junctionTable; |
||
76 | |||
77 | /** |
||
78 | * Junction table name |
||
79 | * |
||
80 | * @var string |
||
81 | */ |
||
82 | protected $_junctionTableName; |
||
83 | |||
84 | /** |
||
85 | * The name of the hasMany association from the target table |
||
86 | * to the junction table |
||
87 | * |
||
88 | * @var string |
||
89 | */ |
||
90 | protected $_junctionAssociationName; |
||
91 | |||
92 | /** |
||
93 | * The name of the property to be set containing data from the junction table |
||
94 | * once a record from the target table is hydrated |
||
95 | * |
||
96 | * @var string |
||
97 | */ |
||
98 | protected $_junctionProperty = '_joinData'; |
||
99 | |||
100 | /** |
||
101 | * Saving strategy to be used by this association |
||
102 | * |
||
103 | * @var string |
||
104 | */ |
||
105 | protected $_saveStrategy = self::SAVE_REPLACE; |
||
106 | |||
107 | /** |
||
108 | * The name of the field representing the foreign key to the target table |
||
109 | * |
||
110 | * @var string|array |
||
111 | */ |
||
112 | protected $_targetForeignKey; |
||
113 | |||
114 | /** |
||
115 | * The table instance for the junction relation. |
||
116 | * |
||
117 | * @var string|\Cake\ORM\Table |
||
118 | */ |
||
119 | protected $_through; |
||
120 | |||
121 | /** |
||
122 | * Valid strategies for this type of association |
||
123 | * |
||
124 | * @var array |
||
125 | */ |
||
126 | protected $_validStrategies = [self::STRATEGY_SELECT, self::STRATEGY_SUBQUERY]; |
||
127 | |||
128 | /** |
||
129 | * Whether the records on the joint table should be removed when a record |
||
130 | * on the source table is deleted. |
||
131 | * |
||
132 | * Defaults to true for backwards compatibility. |
||
133 | * |
||
134 | * @var bool |
||
135 | */ |
||
136 | protected $_dependent = true; |
||
137 | |||
138 | /** |
||
139 | * Filtered conditions that reference the target table. |
||
140 | * |
||
141 | * @var null|array |
||
142 | */ |
||
143 | protected $_targetConditions; |
||
144 | |||
145 | /** |
||
146 | * Filtered conditions that reference the junction table. |
||
147 | * |
||
148 | * @var null|array |
||
149 | */ |
||
150 | protected $_junctionConditions; |
||
151 | |||
152 | /** |
||
153 | * Sets the name of the field representing the foreign key to the target table. |
||
154 | * If no parameters are passed current field is returned |
||
155 | * |
||
156 | * @param string|null $key the key to be used to link both tables together |
||
157 | * @return string |
||
158 | */ |
||
159 | View Code Duplication | public function targetForeignKey($key = null) |
|
169 | |||
170 | /** |
||
171 | * Sets the table instance for the junction relation. If no arguments |
||
172 | * are passed, the current configured table instance is returned |
||
173 | * |
||
174 | * @param string|\Cake\ORM\Table|null $table Name or instance for the join table |
||
175 | * @return \Cake\ORM\Table |
||
176 | */ |
||
177 | public function junction($table = null) |
||
211 | |||
212 | /** |
||
213 | * Generate reciprocal associations as necessary. |
||
214 | * |
||
215 | * Generates the following associations: |
||
216 | * |
||
217 | * - target hasMany junction e.g. Articles hasMany ArticlesTags |
||
218 | * - target belongsToMany source e.g Articles belongsToMany Tags. |
||
219 | * |
||
220 | * You can override these generated associations by defining associations |
||
221 | * with the correct aliases. |
||
222 | * |
||
223 | * @param \Cake\ORM\Table $junction The junction table. |
||
224 | * @param \Cake\ORM\Table $source The source table. |
||
225 | * @param \Cake\ORM\Table $target The target table. |
||
226 | * @return void |
||
227 | */ |
||
228 | protected function _generateTargetAssociations($junction, $source, $target) |
||
250 | |||
251 | /** |
||
252 | * Generate additional source table associations as necessary. |
||
253 | * |
||
254 | * Generates the following associations: |
||
255 | * |
||
256 | * - source hasMany junction e.g. Tags hasMany ArticlesTags |
||
257 | * |
||
258 | * You can override these generated associations by defining associations |
||
259 | * with the correct aliases. |
||
260 | * |
||
261 | * @param \Cake\ORM\Table $junction The junction table. |
||
262 | * @param \Cake\ORM\Table $source The source table. |
||
263 | * @return void |
||
264 | */ |
||
265 | protected function _generateSourceAssociations($junction, $source) |
||
275 | |||
276 | /** |
||
277 | * Generate associations on the junction table as necessary |
||
278 | * |
||
279 | * Generates the following associations: |
||
280 | * |
||
281 | * - junction belongsTo source e.g. ArticlesTags belongsTo Tags |
||
282 | * - junction belongsTo target e.g. ArticlesTags belongsTo Articles |
||
283 | * |
||
284 | * You can override these generated associations by defining associations |
||
285 | * with the correct aliases. |
||
286 | * |
||
287 | * @param \Cake\ORM\Table $junction The junction table. |
||
288 | * @param \Cake\ORM\Table $source The source table. |
||
289 | * @param \Cake\ORM\Table $target The target table. |
||
290 | * @return void |
||
291 | */ |
||
292 | protected function _generateJunctionAssociations($junction, $source, $target) |
||
310 | |||
311 | /** |
||
312 | * Alters a Query object to include the associated target table data in the final |
||
313 | * result |
||
314 | * |
||
315 | * The options array accept the following keys: |
||
316 | * |
||
317 | * - includeFields: Whether to include target model fields in the result or not |
||
318 | * - foreignKey: The name of the field to use as foreign key, if false none |
||
319 | * will be used |
||
320 | * - conditions: array with a list of conditions to filter the join with |
||
321 | * - fields: a list of fields in the target table to include in the result |
||
322 | * - type: The type of join to be used (e.g. INNER) |
||
323 | * |
||
324 | * @param Query $query the query to be altered to include the target table data |
||
325 | * @param array $options Any extra options or overrides to be taken in account |
||
326 | * @return void |
||
327 | */ |
||
328 | public function attachTo(Query $query, array $options = []) |
||
353 | |||
354 | /** |
||
355 | * {@inheritDoc} |
||
356 | */ |
||
357 | protected function _appendNotMatching($query, $options) |
||
368 | |||
369 | /** |
||
370 | * {@inheritDoc} |
||
371 | */ |
||
372 | public function transformRow($row, $nestKey, $joined) |
||
382 | |||
383 | /** |
||
384 | * Get the relationship type. |
||
385 | * |
||
386 | * @return string |
||
387 | */ |
||
388 | public function type() |
||
392 | |||
393 | /** |
||
394 | * Return false as join conditions are defined in the junction table |
||
395 | * |
||
396 | * @param array $options list of options passed to attachTo method |
||
397 | * @return bool false |
||
398 | */ |
||
399 | protected function _joinCondition($options) |
||
403 | |||
404 | /** |
||
405 | * Builds an array containing the results from fetchQuery indexed by |
||
406 | * the foreignKey value corresponding to this association. |
||
407 | * |
||
408 | * @param \Cake\ORM\Query $fetchQuery The query to get results from |
||
409 | * @param array $options The options passed to the eager loader |
||
410 | * @return array |
||
411 | * @throws \RuntimeException when the association property is not part of the results set. |
||
412 | */ |
||
413 | protected function _buildResultMap($fetchQuery, $options) |
||
442 | |||
443 | /** |
||
444 | * Clear out the data in the junction table for a given entity. |
||
445 | * |
||
446 | * @param \Cake\Datasource\EntityInterface $entity The entity that started the cascading delete. |
||
447 | * @param array $options The options for the original delete. |
||
448 | * @return bool Success. |
||
449 | */ |
||
450 | public function cascadeDelete(EntityInterface $entity, array $options = []) |
||
475 | |||
476 | /** |
||
477 | * Returns boolean true, as both of the tables 'own' rows in the other side |
||
478 | * of the association via the joint table. |
||
479 | * |
||
480 | * @param \Cake\ORM\Table $side The potential Table with ownership |
||
481 | * @return bool |
||
482 | */ |
||
483 | public function isOwningSide(Table $side) |
||
487 | |||
488 | /** |
||
489 | * Sets the strategy that should be used for saving. If called with no |
||
490 | * arguments, it will return the currently configured strategy |
||
491 | * |
||
492 | * @param string|null $strategy the strategy name to be used |
||
493 | * @throws \InvalidArgumentException if an invalid strategy name is passed |
||
494 | * @return string the strategy to be used for saving |
||
495 | */ |
||
496 | View Code Duplication | public function saveStrategy($strategy = null) |
|
507 | |||
508 | /** |
||
509 | * Takes an entity from the source table and looks if there is a field |
||
510 | * matching the property name for this association. The found entity will be |
||
511 | * saved on the target table for this association by passing supplied |
||
512 | * `$options` |
||
513 | * |
||
514 | * When using the 'append' strategy, this function will only create new links |
||
515 | * between each side of this association. It will not destroy existing ones even |
||
516 | * though they may not be present in the array of entities to be saved. |
||
517 | * |
||
518 | * When using the 'replace' strategy, existing links will be removed and new links |
||
519 | * will be created in the joint table. If there exists links in the database to some |
||
520 | * of the entities intended to be saved by this method, they will be updated, |
||
521 | * not deleted. |
||
522 | * |
||
523 | * @param \Cake\Datasource\EntityInterface $entity an entity from the source table |
||
524 | * @param array|\ArrayObject $options options to be passed to the save method in |
||
525 | * the target table |
||
526 | * @throws \InvalidArgumentException if the property representing the association |
||
527 | * in the parent entity cannot be traversed |
||
528 | * @return bool|\Cake\Datasource\EntityInterface false if $entity could not be saved, otherwise it returns |
||
529 | * the saved entity |
||
530 | * @see Table::save() |
||
531 | * @see BelongsToMany::replaceLinks() |
||
532 | */ |
||
533 | public function saveAssociated(EntityInterface $entity, array $options = []) |
||
556 | |||
557 | /** |
||
558 | * Persists each of the entities into the target table and creates links between |
||
559 | * the parent entity and each one of the saved target entities. |
||
560 | * |
||
561 | * @param \Cake\Datasource\EntityInterface $parentEntity the source entity containing the target |
||
562 | * entities to be saved. |
||
563 | * @param array|\Traversable $entities list of entities to persist in target table and to |
||
564 | * link to the parent entity |
||
565 | * @param array $options list of options accepted by `Table::save()` |
||
566 | * @throws \InvalidArgumentException if the property representing the association |
||
567 | * in the parent entity cannot be traversed |
||
568 | * @return \Cake\Datasource\EntityInterface|bool The parent entity after all links have been |
||
569 | * created if no errors happened, false otherwise |
||
570 | */ |
||
571 | protected function _saveTarget(EntityInterface $parentEntity, $entities, $options) |
||
620 | |||
621 | /** |
||
622 | * Creates links between the source entity and each of the passed target entities |
||
623 | * |
||
624 | * @param \Cake\Datasource\EntityInterface $sourceEntity the entity from source table in this |
||
625 | * association |
||
626 | * @param array $targetEntities list of entities to link to link to the source entity using the |
||
627 | * junction table |
||
628 | * @param array $options list of options accepted by `Table::save()` |
||
629 | * @return bool success |
||
630 | */ |
||
631 | protected function _saveLinks(EntityInterface $sourceEntity, $targetEntities, $options) |
||
672 | |||
673 | /** |
||
674 | * Associates the source entity to each of the target entities provided by |
||
675 | * creating links in the junction table. Both the source entity and each of |
||
676 | * the target entities are assumed to be already persisted, if the are marked |
||
677 | * as new or their status is unknown, an exception will be thrown. |
||
678 | * |
||
679 | * When using this method, all entities in `$targetEntities` will be appended to |
||
680 | * the source entity's property corresponding to this association object. |
||
681 | * |
||
682 | * This method does not check link uniqueness. |
||
683 | * |
||
684 | * ### Example: |
||
685 | * |
||
686 | * ``` |
||
687 | * $newTags = $tags->find('relevant')->execute(); |
||
688 | * $articles->association('tags')->link($article, $newTags); |
||
689 | * ``` |
||
690 | * |
||
691 | * `$article->get('tags')` will contain all tags in `$newTags` after liking |
||
692 | * |
||
693 | * @param \Cake\Datasource\EntityInterface $sourceEntity the row belonging to the `source` side |
||
694 | * of this association |
||
695 | * @param array $targetEntities list of entities belonging to the `target` side |
||
696 | * of this association |
||
697 | * @param array $options list of options to be passed to the internal `save` call |
||
698 | * @throws \InvalidArgumentException when any of the values in $targetEntities is |
||
699 | * detected to not be already persisted |
||
700 | * @return bool true on success, false otherwise |
||
701 | */ |
||
702 | public function link(EntityInterface $sourceEntity, array $targetEntities, array $options = []) |
||
716 | |||
717 | /** |
||
718 | * Removes all links between the passed source entity and each of the provided |
||
719 | * target entities. This method assumes that all passed objects are already persisted |
||
720 | * in the database and that each of them contain a primary key value. |
||
721 | * |
||
722 | * ### Options |
||
723 | * |
||
724 | * Additionally to the default options accepted by `Table::delete()`, the following |
||
725 | * keys are supported: |
||
726 | * |
||
727 | * - cleanProperty: Whether or not to remove all the objects in `$targetEntities` that |
||
728 | * are stored in `$sourceEntity` (default: true) |
||
729 | * |
||
730 | * By default this method will unset each of the entity objects stored inside the |
||
731 | * source entity. |
||
732 | * |
||
733 | * ### Example: |
||
734 | * |
||
735 | * ``` |
||
736 | * $article->tags = [$tag1, $tag2, $tag3, $tag4]; |
||
737 | * $tags = [$tag1, $tag2, $tag3]; |
||
738 | * $articles->association('tags')->unlink($article, $tags); |
||
739 | * ``` |
||
740 | * |
||
741 | * `$article->get('tags')` will contain only `[$tag4]` after deleting in the database |
||
742 | * |
||
743 | * @param \Cake\Datasource\EntityInterface $sourceEntity an entity persisted in the source table for |
||
744 | * this association |
||
745 | * @param array $targetEntities list of entities persisted in the target table for |
||
746 | * this association |
||
747 | * @param array|bool $options list of options to be passed to the internal `delete` call, |
||
748 | * or a `boolean` |
||
749 | * @throws \InvalidArgumentException if non persisted entities are passed or if |
||
750 | * any of them is lacking a primary key value |
||
751 | * @return void |
||
752 | */ |
||
753 | public function unlink(EntityInterface $sourceEntity, array $targetEntities, $options = []) |
||
794 | |||
795 | /** |
||
796 | * {@inheritDoc} |
||
797 | */ |
||
798 | public function conditions($conditions = null) |
||
806 | |||
807 | /** |
||
808 | * Returns filtered conditions that reference the target table. |
||
809 | * |
||
810 | * Any string expressions, or expression objects will |
||
811 | * also be returned in this list. |
||
812 | * |
||
813 | * @return mixed Generally an array. If the conditions |
||
814 | * are not an array, the association conditions will be |
||
815 | * returned unmodified. |
||
816 | */ |
||
817 | protected function targetConditions() |
||
837 | |||
838 | /** |
||
839 | * Returns filtered conditions that specifically reference |
||
840 | * the junction table. |
||
841 | * |
||
842 | * @return array |
||
843 | */ |
||
844 | protected function junctionConditions() |
||
862 | |||
863 | /** |
||
864 | * Proxies the finding operation to the target table's find method |
||
865 | * and modifies the query accordingly based of this association |
||
866 | * configuration. |
||
867 | * |
||
868 | * If your association includes conditions, the junction table will be |
||
869 | * included in the query's contained associations. |
||
870 | * |
||
871 | * @param string|array $type the type of query to perform, if an array is passed, |
||
872 | * it will be interpreted as the `$options` parameter |
||
873 | * @param array $options The options to for the find |
||
874 | * @see \Cake\ORM\Table::find() |
||
875 | * @return \Cake\ORM\Query |
||
876 | */ |
||
877 | public function find($type = null, array $options = []) |
||
896 | |||
897 | /** |
||
898 | * Append a join to the junction table. |
||
899 | * |
||
900 | * @param \Cake\ORM\Query $query The query to append. |
||
901 | * @param string|array $conditions The query conditions to use. |
||
902 | * @return \Cake\ORM\Query The modified query. |
||
903 | */ |
||
904 | protected function _appendJunctionJoin($query, $conditions) |
||
923 | |||
924 | /** |
||
925 | * Replaces existing association links between the source entity and the target |
||
926 | * with the ones passed. This method does a smart cleanup, links that are already |
||
927 | * persisted and present in `$targetEntities` will not be deleted, new links will |
||
928 | * be created for the passed target entities that are not already in the database |
||
929 | * and the rest will be removed. |
||
930 | * |
||
931 | * For example, if an article is linked to tags 'cake' and 'framework' and you pass |
||
932 | * to this method an array containing the entities for tags 'cake', 'php' and 'awesome', |
||
933 | * only the link for cake will be kept in database, the link for 'framework' will be |
||
934 | * deleted and the links for 'php' and 'awesome' will be created. |
||
935 | * |
||
936 | * Existing links are not deleted and created again, they are either left untouched |
||
937 | * or updated so that potential extra information stored in the joint row is not |
||
938 | * lost. Updating the link row can be done by making sure the corresponding passed |
||
939 | * target entity contains the joint property with its primary key and any extra |
||
940 | * information to be stored. |
||
941 | * |
||
942 | * On success, the passed `$sourceEntity` will contain `$targetEntities` as value |
||
943 | * in the corresponding property for this association. |
||
944 | * |
||
945 | * This method assumes that links between both the source entity and each of the |
||
946 | * target entities are unique. That is, for any given row in the source table there |
||
947 | * can only be one link in the junction table pointing to any other given row in |
||
948 | * the target table. |
||
949 | * |
||
950 | * Additional options for new links to be saved can be passed in the third argument, |
||
951 | * check `Table::save()` for information on the accepted options. |
||
952 | * |
||
953 | * ### Example: |
||
954 | * |
||
955 | * ``` |
||
956 | * $article->tags = [$tag1, $tag2, $tag3, $tag4]; |
||
957 | * $articles->save($article); |
||
958 | * $tags = [$tag1, $tag3]; |
||
959 | * $articles->association('tags')->replaceLinks($article, $tags); |
||
960 | * ``` |
||
961 | * |
||
962 | * `$article->get('tags')` will contain only `[$tag1, $tag3]` at the end |
||
963 | * |
||
964 | * @param \Cake\Datasource\EntityInterface $sourceEntity an entity persisted in the source table for |
||
965 | * this association |
||
966 | * @param array $targetEntities list of entities from the target table to be linked |
||
967 | * @param array $options list of options to be passed to the internal `save`/`delete` calls |
||
968 | * when persisting/updating new links, or deleting existing ones |
||
969 | * @throws \InvalidArgumentException if non persisted entities are passed or if |
||
970 | * any of them is lacking a primary key value |
||
971 | * @return bool success |
||
972 | */ |
||
973 | public function replaceLinks(EntityInterface $sourceEntity, array $targetEntities, array $options = []) |
||
1020 | |||
1021 | /** |
||
1022 | * Helper method used to delete the difference between the links passed in |
||
1023 | * `$existing` and `$jointEntities`. This method will return the values from |
||
1024 | * `$targetEntities` that were not deleted from calculating the difference. |
||
1025 | * |
||
1026 | * @param \Cake\ORM\Query $existing a query for getting existing links |
||
1027 | * @param array $jointEntities link entities that should be persisted |
||
1028 | * @param array $targetEntities entities in target table that are related to |
||
1029 | * the `$jointEntities` |
||
1030 | * @param array $options list of options accepted by `Table::delete()` |
||
1031 | * @return array |
||
1032 | */ |
||
1033 | protected function _diffLinks($existing, $jointEntities, $targetEntities, $options = []) |
||
1088 | |||
1089 | /** |
||
1090 | * Throws an exception should any of the passed entities is not persisted. |
||
1091 | * |
||
1092 | * @param \Cake\Datasource\EntityInterface $sourceEntity the row belonging to the `source` side |
||
1093 | * of this association |
||
1094 | * @param array $targetEntities list of entities belonging to the `target` side |
||
1095 | * of this association |
||
1096 | * @return bool |
||
1097 | * @throws \InvalidArgumentException |
||
1098 | */ |
||
1099 | protected function _checkPersistenceStatus($sourceEntity, array $targetEntities) |
||
1115 | |||
1116 | /** |
||
1117 | * Returns the list of joint entities that exist between the source entity |
||
1118 | * and each of the passed target entities |
||
1119 | * |
||
1120 | * @param \Cake\Datasource\EntityInterface $sourceEntity The row belonging to the source side |
||
1121 | * of this association. |
||
1122 | * @param array $targetEntities The rows belonging to the target side of this |
||
1123 | * association. |
||
1124 | * @throws \InvalidArgumentException if any of the entities is lacking a primary |
||
1125 | * key value |
||
1126 | * @return array |
||
1127 | */ |
||
1128 | protected function _collectJointEntities($sourceEntity, $targetEntities) |
||
1176 | |||
1177 | /** |
||
1178 | * Auxiliary function to construct a new Query object to return all the records |
||
1179 | * in the target table that are associated to those specified in $options from |
||
1180 | * the source table. |
||
1181 | * |
||
1182 | * This is used for eager loading records on the target table based on conditions. |
||
1183 | * |
||
1184 | * @param array $options options accepted by eagerLoader() |
||
1185 | * @return \Cake\ORM\Query |
||
1186 | * @throws \InvalidArgumentException When a key is required for associations but not selected. |
||
1187 | */ |
||
1188 | protected function _buildQuery($options) |
||
1217 | |||
1218 | /** |
||
1219 | * Generates a string used as a table field that contains the values upon |
||
1220 | * which the filter should be applied |
||
1221 | * |
||
1222 | * @param array $options the options to use for getting the link field. |
||
1223 | * @return string |
||
1224 | */ |
||
1225 | View Code Duplication | protected function _linkField($options) |
|
1240 | |||
1241 | /** |
||
1242 | * Returns the name of the association from the target table to the junction table, |
||
1243 | * this name is used to generate alias in the query and to later on retrieve the |
||
1244 | * results. |
||
1245 | * |
||
1246 | * @return string |
||
1247 | */ |
||
1248 | protected function _junctionAssociationName() |
||
1257 | |||
1258 | /** |
||
1259 | * Sets the name of the junction table. |
||
1260 | * If no arguments are passed the current configured name is returned. A default |
||
1261 | * name based of the associated tables will be generated if none found. |
||
1262 | * |
||
1263 | * @param string|null $name The name of the junction table. |
||
1264 | * @return string |
||
1265 | */ |
||
1266 | protected function _junctionTableName($name = null) |
||
1281 | |||
1282 | /** |
||
1283 | * Parse extra options passed in the constructor. |
||
1284 | * |
||
1285 | * @param array $opts original list of options passed in constructor |
||
1286 | * @return void |
||
1287 | */ |
||
1288 | protected function _options(array $opts) |
||
1304 | } |
||
1305 |
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.