Skip to content

Commit 58903d8

Browse files
committed
Starting to use an object for representing an eagerloadable
1 parent c3d8e23 commit 58903d8

File tree

2 files changed

+190
-53
lines changed

2 files changed

+190
-53
lines changed

src/ORM/EagerLoadable.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
<?php
2+
/**
3+
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
4+
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
5+
*
6+
* Licensed under The MIT License
7+
* For full copyright and license information, please see the LICENSE.txt
8+
* Redistributions of files must retain the above copyright notice.
9+
*
10+
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11+
* @link http://cakephp.org CakePHP(tm) Project
12+
* @since 3.0.0
13+
* @license http://www.opensource.org/licenses/mit-license.php MIT License
14+
*/
15+
namespace Cake\ORM;
16+
17+
/**
18+
*/
19+
class EagerLoadable
20+
{
21+
22+
protected $_name;
23+
24+
protected $_associations = [];
25+
26+
protected $_instance;
27+
28+
protected $_config = [];
29+
30+
protected $_aliasPath;
31+
32+
protected $_propertyPath;
33+
34+
protected $_canBeJoined = false;
35+
36+
protected $_forMatching;
37+
38+
public function __construct($name, array $config = [])
39+
{
40+
$this->_name = $name;
41+
$allowed = [
42+
'associations', 'instance', 'config', 'canBeJoined',
43+
'aliasPath', 'propertyPath', 'forMatching'
44+
];
45+
foreach ($allowed as $property) {
46+
if (isset($config[$property])) {
47+
$this->{'_' . $property} = $config[$property];
48+
}
49+
}
50+
}
51+
52+
public function addAssociation($name, EagerLoadable $association)
53+
{
54+
$this->_associations[$name] = $association;
55+
}
56+
57+
public function associations()
58+
{
59+
return $this->_associations;
60+
}
61+
62+
public function instance($instance = null)
63+
{
64+
if ($instance === null) {
65+
return $this->_instance;
66+
}
67+
$this->_instance = $instance;
68+
}
69+
70+
public function aliasPath($path = null)
71+
{
72+
if ($path === null) {
73+
return $this->_aliasPath;
74+
}
75+
$this->_aliasPath = $path;
76+
}
77+
78+
public function propertyPath($path = null)
79+
{
80+
if ($path === null) {
81+
return $this->_propertyPath;
82+
}
83+
$this->_propertyPath = $path;
84+
}
85+
86+
public function canBeJoined($possible = null)
87+
{
88+
if ($possible === null) {
89+
return $this->_canBeJoined;
90+
}
91+
$this->_canBeJoined = $possible;
92+
}
93+
94+
public function config(array $config = null)
95+
{
96+
if ($config === null) {
97+
return $this->_config;
98+
}
99+
$this->_config = $config;
100+
}
101+
102+
public function forMatching($matching = null)
103+
{
104+
if ($matching === null) {
105+
return $this->_forMatching;
106+
}
107+
$this->_forMatching = $matching;
108+
}
109+
110+
public function asContainArray()
111+
{
112+
$associations = [];
113+
foreach ($this->_associations as $assoc) {
114+
$associations += $assoc->asContainArray();
115+
}
116+
$config = $this->_config;
117+
if ($this->_forMatching !== null) {
118+
$config = ['matching' => $this->_forMatching] + $config;
119+
}
120+
return [
121+
$this->_name => [
122+
'associations' => $associations,
123+
'config' => $config
124+
]
125+
];
126+
}
127+
}

src/ORM/EagerLoader.php

