Skip to content
Permalink
Browse files

Migrated HasMany to use the new SelectLoader

  • Loading branch information...
lorenzo committed Oct 10, 2016
1 parent d66a254 commit 4955a516ced0140096a3e320abee7987004de8de
@@ -750,6 +750,20 @@ public function deleteAll($conditions)
return $target->deleteAll($expression);
}
/**
* Returns true if the eager loading process will require a set of the owning table's
* binding keys in order to use them as a filter in the finder query.
*
* @param array $options The options containing the strategy to be used.
* @return bool true if a list of keys will be required
*/
public function requiresKeys(array $options = [])
{
$strategy = isset($options['strategy']) ? $options['strategy'] : $this->strategy();
return $strategy === $this::STRATEGY_SELECT;
}
/**
* Triggers beforeFind on the target table for the query this association is
* attaching to
@@ -1026,15 +1040,6 @@ public function __call($method, $argument)
*/
abstract public function eagerLoader(array $options);
/**
* Returns true if the eager loading process will require a set of the owning table's
* binding keys in order to use them as a filter in the finder query.
*
* @param array $options The options containing the strategy to be used.
* @return bool true if a list of keys will be required
*/
abstract function requiresKeys(array $options = []);
/**
* Handles cascading a delete from an associated model.
*
@@ -202,54 +202,4 @@ public function eagerLoader(array $options) {
return $loader->buildLoadingQuery($options);
}
/**
* {@inheritDoc}
*
* @return bool
*/
public function requiresKeys(array $options = [])
{
$strategy = isset($options['strategy']) ? $options['strategy'] : $this->strategy();
return $strategy === $this::STRATEGY_SELECT;
}
/**
* {@inheritDoc}
*/
protected function _linkField($options)
{
$links = [];
$name = $this->alias();
foreach ((array)$this->bindingKey() as $key) {
$links[] = sprintf('%s.%s', $name, $key);
}
if (count($links) === 1) {
return $links[0];
}
return $links;
}
/**
* {@inheritDoc}
*/
protected function _buildResultMap($fetchQuery, $options)
{
$resultMap = [];
$key = (array)$this->bindingKey();
foreach ($fetchQuery->all() as $result) {
$values = [];
foreach ($key as $k) {
$values[] = $result[$k];
}
$resultMap[implode(';', $values)] = $result;
}
return $resultMap;
}
}
@@ -20,9 +20,9 @@
use Cake\Database\Expression\QueryExpression;
use Cake\Datasource\EntityInterface;
use Cake\ORM\Association;
use Cake\ORM\Association\Loader\SelectLoader;
use Cake\ORM\Table;
use InvalidArgumentException;
use RuntimeException;
use Traversable;
/**
@@ -35,7 +35,13 @@ class HasMany extends Association
{
use DependentDeleteTrait;
use ExternalAssociationTrait;
/**
* Order in which target records should be returned
*
* @var mixed
*/
protected $_sort;
/**
* The type of join to be used when adding the association to a query
@@ -491,37 +497,74 @@ function ($prop) use ($table) {
}
/**
* {@inheritDoc}
* Get the relationship type.
*
* @return string
*/
protected function _linkField($options)
public function type()
{
$links = [];
$name = $this->alias();
if ($options['foreignKey'] === false) {
$msg = 'Cannot have foreignKey = false for hasMany associations. ' .
'You must provide a foreignKey column.';
throw new RuntimeException($msg);
}
return self::ONE_TO_MANY;
}
foreach ((array)$options['foreignKey'] as $key) {
$links[] = sprintf('%s.%s', $name, $key);
}
/**
* Whether this association can be expressed directly in a query join
*
* @param array $options custom options key that could alter the return value
* @return bool if the 'matching' key in $option is true then this function
* will return true, false otherwise
*/
public function canBeJoined(array $options = [])
{
return !empty($options['matching']);
}
if (count($links) === 1) {
return $links[0];
/**
* Sets the name of the field representing the foreign key to the source table.
* If no parameters are passed current field is returned
*
* @param string|null $key the key to be used to link both tables together
* @return string
*/
public function foreignKey($key = null)
{
if ($key === null) {
if ($this->_foreignKey === null) {
$this->_foreignKey = $this->_modelKey($this->source()->table());
}
return $this->_foreignKey;
}
return $links;
return parent::foreignKey($key);
}
/**
* Get the relationship type.
* Sets the sort order in which target records should be returned.
* If no arguments are passed the currently configured value is returned
*
* @return string
* @param mixed $sort A find() compatible order clause
* @return mixed
*/
public function type()
public function sort($sort = null)
{
return self::ONE_TO_MANY;
if ($sort !== null) {
$this->_sort = $sort;
}
return $this->_sort;
}
/**
* {@inheritDoc}
*/
public function defaultRowValue($row, $joined)
{
$sourceAlias = $this->source()->alias();
if (isset($row[$sourceAlias])) {
$row[$sourceAlias][$this->property()] = $joined ? null : [];
}
return $row;
}
/**
@@ -539,4 +582,25 @@ protected function _options(array $opts)
$this->sort($opts['sort']);
}
}
/**
* {@inheritDoc}
*
* @return callable
*/
public function eagerLoader(array $options) {
$loader = new SelectLoader([
'alias' => $this->alias(),
'sourceAlias' => $this->source()->alias(),
'targetAlias' => $this->target()->alias(),
'foreignKey' => $this->foreignKey(),
'bindingKey' => $this->bindingKey(),
'strategy' => $this->strategy(),
'associationType' => $this->type(),
'sort' => $this->sort(),
'finder' => [$this, 'find']
]);
return $loader->buildLoadingQuery($options);
}
}
@@ -147,16 +147,4 @@ public function eagerLoader(array $options) {
return $loader->buildLoadingQuery($options);
}
/**
* {@inheritDoc}
*
* @return bool
*/
public function requiresKeys(array $options = [])
{
$strategy = isset($options['strategy']) ? $options['strategy'] : $this->strategy();
return $strategy === $this::STRATEGY_SELECT;
}
}
@@ -19,6 +19,7 @@
use Cake\Database\ValueBinder;
use InvalidArgumentException;
use Cake\ORM\Association;
use RuntimeException;
/**
* Implements the logic for loading an association using a SELECT query
@@ -42,6 +43,8 @@ class SelectLoader
protected $associationType;
protected $sort;
public function __construct(array $options)
{
$this->alias = $options['alias'];
@@ -52,6 +55,7 @@ public function __construct(array $options)
$this->bindingKey = $options['bindingKey'];
$this->finder = $options['finder'];
$this->associationType = $options['associationType'];
$this->sort = isset($options['sort']) ? $options['sort'] : null;
}
@@ -75,7 +79,8 @@ protected function _defaultOptions()
'foreignKey' => $this->foreignKey,
'conditions' => [],
'strategy' => $this->strategy,
'nestKey' => $this->alias
'nestKey' => $this->alias,
'sort' => $this->sort
];
}
@@ -265,7 +270,14 @@ protected function _linkField($options)
{
$links = [];
$name = $this->alias;
$keys = $this->associationType === Association::ONE_TO_ONE ?
if ($options['foreignKey'] === false && $this->associationType === Association::ONE_TO_MANY) {
$msg = 'Cannot have foreignKey = false for hasMany associations. ' .
'You must provide a foreignKey column.';
throw new RuntimeException($msg);
}
$keys = in_array($this->associationType, [Association::ONE_TO_ONE, Association::ONE_TO_MANY]) ?
$this->foreignKey :
$this->bindingKey;
@@ -354,7 +366,8 @@ protected function _subqueryFields($query)
protected function _buildResultMap($fetchQuery, $options)
{
$resultMap = [];
$keys = $this->associationType === Association::ONE_TO_ONE ?
$singleResult = in_array($this->associationType, [Association::MANY_TO_ONE, Association::ONE_TO_ONE]);
$keys = in_array($this->associationType, [Association::ONE_TO_ONE, Association::ONE_TO_MANY]) ?
$this->foreignKey :
$this->bindingKey;
$key = (array)$keys;
@@ -364,7 +377,11 @@ protected function _buildResultMap($fetchQuery, $options)
foreach ($key as $k) {
$values[] = $result[$k];
}
$resultMap[implode(';', $values)] = $result;
if ($singleResult) {
$resultMap[implode(';', $values)] = $result;
} else {
$resultMap[implode(';', $values)][] = $result;
}
}
return $resultMap;

0 comments on commit 4955a51

Please sign in to comment.
You can’t perform that action at this time.