One2One::__get()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 9
rs 9.6666
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
/**
3
 * Fwk
4
 *
5
 * Copyright (c) 2011-2012, Julien Ballestracci <[email protected]>.
6
 * All rights reserved.
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 *
11
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
12
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
13
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
14
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
15
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
16
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
17
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
19
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
21
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
22
 * POSSIBILITY OF SUCH DAMAGE.
23
 *
24
 * PHP Version 5.3
25
 * 
26
 * @category  Database
27
 * @package   Fwk\Db
28
 * @author    Julien Ballestracci <[email protected]>
29
 * @copyright 2011-2012 Julien Ballestracci <[email protected]>
30
 * @license   http://www.opensource.org/licenses/bsd-license.php  BSD License
31
 * @link      http://www.phpfwk.com
32
 */
33
namespace Fwk\Db\Relations;
34
35
use Fwk\Db\Events\AbstractEntityEvent;
36
use Fwk\Db\Events\BeforeSaveEvent;
37
use Fwk\Db\Events\BeforeUpdateEvent;
38
use Fwk\Db\RelationInterface;
39
use Fwk\Db\Query;
40
use Fwk\Db\Accessor;
41
use Fwk\Db\Registry\Registry;
42
use Fwk\Db\Workers\SaveEntityWorker;
43
use Fwk\Db\Workers\DeleteEntityWorker;
44
use Fwk\Events\Dispatcher;
45
46
/**
47
 * Represents a One --> One database relation.
48
 *
49
 * @category Relations
50
 * @package  Fwk\Db
51
 * @author   Julien Ballestracci <[email protected]>
52
 * @license  http://www.opensource.org/licenses/bsd-license.php  BSD License
53
 * @link     http://www.phpfwk.com
54
 */
