Complex classes like ManyManyList 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 ManyManyList, and based on these observations, apply Extract Interface, too.
| 1 | <?php |
||
| 9 | class ManyManyList extends RelationList { |
||
| 10 | |||
| 11 | /** |
||
| 12 | * @var string $joinTable |
||
| 13 | */ |
||
| 14 | protected $joinTable; |
||
| 15 | |||
| 16 | /** |
||
| 17 | * @var string $localKey |
||
| 18 | */ |
||
| 19 | protected $localKey; |
||
| 20 | |||
| 21 | /** |
||
| 22 | * @var string $foreignKey |
||
| 23 | */ |
||
| 24 | protected $foreignKey; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * @var array $extraFields |
||
| 28 | */ |
||
| 29 | protected $extraFields; |
||
| 30 | |||
| 31 | /** |
||
| 32 | * @var array $_compositeExtraFields |
||
| 33 | */ |
||
| 34 | protected $_compositeExtraFields = array(); |
||
| 35 | |||
| 36 | /** |
||
| 37 | * Create a new ManyManyList object. |
||
| 38 | * |
||
| 39 | * A ManyManyList object represents a list of {@link DataObject} records |
||
| 40 | * that correspond to a many-many relationship. |
||
| 41 | * |
||
| 42 | * Generation of the appropriate record set is left up to the caller, using |
||
| 43 | * the normal {@link DataList} methods. Addition arguments are used to |
||
| 44 | * support {@@link add()} and {@link remove()} methods. |
||
| 45 | * |
||
| 46 | * @param string $dataClass The class of the DataObjects that this will list. |
||
| 47 | * @param string $joinTable The name of the table whose entries define the content of this many_many relation. |
||
| 48 | * @param string $localKey The key in the join table that maps to the dataClass' PK. |
||
| 49 | * @param string $foreignKey The key in the join table that maps to joined class' PK. |
||
| 50 | * @param array $extraFields A map of field => fieldtype of extra fields on the join table. |
||
| 51 | * |
||
| 52 | * @example new ManyManyList('Group','Group_Members', 'GroupID', 'MemberID'); |
||
| 53 | */ |
||
| 54 | public function __construct($dataClass, $joinTable, $localKey, $foreignKey, $extraFields = array()) { |
||
| 64 | |||
| 65 | /** |
||
| 66 | * Setup the join between this dataobject and the necessary mapping table |
||
| 67 | */ |
||
| 68 | protected function linkJoinTable() { |
||
| 78 | |||
| 79 | /** |
||
| 80 | * Adds the many_many_extraFields to the select of the underlying |
||
| 81 | * {@link DataQuery}. |
||
| 82 | * |
||
| 83 | * @return void |
||
| 84 | */ |
||
| 85 | protected function appendExtraFieldsToQuery() { |
||
| 109 | |||
| 110 | /** |
||
| 111 | * Create a DataObject from the given SQL row. |
||
| 112 | * |
||
| 113 | * @param array $row |
||
| 114 | * @return DataObject |
||
| 115 | */ |
||
| 116 | protected function createDataObject($row) { |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Return a filter expression for when getting the contents of the |
||
| 152 | * relationship for some foreign ID |
||
| 153 | * |
||
| 154 | * @param int|null $id |
||
| 155 | * |
||
| 156 | * @return array |
||
| 157 | */ |
||
| 158 | protected function foreignIDFilter($id = null) { |
||
| 171 | |||
| 172 | /** |
||
| 173 | * Return a filter expression for the join table when writing to the join table |
||
| 174 | * |
||
| 175 | * When writing (add, remove, removeByID), we need to filter the join table to just the relevant |
||
| 176 | * entries. However some subclasses of ManyManyList (Member_GroupSet) modify foreignIDFilter to |
||
| 177 | * include additional calculated entries, so we need different filters when reading and when writing |
||
| 178 | * |
||
| 179 | * @param array|int|null $id (optional) An ID or an array of IDs - if not provided, will use the current ids |
||
| 180 | * as per getForeignID |
||
| 181 | * @return array Condition In array(SQL => parameters format) |
||
| 182 | */ |
||
| 183 | protected function foreignIDWriteFilter($id = null) { |
||
| 186 | |||
| 187 | /** |
||
| 188 | * Add an item to this many_many relationship |
||
| 189 | * Does so by adding an entry to the joinTable. |
||
| 190 | * |
||
| 191 | * Can also be used to update an already existing joinTable entry |
||
| 192 | * |
||
| 193 | * Example: |
||
| 194 | * |
||
| 195 | * $manyManyList->add($recordID, array("ExtraField"=>"value")); |
||
| 196 | * |
||
| 197 | * |
||
| 198 | * @throws InvalidArgumentException |
||
| 199 | * @throws Exception |
||
| 200 | * |
||
| 201 | * @param DataObject|int $item |
||
| 202 | * @param array $extraFields A map of additional columns to insert into the joinTable. |
||
| 203 | * Column names should be ANSI quoted. |
||
| 204 | */ |
||
| 205 | public function add($item, $extraFields = array()) { |
||
| 291 | |||
| 292 | /** |
||
| 293 | * Remove the given item from this list. |
||
| 294 | * |
||
| 295 | * Note that for a ManyManyList, the item is never actually deleted, only |
||
| 296 | * the join table is affected. |
||
| 297 | * |
||
| 298 | * @param DataObject $item |
||
| 299 | */ |
||
| 300 | public function remove($item) { |
||
| 307 | |||
| 308 | /** |
||
| 309 | * Remove the given item from this list. |
||
| 310 | * |
||
| 311 | * Note that for a ManyManyList, the item is never actually deleted, only |
||
| 312 | * the join table is affected |
||
| 313 | * |
||
| 314 | * @param int $itemID The item ID |
||
| 315 | */ |
||
| 316 | public function removeByID($itemID) { |
||
| 330 | |||
| 331 | /** |
||
| 332 | * Remove all items from this many-many join. To remove a subset of items, |
||
| 333 | * filter it first. |
||
| 334 | * |
||
| 335 | * @return void |
||
| 336 | */ |
||
| 337 | public function removeAll() { |
||
| 365 | |||
| 366 | /** |
||
| 367 | * Find the extra field data for a single row of the relationship join |
||
| 368 | * table, given the known child ID. |
||
| 369 | * |
||
| 370 | * @param string $componentName The name of the component |
||
| 371 | * @param int $itemID The ID of the child for the relationship |
||
| 372 | * |
||
| 373 | * @return array Map of fieldName => fieldValue |
||
| 374 | */ |
||
| 375 | public function getExtraData($componentName, $itemID) { |
||
| 410 | |||
| 411 | /** |
||
| 412 | * Gets the join table used for the relationship. |
||
| 413 | * |
||
| 414 | * @return string the name of the table |
||
| 415 | */ |
||
| 416 | public function getJoinTable() { |
||
| 419 | |||
| 420 | /** |
||
| 421 | * Gets the key used to store the ID of the local/parent object. |
||
| 422 | * |
||
| 423 | * @return string the field name |
||
| 424 | */ |
||
| 425 | public function getLocalKey() { |
||
| 428 | |||
| 429 | /** |
||
| 430 | * Gets the key used to store the ID of the foreign/child object. |
||
| 431 | * |
||
| 432 | * @return string the field name |
||
| 433 | */ |
||
| 434 | public function getForeignKey() { |
||
| 437 | |||
| 438 | /** |
||
| 439 | * Gets the extra fields included in the relationship. |
||
| 440 | * |
||
| 441 | * @return array a map of field names to types |
||
| 442 | */ |
||
| 443 | public function getExtraFields() { |
||
| 446 | |||
| 447 | } |
||
| 448 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.