Completed
Push — master ( d20124...0fac02 )
by Joschi
03:11
created

AbstractResource::callGetterPartMethod()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 2
rs 10
1
<?php
2
3
/**
4
 * apparat-resource
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Resource
8
 * @subpackage Apparat\Resource\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\Resource\Domain\Model\Resource;
38
39
use Apparat\Resource\Domain\Contract\ReaderInterface;
40
use Apparat\Resource\Domain\Contract\WriterInterface;
41
use Apparat\Resource\Domain\Factory\HydratorFactory;
42
use Apparat\Resource\Domain\Model\Hydrator\HydratorInterface;
43
use Apparat\Resource\Domain\Model\Part\AbstractPart;
44
use Apparat\Resource\Domain\Model\Part\PartInterface;
45
46
/**
47
 * File
48
 *
49
 * @package     Apparat\Resource
50
 * @subpackage Apparat\Resource\Domain
51
 * @method string getMediaTypePart($part = '/') getMediaTypePart($part = '/') Get the media type of a particular part
52
 */
53
abstract class AbstractResource
54
{
55
    /**
56
     * Part or part aggregate
57
     *
58
     * @var PartInterface
59
     */
60
    protected $part = null;
61
62
    /**
63
     * Reader instance
64
     *
65
     * @var ReaderInterface
66
     */
67
    protected $reader = null;
68
    /**
69
     * File hydrator
70
     *
71
     * @var HydratorInterface
72
     */
73
    private $hydrator = null;
74
75
    /*******************************************************************************
76
     * PUBLIC METHODS
77
     *******************************************************************************/
78
79
    /**
80
     * Set a reader instance for this file
81
     *
82
     * @param ReaderInterface $reader Reader instance
83
     * @return Resource Self reference
84
     */
85 51
    public function load(ReaderInterface $reader)
86
    {
87 51
        $this->reset();
88 51
        $this->reader = $reader;
89 51
        return $this;
90
    }
91
92
    /**
93
     * Dump this files contents into a writer
94
     *
95
     * @param WriterInterface $writer Writer instance
96
     * @return Resource Self reference
97
     */
98 12
    public function dump(WriterInterface $writer)
99
    {
100 12
        $writer->write($this->getPart('/'));
101 12
        return $this;
102
    }
103
104
    /**
105
     * Set the content of a particular part
106
     *
107
     * @param mixed $data Content
108
     * @param string $part Part path
109
     * @return Resource Self reference
110
     */
111 12
    public function setPart($data, $part = '/')
112
    {
113 12
        $this->part = $this->part()->set($data, $this->partPath($part));
114 12
        return $this;
115
    }
116
117
    /**
118
     * Return the part's content
119
     *
120
     * @param string $part Part path
121
     * @return string Part content
122
     */
123 46
    public function getPart($part = '/')
124
    {
125 46
        $partPath = $this->partPath($part);
126 44
        $part = $this->part()->get($partPath);
127 39
        return $part->getHydrator()->dehydrate($part);
128
    }
129
130
    /**
131
     * Magic caller for part methods
132
     *
133
     * @param string $name Part method name
134
     * @param array $arguments Part method arguments
135
     * @return mixed|AbstractResource Self reference
136
     * @throw RuntimeException  If an invalid file method is called
137
     * @throw RuntimeException  If an invalid file part method is called
138
     */
139 32
    public function __call($name, array $arguments)
140
    {
141
        // If a (sub)part method is called
142 32
        if (preg_match("%^(.+)Part$%", $name, $partMethod)) {
143 31
            return $this->callPartMethod($partMethod, $arguments);
144
        }
145
146 1
        throw new RuntimeException(
147 1
            sprintf('Invalid file method "%s"', $name),
148 1
            RuntimeException::INVALID_FILE_METHOD
149
        );
150
    }
151
152
    /*******************************************************************************
153
     * PRIVATE METHODS
154
     *******************************************************************************/
155
156
    /**
157
     * Private constructor
158
     *
159
     * @param HydratorInterface|array|string $hydrator File hydrator
160
     * @param ReaderInterface $reader Reader instance
161
     */
162 71
    protected function __construct($hydrator, ReaderInterface $reader = null)
163
    {
164
        // If the hydrator needs to be instantiated from a string or array
165 71
        if (!($hydrator instanceof HydratorInterface)) {
166 71
            $hydrator = HydratorFactory::build((array)$hydrator);
167
        }
168
169
        // Register the hydrator
170 71
        $this->hydrator = $hydrator;
171
172
        // Register the reader if available
173 71
        if ($reader instanceof ReaderInterface) {
174 50
            $this->load($reader);
175
        }
176 71
    }
177
178
    /**
179
     * Reset the file
180
     *
181
     * @return void
182
     */
183 51
    protected function reset()
184
    {
185 51
        $this->part = null;
186 51
    }
187
188
    /**
189
     * Lazy-hydrate and return the main file part
190
     *
191
     * @return PartInterface Main file part
192
     */
193 66
    protected function part()
194
    {
195 66
        if (!($this->part instanceof PartInterface)) {
196 66
            $this->part = $this->hydrator->hydrate(
197 66
                ($this->reader instanceof ReaderInterface) ? $this->reader->read() : ''
198
            );
199
        }
200 66
        return $this->part;
201
    }
202
203
    /**
204
     * Split a part path string into path identifiers
205
     *
206
     * @param string $path Part path string
207
     * @return array Part path identifiers
208
     */
209 67
    protected function partPath($path)
210
    {
211 67
        return (trim($path) == '/') ? [] : array_map(
212 24
            function ($pathIdentifier) {
213 24
                $pathIdentifier = trim($pathIdentifier);
214 24
                AbstractPart::validatePartIdentifier($pathIdentifier);
215 23
                return $pathIdentifier;
216 24
            },
217 67
            explode('/', ltrim($path, '/'))
218
        );
219
    }
220
221
    /**
222
     * Call a method on one of the subparts
223
     *
224
     * @param array $partMethod Part method components
225
     * @param array $arguments Part method arguments
226
     * @return mixed|AbstractResource Getter result / self reference
227
     */
228 31
    protected function callPartMethod(array $partMethod, array $arguments)
229
    {
230 31
        $partMethod = $partMethod[1];
231 31
        return strncmp('get', $partMethod, 3)
232 16
            ? $this->callNonGetterPartMethod($partMethod, $arguments)
233 29
            : $this->callGetterPartMethod($partMethod, $arguments);
234
    }
235
236
    /**
237
     * Call a getter method on one of the subparts
238
     *
239
     * @param string $partMethod Part method
240
     * @param array $arguments Part method arguments
241
     * @return mixed Getter result
242
     */
243 19
    protected function callGetterPartMethod($partMethod, array $arguments) {
244 19
        $subparts = $this->partPath(count($arguments) ? $arguments[0] : '/');
245 19
        return $this->part()->delegate($partMethod, $subparts, []);
246
    }
247
248
    /**
249
     * Call a non-getter method on one of the subparts
250
     *
251
     * @param string $partMethod Part method
252
     * @param array $arguments Part method arguments
253
     * @return AbstractResource Self reference
254
     */
255 16
    protected function callNonGetterPartMethod($partMethod, array $arguments) {
256 16
        $subparts = $this->partPath((count($arguments) > 1) ? $arguments[1] : '/');
257 16
        $this->part = $this->part()->delegate($partMethod, $subparts, array_slice($arguments, 0, 1));
258 14
        return $this;
259
    }
260
}
261