Total Complexity | 58 |
Total Lines | 550 |
Duplicated Lines | 0 % |
Changes | 6 | ||
Bugs | 2 | Features | 0 |
Complex classes like app_RecordSet 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.
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 app_RecordSet, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
38 | class app_RecordSet extends ORM_RecordSet implements app_Object_Interface |
||
39 | { |
||
40 | /** |
||
41 | * @var Func_App |
||
42 | */ |
||
43 | protected $app = null; |
||
44 | |||
45 | protected $accessRights = null; |
||
46 | |||
47 | /** |
||
48 | * @var app_AccessManager |
||
49 | */ |
||
50 | private $accessManager = null; |
||
51 | |||
52 | /** |
||
53 | * @var array |
||
54 | */ |
||
55 | private $customFields = null; |
||
56 | |||
57 | |||
58 | /** |
||
59 | * @param Func_App $app |
||
60 | */ |
||
61 | public function __construct(Func_App $app) |
||
62 | { |
||
63 | parent::__construct(); |
||
64 | $this->setApp($app); |
||
65 | $this->accessRights = array(); |
||
66 | |||
67 | $this->setAccessManager($app->AccessManager()); |
||
68 | $this->setPrimaryKey('id'); |
||
69 | } |
||
70 | |||
71 | /** |
||
72 | * {@inheritDoc} |
||
73 | * @see app_Object_Interface::setApp() |
||
74 | */ |
||
75 | public function setApp(Func_App $app) |
||
76 | { |
||
77 | $this->app = $app; |
||
78 | return $this; |
||
79 | } |
||
80 | |||
81 | |||
82 | /** |
||
83 | * {@inheritDoc} |
||
84 | * @see app_Object_Interface::App() |
||
85 | */ |
||
86 | public function App() |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * @param string $setName |
||
93 | */ |
||
94 | protected function extractSetPrefixAndName($setName) |
||
95 | { |
||
96 | $pos = strrpos($setName, '\\'); |
||
97 | if ($pos === false) { |
||
98 | return explode('_', $setName); |
||
99 | } |
||
100 | return array(substr($setName, 0, $pos), substr($setName, $pos + 1)); |
||
101 | } |
||
102 | |||
103 | /** |
||
104 | * Similar to the ORM_RecordSet::join() method but instanciates the |
||
105 | * joined RecordSet using App methods. |
||
106 | * |
||
107 | * @see ORM_RecordSet::join() |
||
108 | */ |
||
109 | public function join($fkFieldName) |
||
110 | { |
||
111 | $fkField = $this->getField($fkFieldName); |
||
112 | if (!($fkField instanceof ORM_FkField)) { |
||
113 | return $this; |
||
114 | } |
||
115 | $setName = $fkField->getForeignSetName(); |
||
116 | |||
117 | if (!$setName || 'Set' === $setName) { |
||
118 | throw new Exception('The set name is missing on foreign key field '.$fkFieldName); |
||
119 | } |
||
120 | |||
121 | list($prefix, $appSetName) = $this->extractSetPrefixAndName($setName); |
||
122 | $set = $this->App()->$appSetName(); |
||
123 | $set->setName($fkField->getName()); |
||
124 | $set->setDescription($fkField->getDescription()); |
||
125 | |||
126 | $this->aField[$fkFieldName] = $set; |
||
127 | $set->setParentSet($this); |
||
128 | return $this; |
||
129 | } |
||
130 | |||
131 | |||
132 | // /** |
||
133 | // * |
||
134 | // * @param string $accessName |
||
135 | // * @param string $type |
||
136 | // */ |
||
137 | // public function addAccessRight($accessName, $type = 'acl') |
||
138 | // { |
||
139 | // $this->accessRights[$accessName] = $type; |
||
140 | // } |
||
141 | |||
142 | |||
143 | // /** |
||
144 | // * @return array |
||
145 | // */ |
||
146 | // public function getAccessRights() |
||
147 | // { |
||
148 | // return $this->accessRights; |
||
149 | // } |
||
150 | |||
151 | |||
152 | |||
153 | /** |
||
154 | * @return app_CustomField[] |
||
155 | */ |
||
156 | public function getCustomFields() |
||
157 | { |
||
158 | $App = $this->App(); |
||
159 | |||
160 | if (null === $this->customFields) { |
||
161 | $this->customFields = array(); |
||
162 | |||
163 | if (isset($App->CustomField)) { |
||
|
|||
164 | $customFieldSet = $App->CustomFieldSet(); |
||
165 | $object = mb_substr(get_class($this), mb_strlen($App->classPrefix), -mb_strlen('Set')); |
||
166 | try { |
||
167 | $customFields = $customFieldSet->select($customFieldSet->object->is($object)); |
||
168 | |||
169 | foreach ($customFields as $customfield) { |
||
170 | $this->customFields[] = $customfield; |
||
171 | |||
172 | /*@var $customfield app_CustomField */ |
||
173 | |||
174 | } |
||
175 | } catch (ORM_BackEndSelectException $e) { |
||
176 | // table does not exist, this error is thrown by the install program while creating the sets |
||
177 | } |
||
178 | } |
||
179 | } |
||
180 | |||
181 | return $this->customFields; |
||
182 | } |
||
183 | |||
184 | |||
185 | |||
186 | |||
187 | /** |
||
188 | * @return app_CustomField[] |
||
189 | */ |
||
190 | public function selectCustomFields() |
||
191 | { |
||
192 | $App = $this->App(); |
||
193 | |||
194 | $customFieldSet= $App->CustomFieldSet(); |
||
195 | $object = mb_substr(get_class($this), mb_strlen($App->classPrefix), -mb_strlen('Set')); |
||
196 | |||
197 | $customFields = $customFieldSet->select($customFieldSet->object->is($object)); |
||
198 | |||
199 | return $customFields; |
||
200 | } |
||
201 | |||
202 | |||
203 | /** |
||
204 | * @return self |
||
205 | */ |
||
206 | public function addCustomFields() |
||
207 | { |
||
208 | $customFields = $this->selectCustomFields(); |
||
209 | foreach ($customFields as $customField) { |
||
210 | /*@var $customField app_CustomField */ |
||
211 | $description = $customField->name; |
||
212 | $ormField = $customField->getORMField() |
||
213 | ->setDescription($description); |
||
214 | if ($ormField instanceof ORM_FkField) { |
||
215 | $this->hasOne($customField->fieldname, $ormField->getForeignSetName()) |
||
216 | ->setDescription($description); |
||
217 | } else { |
||
218 | $this->addFields($ormField); |
||
219 | } |
||
220 | } |
||
221 | |||
222 | return $this; |
||
223 | } |
||
224 | |||
225 | |||
226 | /** |
||
227 | * Similar to ORM_RecordSet::get() method but throws a app_NotFoundException if the |
||
228 | * record is not found. |
||
229 | * |
||
230 | * @since 1.0.18 |
||
231 | * |
||
232 | * @throws ORM_Exception |
||
233 | * @throws app_NotFoundException |
||
234 | * |
||
235 | * @param ORM_Criteria|string $mixedParam Criteria for selecting records |
||
236 | * or the value for selecting record |
||
237 | * @param string $sPropertyName The name of the property on which |
||
238 | * the value applies. If not |
||
239 | * specified or null, the set's |
||
240 | * primary key will be used. |
||
241 | * |
||
242 | * @return app_Record |
||
243 | */ |
||
244 | public function request($mixedParam = null, $sPropertyName = null) |
||
258 | } |
||
259 | |||
260 | |||
261 | |||
262 | |||
263 | |||
264 | |||
265 | |||
266 | |||
267 | |||
268 | /** |
||
269 | * Returns an iterator of traceableRecord linked to the specified source, |
||
270 | * optionally filtered on the specified link type. |
||
271 | * |
||
272 | * @param app_Record | array $source source can be an array of record |
||
273 | * @param string $linkType |
||
274 | * |
||
275 | * @return ORM_Iterator |
||
276 | */ |
||
277 | public function selectLinkedTo($source, $linkType = null) |
||
278 | { |
||
279 | $linkSet = $this->App()->LinkSet(); |
||
280 | if (is_array($source) || ($source instanceof Iterator)) { |
||
281 | return $linkSet->selectForSources($source, $this->getRecordClassName(), $linkType); |
||
282 | } else { |
||
283 | return $linkSet->selectForSource($source, $this->getRecordClassName(), $linkType); |
||
284 | } |
||
285 | } |
||
286 | |||
287 | /** |
||
288 | * Returns an iterator of traceableRecord linked to the specified target, |
||
289 | * optionally filtered on the specified link type. |
||
290 | * |
||
291 | * @param app_Record | array $target target can be an array of record |
||
292 | * @param string $linkType |
||
293 | * |
||
294 | * @return ORM_Iterator |
||
295 | */ |
||
296 | public function selectLinkedFrom($target, $linkType = null) |
||
297 | { |
||
298 | $linkSet = $this->App()->LinkSet(); |
||
299 | if (is_array($target) || ($target instanceof Iterator)) { |
||
300 | return $linkSet->selectForTargets($target, $this->getRecordClassName(), $linkType); |
||
301 | } else { |
||
302 | return $linkSet->selectForTarget($target, $this->getRecordClassName(), $linkType); |
||
303 | } |
||
304 | } |
||
305 | |||
306 | |||
307 | /** |
||
308 | * Returns a criteria usable to select records of this set which are source of app_Links to the specified app_Record. |
||
309 | * |
||
310 | * @param app_Record $target |
||
311 | * @param string $linkType |
||
312 | * @return ORM_Criteria |
||
313 | */ |
||
314 | public function isSourceOf(app_Record $target, $linkType = null) |
||
315 | { |
||
316 | $linkSet = $this->App()->LinkSet(); |
||
317 | |||
318 | $linkSet->hasOne('sourceId', get_class($this)); |
||
319 | |||
320 | $criteria = $linkSet->targetClass->is(get_class($target)) |
||
321 | ->_AND_($linkSet->targetId->is($target->id)) |
||
322 | ->_AND_($linkSet->sourceClass->is($this->getRecordClassName())); |
||
323 | if (isset($linkType)) { |
||
324 | if (is_array($linkType)) { |
||
325 | $criteria = $criteria->_AND_($linkSet->type->in($linkType)); |
||
326 | } else { |
||
327 | $criteria = $criteria->_AND_($linkSet->type->is($linkType)); |
||
328 | } |
||
329 | } |
||
330 | $criteria = $this->id->in($criteria); |
||
331 | |||
332 | return $criteria; |
||
333 | } |
||
334 | |||
335 | |||
336 | |||
337 | /** |
||
338 | * Returns a criteria usable to select records of this set which are target of app_Links to the specified app_Record. |
||
339 | * |
||
340 | * @param app_Record $source |
||
341 | * @param null|string|string[] $linkType |
||
342 | * @return ORM_Criteria |
||
343 | */ |
||
344 | public function isTargetOf(app_Record $source, $linkType = null) |
||
345 | { |
||
346 | $linkSet = $this->App()->LinkSet(); |
||
347 | |||
348 | $linkSet->hasOne('targetId', get_class($this)); |
||
349 | |||
350 | $criteria = $linkSet->sourceClass->is(get_class($source)) |
||
351 | ->_AND_($linkSet->sourceId->is($source->id)) |
||
352 | ->_AND_($linkSet->targetClass->is($this->getRecordClassName())); |
||
353 | if (isset($linkType)) { |
||
354 | if (is_array($linkType)) { |
||
355 | $criteria = $criteria->_AND_($linkSet->type->in($linkType)); |
||
356 | } else { |
||
357 | $criteria = $criteria->_AND_($linkSet->type->is($linkType)); |
||
358 | } |
||
359 | } |
||
360 | $criteria = $this->id->in($criteria); |
||
361 | |||
362 | return $criteria; |
||
363 | } |
||
364 | |||
365 | |||
366 | /** |
||
367 | * Returns a criteria usable to select records of this set which are target of app_Links from the specified app_Records. |
||
368 | * |
||
369 | * @since 1.0.23 |
||
370 | * |
||
371 | * @param app_Record[] $sources |
||
372 | * @param null|string|string[] $linkType |
||
373 | * @return ORM_Criteria |
||
374 | */ |
||
375 | public function isTargetOfAny($sources, $linkType = null) |
||
376 | { |
||
377 | $linkSet = $this->App()->LinkSet(); |
||
378 | $linkSet->hasOne('targetId', get_class($this)); |
||
379 | |||
380 | $sourceIdsByClasses = array(); |
||
381 | foreach ($sources as $source) { |
||
382 | $sourceClass = get_class($source); |
||
383 | if (!isset($sourceIdsByClasses[$sourceClass])) { |
||
384 | $sourceIdsByClasses[$sourceClass] = array(); |
||
385 | } |
||
386 | $sourceIdsByClasses[$sourceClass][] = $source->id; |
||
387 | } |
||
388 | |||
389 | $sourcesCriteria = array(); |
||
390 | foreach ($sourceIdsByClasses as $sourceClass => $sourceIds) { |
||
391 | $sourcesCriteria[] = $linkSet->sourceClass->is($sourceClass)->_AND_($linkSet->sourceId->in($sourceIds)); |
||
392 | } |
||
393 | |||
394 | $criteria = $linkSet->all( |
||
395 | $linkSet->targetClass->is($this->getRecordClassName()), |
||
396 | $linkSet->any($sourcesCriteria) |
||
397 | ); |
||
398 | if (isset($linkType)) { |
||
399 | if (is_array($linkType)) { |
||
400 | $criteria = $criteria->_AND_($linkSet->type->in($linkType)); |
||
401 | } else { |
||
402 | $criteria = $criteria->_AND_($linkSet->type->is($linkType)); |
||
403 | } |
||
404 | } |
||
405 | $criteria = $this->id->in($criteria); |
||
406 | |||
407 | return $criteria; |
||
408 | } |
||
409 | |||
410 | |||
411 | /** |
||
412 | * Returns a criteria usable to select records of this set which are source of app_Links to the specified app_Records. |
||
413 | * |
||
414 | * @since 1.0.23 |
||
415 | * |
||
416 | * @param app_Record[] $targets |
||
417 | * @param string|null $linkType |
||
418 | * @return ORM_Criteria |
||
419 | */ |
||
420 | public function isSourceOfAny($targets, $linkType = null) |
||
421 | { |
||
422 | $linkSet = $this->App()->LinkSet(); |
||
423 | $linkSet->hasOne('sourceId', get_class($this)); |
||
424 | |||
425 | $targetIdsByClasses = array(); |
||
426 | foreach ($targets as $target) { |
||
427 | $targetClass = get_class($target); |
||
428 | if (!isset($targetIdsByClasses[$targetClass])) { |
||
429 | $targetIdsByClasses[$targetClass] = array(); |
||
430 | } |
||
431 | $targetIdsByClasses[$targetClass][] = $target->id; |
||
432 | } |
||
433 | |||
434 | $targetsCriteria = array(); |
||
435 | foreach ($targetIdsByClasses as $targetClass => $targetIds) { |
||
436 | $targetsCriteria[] = $linkSet->targetClass->is($targetClass)->_AND_($linkSet->targetId->in($targetIds)); |
||
437 | } |
||
438 | |||
439 | $criteria = $linkSet->all( |
||
440 | $linkSet->sourceClass->is($this->getRecordClassName()), |
||
441 | $linkSet->any($targetsCriteria) |
||
442 | ); |
||
443 | if (isset($linkType)) { |
||
444 | if (is_array($linkType)) { |
||
445 | $criteria = $criteria->_AND_($linkSet->type->in($linkType)); |
||
446 | } else { |
||
447 | $criteria = $criteria->_AND_($linkSet->type->is($linkType)); |
||
448 | } |
||
449 | } |
||
450 | $criteria = $this->id->in($criteria); |
||
451 | |||
452 | return $criteria; |
||
453 | } |
||
454 | |||
455 | |||
456 | /** |
||
457 | * @param app_AccessManager $accessManager |
||
458 | * @return self |
||
459 | */ |
||
460 | public function setAccessManager(app_AccessManager $accessManager) |
||
464 | } |
||
465 | |||
466 | |||
467 | /** |
||
468 | * @return app_AccessManager |
||
469 | */ |
||
470 | public function getAccessManager() |
||
471 | { |
||
472 | return $this->accessManager; |
||
473 | } |
||
474 | |||
475 | |||
476 | /** |
||
477 | * Defines if records can be created by the current user. |
||
478 | * |
||
479 | * @return boolean |
||
480 | */ |
||
481 | public function isCreatable() |
||
482 | { |
||
483 | return false; |
||
484 | } |
||
485 | |||
486 | |||
487 | |||
488 | /** |
||
489 | * |
||
490 | * @return ORM_Criteria |
||
491 | */ |
||
492 | public function isReadable() |
||
493 | { |
||
494 | return $this->hasAccess('read'); |
||
495 | } |
||
496 | |||
497 | /** |
||
498 | * |
||
499 | * @return ORM_Criteria |
||
500 | */ |
||
501 | public function isUpdatable() |
||
502 | { |
||
503 | return $this->hasAccess('update'); |
||
504 | } |
||
505 | |||
506 | /** |
||
507 | * |
||
508 | * @return ORM_Criteria |
||
509 | */ |
||
510 | public function isDeletable() |
||
511 | { |
||
512 | return $this->hasAccess('delete'); |
||
513 | } |
||
514 | |||
515 | |||
516 | |||
517 | /** |
||
518 | * Returns a criterion matching records that can be put to trash by the current user. |
||
519 | * |
||
520 | * @return ORM_Criterion |
||
521 | */ |
||
522 | public function isRemovable() |
||
525 | } |
||
526 | |||
527 | |||
528 | /** |
||
529 | * Returns a criterion matching records that can be restored from the trash by the current user. |
||
530 | * |
||
531 | * @return ORM_Criterion |
||
532 | */ |
||
533 | public function isRestorable() |
||
534 | { |
||
535 | return $this->isUpdatable(); |
||
536 | } |
||
537 | |||
538 | /** |
||
539 | * Returns a criterion matching records deletable by the current user. |
||
540 | * |
||
541 | * @param string $accessType |
||
542 | * @param int|null $user |
||
543 | * |
||
544 | * @return ORM_Criterion |
||
545 | */ |
||
546 | public function hasAccess($accessType, $user = null) |
||
547 | { |
||
548 | $accessManager = $this->getAccessManager(); |
||
549 | return $accessManager->getAccessCriterion($this, $accessType, $user); |
||
550 | } |
||
551 | |||
552 | /** |
||
553 | * Returns a criteria usable to select records of this set associated to the specified tags. |
||
554 | * |
||
555 | * @array $tags An array of tag ids |
||
556 | * @string $type The link type [optional] |
||
557 | * @return ORM_Criteria |
||
558 | */ |
||
559 | public function haveTagLabels($tagLabels, $linkType = null) |
||
588 | } |
||
589 | } |
||
590 | |||
591 | |||
592 | |||
593 | /** |
||
594 | * @property int $id |
||
595 | * |
||
596 | * @method app_RecordSet getParentSet() |
||
597 | */ |
||
598 | class app_Record extends ORM_Record implements app_Object_Interface |
||
599 | { |
||
600 | /** |
||
601 | * @var Func_App |
||
602 | */ |
||
603 | protected $app = null; |
||
604 | |||
1215 |