Completed
Push — master ( 567095...50e176 )
by Joschi
03:03
created

ObjectProxy::addAuthor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
ccs 0
cts 4
cp 0
crap 2
1
<?php
2
3
/**
4
 * apparat-object
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Object
8
 * @subpackage  Apparat\Object\Domain
9
 * @author      Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright   Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license     http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Apparat\Object\Domain\Model\Object;
38
39
use Apparat\Kernel\Ports\Kernel;
40
use Apparat\Object\Domain\Model\Path\ApparatUrl;
41
use Apparat\Object\Domain\Model\Path\PathInterface;
42
use Apparat\Object\Domain\Repository\Service;
43
44
/**
45
 * Object proxy (lazy loading)
46
 *
47
 * @package Apparat\Object
48
 * @subpackage Apparat\Object\Domain
49
 */
50
class ObjectProxy implements ObjectInterface
51
{
52
    /**
53
     * Apparat object URL
54
     *
55
     * @var ApparatUrl
56
     */
57
    protected $url = null;
58
    /**
59
     * Object
60
     *
61
     * @var ObjectInterface
62
     */
63
    protected $object = null;
64
65
    /*******************************************************************************
66
     * PUBLIC METHODS
67
     *******************************************************************************/
68
69
    /**
70
     * Object proxy constructor
71
     *
72
     * @param ApparatUrl $url Apparat object URL
73
     */
74
    public function __construct(ApparatUrl $url)
75
    {
76
        $this->url = $url;
77
    }
78
79
    /**
80
     * Return the object repository path
81
     *
82
     * @return PathInterface Object repository path
83
     */
84
    public function getRepositoryPath()
85
    {
86
        // If the object has already been instantiated
87
        if ($this->object instanceof ObjectInterface) {
88
            return $this->object->getRepositoryPath();
89
90
            // Else
91
        } else {
92
            return $this->url->getLocalPath();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->url->getLocalPath(); (Apparat\Object\Domain\Model\Path\LocalPath) is incompatible with the return type declared by the interface Apparat\Object\Domain\Mo...face::getRepositoryPath of type Apparat\Object\Domain\Mo...RepositoryPathInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
93
        }
94
    }
95
96
    /**
97
     * Return the object property data
98
     *
99
     * @return array Object property data
100
     */
101
    public function getPropertyData()
102
    {
103
        return $this->object()->getPropertyData();
104
    }
105
106
    /**
107
     * Return the enclosed remote object
108
     *
109
     * @return ObjectInterface Remote object
110
     */
111
    protected function object()
112
    {
113
        // Lazy-load the remote object if necessary
114
        if (!$this->object instanceof ObjectInterface) {
115
            // Instantiate the local object repository, load and return the object
116
            $this->object = Kernel::create(Service::class)->get($this->url)->loadObject($this->url->getLocalPath());
117
        }
118
119
        return $this->object;
120
    }
121
122
    /**
123
     * Return the object payload
124
     *
125
     * @return string Object payload
126
     */
127
    public function getPayload()
128
    {
129
        return $this->object()->getPayload();
130
    }
131
132
    /**
133
     * Set the payload
134
     *
135
     * @param string $payload Payload
136
     * @return ObjectInterface Self reference
137
     */
138
    public function setPayload($payload)
139
    {
140
        return $this->object()->setPayload($payload);
141
    }
142
143
    /**
144
     * Return the object ID
145
     *
146
     * @return Id Object ID
147
     */
148
    public function getId()
149
    {
150
        return $this->object()->getId();
151
    }
152
153
    /**
154
     * Return the object type
155
     *
156
     * @return Type Object type
157
     */
158
    public function getType()
159
    {
160
        return $this->object()->getType();
161
    }
162
163
    /**
164
     * Return the object revision
165
     *
166
     * @return Revision Object revision
167
     */
168
    public function getRevision()
169
    {
170
        return $this->object()->getRevision();
171
    }
172
173
    /**
174
     * Return the object draft mode
175
     *
176
     * @return boolean Object draft mode
177
     */
178
    public function isDraft()
179
    {
180
        return $this->object()->isDraft();
181
    }
182
183
    /**
184
     * Return whether the object is in dirty state
185
     *
186
     * @return boolean Dirty state
187
     */
188
    public function isDirty()
189
    {
190
        return $this->object()->isDirty();
191
    }
192
193
    /**
194
     * Return whether the object is in mutated state
195
     *
196
     * @return boolean Mutated state
197
     */
198
    public function isMutated()
199
    {
200
        return $this->object()->isMutated();
201
    }
202
203
    /**
204
     * Return the creation date & time
205
     *
206
     * @return \DateTimeImmutable Creation date & time
207
     */
208
    public function getCreated()
209
    {
210
        return $this->object()->getCreated();
211
    }
212
213
    /**
214
     * Return the publication date & time
215
     *
216
     * @return \DateTimeImmutable Publication date & time
217
     */
218
    public function getPublished()
219
    {
220
        return $this->object()->getPublished();
221
    }
222
223
    /**
224
     * Return the object hash
225
     *
226
     * @return string Object hash
227
     */
228
    public function getHash()
229
    {
230
        return $this->object()->getHash();
231
    }
232
233
    /**
234
     * Return the object title
235
     *
236
     * @return string Object title
237
     */
238
    public function getTitle()
239
    {
240
        return $this->object()->getTitle();
241
    }
242
243
    /**
244
     * Set the title
245
     *
246
     * @param string $title Title
247
     * @return ObjectInterface Self reference
248
     */
249
    public function setTitle($title)
250
    {
251
        return $this->object()->setTitle($title);
252
    }
253
254
    /**
255
     * Return the object slug
256
     *
257
     * @return string Object slug
258
     */
259
    public function getSlug()
260
    {
261
        return $this->object()->getSlug();
262
    }
263
264
    /**
265
     * Set the slug
266
     *
267
     * @param string $slug Slug
268
     * @return ObjectInterface Self reference
269
     */
270
    public function setSlug($slug)
271
    {
272
        return $this->object()->setSlug($slug);
273
    }
274
275
276
    /**
277
     * Return the object description
278
     *
279
     * @return string Object description
280
     */
281
    public function getDescription()
282
    {
283
        return $this->object()->getDescription();
284
    }
285
286
    /**
287
     * Set the description
288
     *
289
     * @param string $description Description
290
     * @return ObjectInterface Self reference
291
     */
292
    public function setDescription($description)
293
    {
294
        return $this->object()->setDescription($description);
295
    }
296
297
    /**
298
     * Return the object abstract
299
     *
300
     * @return string Object abstract
301
     */
302
    public function getAbstract()
303
    {
304
        return $this->object()->getAbstract();
305
    }
306
307
    /**
308
     * Set the abstract
309
     *
310
     * @param string $abstract Abstract
311
     * @return ObjectInterface Self reference
312
     */
313
    public function setAbstract($abstract)
314
    {
315
        return $this->object()->setAbstract($abstract);
316
    }
317
318
    /**
319
     * Return all object keywords
320
     *
321
     * @return array Object keywords
322
     */
323
    public function getKeywords()
324
    {
325
        return $this->object()->getKeywords();
326
    }
327
328
    /**
329
     * Set the keywords
330
     *
331
     * @param array $keywords Keywords
332
     * @return ObjectInterface Self reference
333
     */
334
    public function setKeywords(array $keywords)
335
    {
336
        return $this->object()->setKeywords($keywords);
337
    }
338
339
    /**
340
     * Return all object categories
341
     *
342
     * @return array Object categories
343
     */
344
    public function getCategories()
345
    {
346
        return $this->object()->getCategories();
347
    }
348
349
    /**
350
     * Set the categories
351
     *
352
     * @param array $categories Categories
353
     * @return ObjectInterface Self reference
354
     */
355
    public function setCategories(array $categories)
356
    {
357
        return $this->object()->setCategories($categories);
358
    }
359
360
    /**
361
     * Get a domain property value
362
     *
363
     * Multi-level properties might be traversed by property name paths separated with colons (":").
364
     *
365
     * @param string $property Property name
366
     * @return mixed Property value
367
     */
368
    public function getDomainProperty($property)
369
    {
370
        return $this->object()->getDomainProperty($property);
371
    }
372
373
    /**
374
     * Set a domain property value
375
     *
376
     * @param string $property Property name
377
     * @param mixed $value Property value
378
     * @return ObjectInterface Self reference
379
     */
380
    public function setDomainProperty($property, $value)
381
    {
382
        return $this->object()->setDomainProperty($property, $value);
383
    }
384
385
    /**
386
     * Get a processing instruction
387
     *
388
     * @param string $procInst Processing instruction name
389
     * @return mixed Processing instruction
390
     */
391
    public function getProcessingInstruction($procInst)
392
    {
393
        return $this->object()->getProcessingInstruction($procInst);
394
    }
395
396
    /**
397
     * Set a processing instruction
398
     *
399
     * @param string $procInst Processing instruction name
400
     * @param mixed $value Processing instruction
401
     * @return ObjectInterface Self reference
402
     */
403
    public function setProcessingInstruction($procInst, $value)
404
    {
405
        return $this->object()->setProcessingInstruction($procInst, $value);
406
    }
407
408
    /**
409
     * Return the absolute object URL
410
     *
411
     * @return string
412
     */
413
    public function getAbsoluteUrl()
414
    {
415
        return strval($this->url);
416
    }
417
418
    /**
419
     * Generic caller
420
     *
421
     * @param string $name Method name
422
     * @param array $arguments Method arguments
423
     */
424
    public function __call($name, $arguments)
425
    {
426
        $object = $this->object();
427
        if (is_callable(array($object, $name))) {
428
            return $object->$name(...$arguments);
429
        }
430
431
        throw new InvalidArgumentException(
432
            sprintf('Invalid object proxy method "%s"', $name),
433
            InvalidArgumentException::INVALID_OBJECT_PROXY_METHOD
434
        );
435
    }
436
437
    /**
438
     * Use a specific object revision
439
     *
440
     * @param Revision $revision Revision to be used
441
     * @return ObjectInterface Object
442
     */
443
    public function useRevision(Revision $revision)
444
    {
445
        return $this->object()->useRevision($revision);
446
    }
447
448
    /**
449
     * Persist the current object revision
450
     *
451
     * @return ObjectInterface Object
452
     */
453
    public function persist()
454
    {
455
        return $this->object()->persist();
456
    }
457
458
    /**
459
     * Return whether the object is in published state
460
     *
461
     * @return boolean Published state
462
     */
463
    public function isPublished()
464
    {
465
        return $this->object()->isPublished();
466
    }
467
468
    /**
469
     * Publish the current object revision
470
     *
471
     * @return ObjectInterface Object
472
     */
473
    public function publish()
474
    {
475
        return $this->object()->publish();
476
    }
477
478
479
}
480