Lines changed: 63 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ public function normalized(Table $repository)
195195
$contain = (array)$this->_containments;
196196
break;
197197
}
198-
$contain[$alias] =& $this->_normalizeContain(
198+
$contain[$alias] = $this->_normalizeContain(
199199
$repository,
200200
$alias,
201201
$options,
@@ -279,13 +279,13 @@ public function attachAssociations(Query $query, Table $repository, $includeFiel
279279
return;
280280
}
281281

282-
foreach ($this->attachableAssociations($repository) as $options) {
283-
$config = $options['config'] + [
284-
'aliasPath' => $options['aliasPath'],
285-
'propertyPath' => $options['propertyPath'],
282+
foreach ($this->attachableAssociations($repository) as $loadable) {
283+
$config = $loadable->config() + [
284+
'aliasPath' => $loadable->aliasPath(),
285+
'propertyPath' => $loadable->propertyPath(),
286286
'includeFields' => $includeFields
287287
];
288-
$options['instance']->attachTo($query, $config);
288+
$loadable->instance()->attachTo($query, $config);
289289
}
290290
}
291291

@@ -344,7 +344,7 @@ public function externalAssociations(Table $repository)
344344
* @return array normalized associations
345345
* @throws \InvalidArgumentException When containments refer to associations that do not exist.
346346
*/
347-
protected function &_normalizeContain(Table $parent, $alias, $options, $paths)
347+
protected function _normalizeContain(Table $parent, $alias, $options, $paths)
348348
{
349349
$defaults = $this->_containOptions;
350350
$instance = $parent->association($alias);
@@ -369,18 +369,22 @@ protected function &_normalizeContain(Table $parent, $alias, $options, $paths)
369369
'propertyPath' => trim($paths['propertyPath'], '.')
370370
];
371371
$config['canBeJoined'] = $instance->canBeJoined($config['config']);
372+
$eagerLoadable = new EagerLoadable($alias, $config);
372373

373374
if ($config['canBeJoined']) {
374-
$this->_aliasList[$paths['root']][$alias][] =& $config;
375+
$this->_aliasList[$paths['root']][$alias][] = $eagerLoadable;
375376
} else {
376377
$paths['root'] = $config['aliasPath'];
377378
}
378379

379380
foreach ($extra as $t => $assoc) {
380-
$config['associations'][$t] =& $this->_normalizeContain($table, $t, $assoc, $paths);
381+
$eagerLoadable->addAssociation(
382+
$t,
383+
$this->_normalizeContain($table, $t, $assoc, $paths)
384+
);
381385
}
382386

383-
return $config;
387+
return $eagerLoadable;
384388
}
385389

386390
/**
@@ -394,14 +398,14 @@ protected function &_normalizeContain(Table $parent, $alias, $options, $paths)
394398
*/
395399
protected function _fixStrategies()
396400
{
397-
foreach ($this->_aliasList as &$aliases) {
398-
foreach ($aliases as $alias => &$configs) {
401+
foreach ($this->_aliasList as $aliases) {
402+
foreach ($aliases as $alias => $configs) {
399403
if (count($configs) < 2) {
400404
continue;
401405
}
402-
foreach ($configs as &$config) {
403-
if (strpos($config['aliasPath'], '.')) {
404-
$this->_correctStrategy($config, $alias);
406+
foreach ($configs as $loadable) {
407+
if (strpos($loadable->aliasPath(), '.')) {
408+
$this->_correctStrategy($loadable, $alias);
405409
}
406410
}
407411
}
@@ -412,26 +416,23 @@ protected function _fixStrategies()
412416
* Changes the association fetching strategy if required because of duplicate
413417
* under the same direct associations chain
414418
*
415-
* This function modifies the $config variable
416-
*
417-
* @param array &$config The association config
419+
* @param \Cake\ORM\EagerLoader $loadable The association config
418420
* @param string $alias the name of the association to evaluate
419-
* @return void|array
420-
* @throws \RuntimeException if a duplicate association in the same chain is detected
421-
* but is not possible to change the strategy due to conflicting settings
421+
* @return void
422422
*/
423-
protected function _correctStrategy(&$config, $alias)
423+
protected function _correctStrategy($loadable, $alias)
424424
{
425-
$currentStrategy = isset($config['config']['strategy']) ?
426-
$config['config']['strategy'] :
425+
$config = $loadable->config();
426+
$currentStrategy = isset($config['strategy']) ?
427+
$config['strategy'] :
427428
'join';
428429

429-
if (!$config['canBeJoined'] || $currentStrategy !== 'join') {
430-
return $config;
430+
if (!$loadable->canBeJoined() || $currentStrategy !== 'join') {
431+
return;
431432
}
432433

433-
$config['canBeJoined'] = false;
434-
$config['config']['strategy'] = $config['instance']::STRATEGY_SELECT;
434+
$config = $config['strategy'] = Association::STRATEGY_SELECT;
435+
$loadable->canBeJoined(false);
435436
}
436437

437438
/**
@@ -447,15 +448,18 @@ protected function _resolveJoins($associations, $matching = [])
447448
$result = [];
448449
foreach ($matching as $table => $options) {
449450
$result[$table] = $options;
450-
$result += $this->_resolveJoins($options['associations'], []);
451+
$result += $this->_resolveJoins($options->associations(), []);
451452
}
452453
foreach ($associations as $table => $options) {
453454
$inMatching = isset($matching[$table]);
454-
if (!$inMatching && $options['canBeJoined']) {
455+
if (!$inMatching && $options->canBeJoined()) {
455456
$result[$table] = $options;
456-
$result += $this->_resolveJoins($options['associations'], $inMatching ? $mathching[$table] : []);
457+
$result += $this->_resolveJoins(
458+
$options->associations(),
459+
$inMatching ? $mathching[$table] : []
460+
);
457461
} else {
458-
$options['canBeJoined'] = false;
462+
$options->canBeJoined(false);
459463
$this->_loadExternal[] = $options;
460464
}
461465
}
@@ -481,21 +485,23 @@ public function loadExternal($query, $statement)
481485
$driver = $query->connection()->driver();
482486
list($collected, $statement) = $this->_collectKeys($external, $query, $statement);
483487
foreach ($external as $meta) {
484-
$contain = $meta['associations'];
485-
$alias = $meta['instance']->source()->alias();
488+
$contain = $meta->associations();
489+
$instance = $meta->instance();
490+
$config = $meta->config();
491+
$alias = $instance->source()->alias();
486492

487-
$requiresKeys = $meta['instance']->requiresKeys($meta['config']);
493+
$requiresKeys = $instance->requiresKeys($config);
488494
if ($requiresKeys && empty($collected[$alias])) {
489495
continue;
490496
}
491497

492498
$keys = isset($collected[$alias]) ? $collected[$alias] : null;
493-
$f = $meta['instance']->eagerLoader(
494-
$meta['config'] + [
499+
$f = $instance->eagerLoader(
500+
$config + [
495501
'query' => $query,
496502
'contain' => $contain,
497503
'keys' => $keys,
498-
'nestKey' => $meta['aliasPath']
504+
'nestKey' => $meta->aliasPath()
499505
]
500506
);
501507
$statement = new CallbackStatement($statement, $driver, $f);
@@ -528,16 +534,20 @@ public function associationsMap($table)
528534

529535
$visitor = function ($level, $matching = false) use (&$visitor, &$map) {
530536
foreach ($level as $assoc => $meta) {
537+
$canBeJoined = $meta->canBeJoined();
538+
$instance = $meta->instance();
539+
$associations = $meta->associations();
540+
$forMatching = $meta->forMatching();
531541
$map[] = [
532542
'alias' => $assoc,
533-
'instance' => $meta['instance'],
534-
'canBeJoined' => $meta['canBeJoined'],
535-
'entityClass' => $meta['instance']->target()->entityClass(),
536-
'nestKey' => $meta['canBeJoined'] ? $assoc : $meta['aliasPath'],
537-
'matching' => isset($meta['matching']) ? $meta['matching'] : $matching
543+
'instance' => $instance,
544+
'canBeJoined' => $canBeJoined,
545+
'entityClass' => $instance->target()->entityClass(),
546+
'nestKey' => $canBeJoined ? $assoc : $meta->aliasPath(),
547+
'matching' => $forMatching !== null ? $forMatching : $matching
538548
];
539-
if ($meta['canBeJoined'] && !empty($meta['associations'])) {
540-
$visitor($meta['associations'], $matching);
549+
if ($canBeJoined && $associations) {
550+
$visitor($associations, $matching);
541551
}
542552
}
543553
};
@@ -561,13 +571,12 @@ public function associationsMap($table)
561571
*/
562572
public function addToJoinsMap($alias, Association $assoc, $asMatching = false)
563573
{
564-
$this->_joinsMap[$alias] = [
574+
$this->_joinsMap[$alias] = new EagerLoadable($alias, [
565575
'aliasPath' => $alias,
566576
'instance' => $assoc,
567577
'canBeJoined' => true,
568-
'matching' => $asMatching,
569-
'associations' => []
570-
];
578+
'forMatching' => $asMatching,
579+
]);
571580
}
572581

573582
/**
@@ -583,13 +592,14 @@ protected function _collectKeys($external, $query, $statement)
583592
{
584593
$collectKeys = [];
585594
foreach ($external as $meta) {
586-
if (!$meta['instance']->requiresKeys($meta['config'])) {
595+
$instance = $meta->instance();
596+
if (!$instance->requiresKeys($meta->config())) {
587597
continue;
588598
}
589599

590-
$source = $meta['instance']->source();
591-
$keys = $meta['instance']->type() === $meta['instance']::MANY_TO_ONE ?
592-
(array)$meta['instance']->foreignKey() :
600+
$source = $instance->source();
601+
$keys = $instance->type() === Association::MANY_TO_ONE ?
602+
(array)$instance->foreignKey() :
593603
(array)$source->primaryKey();
594604

595605
$alias = $source->alias();

0 commit comments

Comments
 (0)