Seditio Source
Root |
./othercms/croogo-4.0.7/vendor/cakephp/cakephp/src/ORM/AssociationCollection.php
<?php
/**
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link          https://cakephp.org CakePHP(tm) Project
 * @since         3.0.0
 * @license       https://opensource.org/licenses/mit-license.php MIT License
 */
namespace Cake\ORM;

use
ArrayIterator;
use
Cake\Datasource\EntityInterface;
use
Cake\ORM\Locator\LocatorAwareTrait;
use
Cake\ORM\Locator\LocatorInterface;
use
InvalidArgumentException;
use
IteratorAggregate;

/**
 * A container/collection for association classes.
 *
 * Contains methods for managing associations, and
 * ordering operations around saving and deleting.
 */
class AssociationCollection implements IteratorAggregate
{
    use
AssociationsNormalizerTrait;
    use
LocatorAwareTrait;

   
/**
     * Stored associations
     *
     * @var \Cake\ORM\Association[]
     */
   
protected $_items = [];

   
/**
     * Constructor.
     *
     * Sets the default table locator for associations.
     * If no locator is provided, the global one will be used.
     *
     * @param \Cake\ORM\Locator\LocatorInterface|null $tableLocator Table locator instance.
     */
   
public function __construct(LocatorInterface $tableLocator = null)
    {
        if (
$tableLocator !== null) {
           
$this->_tableLocator = $tableLocator;
        }
    }

   
/**
     * Add an association to the collection
     *
     * If the alias added contains a `.` the part preceding the `.` will be dropped.
     * This makes using plugins simpler as the Plugin.Class syntax is frequently used.
     *
     * @param string $alias The association alias
     * @param \Cake\ORM\Association $association The association to add.
     * @return \Cake\ORM\Association The association object being added.
     */
   
public function add($alias, Association $association)
    {
        list(,
$alias) = pluginSplit($alias);

        return
$this->_items[strtolower($alias)] = $association;
    }

   
/**
     * Creates and adds the Association object to this collection.
     *
     * @param string $className The name of association class.
     * @param string $associated The alias for the target table.
     * @param array $options List of options to configure the association definition.
     * @return \Cake\ORM\Association
     * @throws \InvalidArgumentException
     */
   
public function load($className, $associated, array $options = [])
    {
       
$options += [
           
'tableLocator' => $this->getTableLocator(),
        ];

       
$association = new $className($associated, $options);
        if (!
$association instanceof Association) {
           
$message = sprintf('The association must extend `%s` class, `%s` given.', Association::class, get_class($association));
            throw new
InvalidArgumentException($message);
        }

        return
$this->add($association->getName(), $association);
    }

   
/**
     * Fetch an attached association by name.
     *
     * @param string $alias The association alias to get.
     * @return \Cake\ORM\Association|null Either the association or null.
     */
   
public function get($alias)
    {
       
$alias = strtolower($alias);
        if (isset(
$this->_items[$alias])) {
            return
$this->_items[$alias];
        }

        return
null;
    }

   
/**
     * Fetch an association by property name.
     *
     * @param string $prop The property to find an association by.
     * @return \Cake\ORM\Association|null Either the association or null.
     */
   
public function getByProperty($prop)
    {
        foreach (
$this->_items as $assoc) {
            if (
$assoc->getProperty() === $prop) {
                return
$assoc;
            }
        }

        return
null;
    }

   
/**
     * Check for an attached association by name.
     *
     * @param string $alias The association alias to get.
     * @return bool Whether or not the association exists.
     */
   
public function has($alias)
    {
        return isset(
$this->_items[strtolower($alias)]);
    }

   
/**
     * Get the names of all the associations in the collection.
     *
     * @return string[]
     */
   
public function keys()
    {
        return
array_keys($this->_items);
    }

   
/**
     * Get an array of associations matching a specific type.
     *
     * @param string|array $class The type of associations you want.
     *   For example 'BelongsTo' or array like ['BelongsTo', 'HasOne']
     * @return array An array of Association objects.
     * @deprecated 3.5.3 Use getByType() instead.
     */
   
public function type($class)
    {
       
deprecationWarning(
           
'AssociationCollection::type() is deprecated. ' .
           
'Use getByType() instead.'
       
);

        return
$this->getByType($class);
    }

   
/**
     * Get an array of associations matching a specific type.
     *
     * @param string|string[] $class The type of associations you want.
     *   For example 'BelongsTo' or array like ['BelongsTo', 'HasOne']
     * @return array An array of Association objects.
     * @since 3.5.3
     */
   
public function getByType($class)
    {
       
$class = array_map('strtolower', (array)$class);

       
$out = array_filter($this->_items, function ($assoc) use ($class) {
            list(,
$name) = namespaceSplit(get_class($assoc));

            return
in_array(strtolower($name), $class, true);
        });

        return
array_values($out);
    }

   
/**
     * Drop/remove an association.
     *
     * Once removed the association will not longer be reachable
     *
     * @param string $alias The alias name.
     * @return void
     */
   
public function remove($alias)
    {
        unset(
$this->_items[strtolower($alias)]);
    }

   
/**
     * Remove all registered associations.
     *
     * Once removed associations will not longer be reachable
     *
     * @return void
     */
   
public function removeAll()
    {
        foreach (
$this->_items as $alias => $object) {
           
$this->remove($alias);
        }
    }

   
/**
     * Save all the associations that are parents of the given entity.
     *
     * Parent associations include any association where the given table
     * is the owning side.
     *
     * @param \Cake\ORM\Table $table The table entity is for.
     * @param \Cake\Datasource\EntityInterface $entity The entity to save associated data for.
     * @param array $associations The list of associations to save parents from.
     *   associations not in this list will not be saved.
     * @param array $options The options for the save operation.
     * @return bool Success
     */
   
public function saveParents(Table $table, EntityInterface $entity, $associations, array $options = [])
    {
        if (empty(
$associations)) {
            return
true;
        }

        return
$this->_saveAssociations($table, $entity, $associations, $options, false);
    }

   
/**
     * Save all the associations that are children of the given entity.
     *
     * Child associations include any association where the given table
     * is not the owning side.
     *
     * @param \Cake\ORM\Table $table The table entity is for.
     * @param \Cake\Datasource\EntityInterface $entity The entity to save associated data for.
     * @param array $associations The list of associations to save children from.
     *   associations not in this list will not be saved.
     * @param array $options The options for the save operation.
     * @return bool Success
     */
   
public function saveChildren(Table $table, EntityInterface $entity, array $associations, array $options)
    {
        if (empty(
$associations)) {
            return
true;
        }

        return
$this->_saveAssociations($table, $entity, $associations, $options, true);
    }

   
/**
     * Helper method for saving an association's data.
     *
     * @param \Cake\ORM\Table $table The table the save is currently operating on
     * @param \Cake\Datasource\EntityInterface $entity The entity to save
     * @param array $associations Array of associations to save.
     * @param array $options Original options
     * @param bool $owningSide Compared with association classes'
     *   isOwningSide method.
     * @return bool Success
     * @throws \InvalidArgumentException When an unknown alias is used.
     */
   
protected function _saveAssociations($table, $entity, $associations, $options, $owningSide)
    {
        unset(
$options['associated']);
        foreach (
$associations as $alias => $nested) {
            if (
is_int($alias)) {
               
$alias = $nested;
               
$nested = [];
            }
           
$relation = $this->get($alias);
            if (!
$relation) {
               
$msg = sprintf(
                   
'Cannot save %s, it is not associated to %s',
                   
$alias,
                   
$table->getAlias()
                );
                throw new
InvalidArgumentException($msg);
            }
            if (
$relation->isOwningSide($table) !== $owningSide) {
                continue;
            }
            if (!
$this->_save($relation, $entity, $nested, $options)) {
                return
false;
            }
        }

        return
true;
    }

   
/**
     * Helper method for saving an association's data.
     *
     * @param \Cake\ORM\Association $association The association object to save with.
     * @param \Cake\Datasource\EntityInterface $entity The entity to save
     * @param array $nested Options for deeper associations
     * @param array $options Original options
     * @return bool Success
     */
   
protected function _save($association, $entity, $nested, $options)
    {
        if (!
$entity->isDirty($association->getProperty())) {
            return
true;
        }
        if (!empty(
$nested)) {
           
$options = (array)$nested + $options;
        }

        return (bool)
$association->saveAssociated($entity, $options);
    }

   
/**
     * Cascade a delete across the various associations.
     * Cascade first across associations for which cascadeCallbacks is true.
     *
     * @param \Cake\Datasource\EntityInterface $entity The entity to delete associations for.
     * @param array $options The options used in the delete operation.
     * @return void
     */
   
public function cascadeDelete(EntityInterface $entity, array $options)
    {
       
$noCascade = $this->_getNoCascadeItems($entity, $options);
        foreach (
$noCascade as $assoc) {
           
$assoc->cascadeDelete($entity, $options);
        }
    }

   
/**
     * Returns items that have no cascade callback.
     *
     * @param \Cake\Datasource\EntityInterface $entity The entity to delete associations for.
     * @param array $options The options used in the delete operation.
     * @return \Cake\ORM\Association[]
     */
   
protected function _getNoCascadeItems($entity, $options)
    {
       
$noCascade = [];
        foreach (
$this->_items as $assoc) {
            if (!
$assoc->getCascadeCallbacks()) {
               
$noCascade[] = $assoc;
                continue;
            }
           
$assoc->cascadeDelete($entity, $options);
        }

        return
$noCascade;
    }

   
/**
     * Returns an associative array of association names out a mixed
     * array. If true is passed, then it returns all association names
     * in this collection.
     *
     * @param bool|array $keys the list of association names to normalize
     * @return array
     */
   
public function normalizeKeys($keys)
    {
        if (
$keys === true) {
           
$keys = $this->keys();
        }

        if (empty(
$keys)) {
            return [];
        }

        return
$this->_normalizeAssociations($keys);
    }

   
/**
     * Allow looping through the associations
     *
     * @return \ArrayIterator
     */
   
public function getIterator()
    {
        return new
ArrayIterator($this->_items);
    }
}