55
class One2One extends AbstractRelation implements RelationInterface
56
{
57
    /**
58
     * Prepares a Query to fetch this relation (only FETCH_EAGER)
59
     *
60
     * @param Query  $query      The query
61
     * @param string $columnName Column name on the parent entity
62
     *
63
     * @return void
64
     */
65
    public function prepare(Query $query, $columnName)
66
    {
67
        if ($this->isLazy()) {
68
            return; 
69
        }
70
71
        $this->columnName = $columnName;
72
        $join = array(
73
            'column'    => $this->columnName,
74
            'relation'  => $this,
75
            'skipped'   => false,
76
            'reference' => null,
77
            'entity'    => $this->getEntity()
78
        );
79
80
        $query->join(
81
            $this->getTableName(),
82
            $this->getLocal(),
83
            $this->getForeign(),
84
            Query::JOIN_LEFT, 
85
            $join
86
        );
87
    }
88
89
    /**
90
     * Fetches (if necessary) relation's entities
91
     * 
92
     * @return One2One
93
     */
94
    public function fetch()
95
    {
96
        if (!$this->fetched && $this->isActive()) {
97
            $query = new Query();
98
            $query->entity($this->getEntity());
99
100
            $query->select()
101
                ->from($this->getTableName(), 'lazy')
102
                ->where('lazy.'. $this->getForeign() .'=?');
103
104
            $connect    = $this->getConnection();
105
            $res        = $connect->execute($query, array($this->parentRefs));
106
            $idKeys     = $connect->table($this->getTableName())
107
                ->getIdentifiersKeys();
108
109
            if (count($res) >= 1) {
110
                $ids     = array();
111
                $access  = new Accessor($res[0]);
112
                foreach ($idKeys as $key) {
113
                    $ids[$key] = $access->get($key);
114
                }
115
                parent::add($res[0], $ids);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (add() instead of fetch()). Are you sure this is correct? If so, you might want to change this to $this->add().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
116
            }
117
118
            $this->setFetched(true);
119
        }
120
121
        return $this;
122
    }
123
124
    /**
125
     * Fetches and return the entity (or null)
126
     *
127
     * @return mixed
128
     */
129
    public function get()
130
    {
131
        $this->fetch();
132
133
        foreach ($this->getRegistry()->getStore() as $entry) {
134
            return $entry->getObject();
135
        }
136
137
        return null;
138
    }
139
140
    /**
141
     * Defines the $object as the One.
142
     * 
143
     * If $object is null, the relation is canceled on the parent object
144
     * 
145
     * @param mixed $object Entity
146
     * 
147
     * @return void 
148
     */
149
    public function set($object = null)
150
    {
151
        if (null === $object) {
152
            foreach ($this->getRegistry()->getStore() as $entry) {
153
                $this->remove($entry->getObject());
154
            }
155
156
            return;
157
        }
158
159
        parent::add($object);
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (add() instead of set()). Are you sure this is correct? If so, you might want to change this to $this->add().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
160
    }
161
162
    /**
163
     * Magic method to allow $parent->relation->propName;
164
     * Returns value from the linked object.
165
     * 
166
     * @param string $key Property/Column name
167
     * 
168
     * @throws \RuntimeException if relation is empty
169
     * @return mixed 
170
     */
171
    public function __get($key)
172
    {
173
        $obj = $this->get();
174
        if (!\is_object($obj)) {
175
            throw new \RuntimeException('Empty relation');
176
        }
177
        
178
        return Accessor::factory($obj)->get($key);
179
    }
180
181
    /**
182
     * Magic method to allow $parent->relation->propName = "value"
183
     * 
184
     * @param string $key   Property/Column name
185
     * @param mixed  $value The value
186
     * 
187
     * @return void 
188
     */
189
    public function __set($key, $value)
190
    {
191
        $obj    = $this->get();
192
        if (!\is_object($obj)) {
193
            throw new \RuntimeException('Empty relation');
194
        }
195
        
196
        Accessor::factory($obj)->set($key, $value);
197
    }
198
199
    /**
200
     * Magic method to allow isset($parent->relation->propName)
201
     * 
202
     * @param string $key Property/Column name
203
     * 
204
     * @return boolean 
205
     */
206
    public function __isset($key)
0 ignored issues
show
Coding Style introduced by
function __isset() does not seem to conform to the naming convention (^(?:is|has|should|may|su...ster|unregister|exists)).

This check examines a number of code elements and verifies that they conform to the given naming conventions.

You can set conventions for local variables, abstract classes, utility classes, constant, properties, methods, parameters, interfaces, classes, exceptions and special methods.

Loading history...
207
    {
208
        $obj    = $this->fetch();
209
        if (!\is_object($obj)) {
210
            throw new \RuntimeException('Empty relation');
211
        }
212
        
213
        $test = Accessor::factory($obj)->get($key);
214
215
        return ($test != false ? true : false);
216
    }
217
218
    /**
219
     * Magic method to allow calling methods like $parent->relation->call()
220
     * 
221
     * @param string $name      Method name
222
     * @param array  $arguments Call arguments
223
     * 
224
     * @return mixed 
225
     */
226
    public function __call($name, $arguments)
227
    {
228
        $obj = $this->get();
229
        if (!\is_object($obj)) {
230
            throw new \RuntimeException('Empty relation');
231
        }
232
        
233
        $access = new Accessor($obj);
234
        try {
235
            $access->getReflector()->getMethod($name);
236
237
            return \call_user_func_array(array($obj, $name), $arguments);
238
        } catch (\ReflectionException $e) {
239
            throw new \RuntimeException(
240
                sprintf(
241
                    'Unable to call method %s::%s(): %s', 
242
                    get_class($obj), 
243
                    $name, 
244
                    $e->getMessage()
245
                )
246
            );
247
        }
248
    }
249
250
    /**
251
     * Defines a parent object (the other One) 
252
     * 
253
     * @param mixed      $object The parent object
254
     * @param Dispatcher $evd    The related Events Dispatcher
255
     * 
256
     * @return boolean
257
     */
258
    public function setParent($object, Dispatcher $evd)
259
    {
260
        $return = parent::setParent($object, $evd);
261
        if ($return === true) {
262
            $evd->on(BeforeSaveEvent::EVENT_NAME, array($this, 'onBeforeParentSave'));
263
            $evd->on(BeforeUpdateEvent::EVENT_NAME, array($this, 'onBeforeParentSave'));
264
        }
265
266
        return $return;
267
    }
268
269
    /**
270
     * Listener executed when parent entity is saved
271
     *
272
     * @param AbstractEntityEvent $event Dispatched event
273
     * 
274
     * @return void
275
     */
276
    public function onBeforeParentSave(AbstractEntityEvent $event)
277
    {
278
        $connection = $event->getConnection();
279
        $parent     = $event->getEntity();
280
281
        foreach ($this->getWorkersQueue() as $worker) {
282
            $worker->setRegistry($this->registry);
283
            $entity = $worker->getEntity();
284
285
            if ($worker instanceof SaveEntityWorker) {
286
                $worker->execute($connection);
287
                $current = Accessor::factory($entity)->get($this->foreign);
288
                Accessor::factory($parent)->set($this->local, $current);
289
                $this->getRegistry()->defineInitialValues(
290
                    $entity,
291
                    $connection,
292
                    $connection->table($this->tableName)
293
                );
294
            }
295
296
            if ($worker instanceof DeleteEntityWorker) {
297
                Accessor::factory($parent)->set($this->local, null);
298
                $this->getRegistry()->remove($entity);
299
            }
300
        }
301
    }
302
303
    /**
304
     * Returns an array of all entities in this relation
305
     *
306
     * @return array
307
     */
308
    public function toArray()
309
    {
310
        $this->fetch();
311
312
        $final = array();
313
        $list = $this->getRegistry()->getStore();
314
        foreach ($list as $entry) {
315
            if ($entry->getAction() == Registry::ACTION_DELETE) {
316
                continue;
317
            }
318
319
            $final[] = $entry->getObject();
320
        }
321
322
        return $final;
323
    }
324
}
325