1: <?php
2: /**
3: * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4: * Copyright (c) Cake Software Foundation, Inc. (https://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. (https://cakefoundation.org)
11: * @link https://cakephp.org CakePHP(tm) Project
12: * @since 3.0.0
13: * @license https://opensource.org/licenses/mit-license.php MIT License
14: */
15: namespace Cake\ORM\Association;
16:
17: use Cake\Datasource\EntityInterface;
18: use Cake\ORM\Association;
19: use Cake\ORM\Association\DependentDeleteHelper;
20: use Cake\ORM\Association\Loader\SelectLoader;
21: use Cake\ORM\Table;
22: use Cake\Utility\Inflector;
23:
24: /**
25: * Represents an 1 - 1 relationship where the source side of the relation is
26: * related to only one record in the target table and vice versa.
27: *
28: * An example of a HasOne association would be User has one Profile.
29: */
30: class HasOne extends Association
31: {
32: /**
33: * Valid strategies for this type of association
34: *
35: * @var array
36: */
37: protected $_validStrategies = [
38: self::STRATEGY_JOIN,
39: self::STRATEGY_SELECT
40: ];
41:
42: /**
43: * Gets the name of the field representing the foreign key to the target table.
44: *
45: * @return string
46: */
47: public function getForeignKey()
48: {
49: if ($this->_foreignKey === null) {
50: $this->_foreignKey = $this->_modelKey($this->getSource()->getAlias());
51: }
52:
53: return $this->_foreignKey;
54: }
55:
56: /**
57: * Returns default property name based on association name.
58: *
59: * @return string
60: */
61: protected function _propertyName()
62: {
63: list(, $name) = pluginSplit($this->_name);
64:
65: return Inflector::underscore(Inflector::singularize($name));
66: }
67:
68: /**
69: * Returns whether or not the passed table is the owning side for this
70: * association. This means that rows in the 'target' table would miss important
71: * or required information if the row in 'source' did not exist.
72: *
73: * @param \Cake\ORM\Table $side The potential Table with ownership
74: * @return bool
75: */
76: public function isOwningSide(Table $side)
77: {
78: return $side === $this->getSource();
79: }
80:
81: /**
82: * Get the relationship type.
83: *
84: * @return string
85: */
86: public function type()
87: {
88: return self::ONE_TO_ONE;
89: }
90:
91: /**
92: * Takes an entity from the source table and looks if there is a field
93: * matching the property name for this association. The found entity will be
94: * saved on the target table for this association by passing supplied
95: * `$options`
96: *
97: * @param \Cake\Datasource\EntityInterface $entity an entity from the source table
98: * @param array $options options to be passed to the save method in the target table
99: * @return bool|\Cake\Datasource\EntityInterface false if $entity could not be saved, otherwise it returns
100: * the saved entity
101: * @see \Cake\ORM\Table::save()
102: */
103: public function saveAssociated(EntityInterface $entity, array $options = [])
104: {
105: $targetEntity = $entity->get($this->getProperty());
106: if (empty($targetEntity) || !($targetEntity instanceof EntityInterface)) {
107: return $entity;
108: }
109:
110: $properties = array_combine(
111: (array)$this->getForeignKey(),
112: $entity->extract((array)$this->getBindingKey())
113: );
114: $targetEntity->set($properties, ['guard' => false]);
115:
116: if (!$this->getTarget()->save($targetEntity, $options)) {
117: $targetEntity->unsetProperty(array_keys($properties));
118:
119: return false;
120: }
121:
122: return $entity;
123: }
124:
125: /**
126: * {@inheritDoc}
127: *
128: * @return \Closure
129: */
130: public function eagerLoader(array $options)
131: {
132: $loader = new SelectLoader([
133: 'alias' => $this->getAlias(),
134: 'sourceAlias' => $this->getSource()->getAlias(),
135: 'targetAlias' => $this->getTarget()->getAlias(),
136: 'foreignKey' => $this->getForeignKey(),
137: 'bindingKey' => $this->getBindingKey(),
138: 'strategy' => $this->getStrategy(),
139: 'associationType' => $this->type(),
140: 'finder' => [$this, 'find']
141: ]);
142:
143: return $loader->buildEagerLoader($options);
144: }
145:
146: /**
147: * {@inheritDoc}
148: */
149: public function cascadeDelete(EntityInterface $entity, array $options = [])
150: {
151: $helper = new DependentDeleteHelper();
152:
153: return $helper->cascadeDelete($this, $entity, $options);
154: }
155: }
156: