Completed
Push — master ( 7552a3...4852b0 )
by Joschi
02:39
created

AbstractResource   A

Complexity

Total Complexity 20

Size/Duplication

Total Lines 193
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Test Coverage

Coverage 100%

Importance

Changes 9
Bugs 0 Features 1
Metric Value
wmc 20
lcom 1
cbo 7
dl 0
loc 193
ccs 61
cts 61
cp 1
rs 10
c 9
b 0
f 1

10 Methods

Rating   Name   Duplication   Size   Complexity  
A load() 0 6 1
A dump() 0 5 1
A setPart() 0 5 1
A getPart() 0 6 1
A __call() 0 12 2
A __construct() 0 15 3
A reset() 0 4 1
A part() 0 9 3
A partPath() 0 11 2
B callPartMethod() 0 17 5
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 getMimeTypePart($part = '/') getMimeTypePart($part = '/') Get the MIME 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 49
    public function load(ReaderInterface $reader)
86
    {
87 48
        $this->reset();
88 49
        $this->reader = $reader;
89 48
        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 11
    public function dump(WriterInterface $writer)
99
    {
100 11
        $writer->write($this->getPart('/'));
101 11
        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 45
    public function getPart($part = '/')
124
    {
125 45
        $partPath = $this->partPath($part);
126 43
        $part = $this->part()->get($partPath);
127 38
        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
            RuntimeException::INVALID_FILE_METHOD
149 1
        );
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 68
    protected function __construct($hydrator, ReaderInterface $reader = null)
163
    {
164
        // If the hydrator needs to be instantiated from a string or array
165 68
        if (!($hydrator instanceof HydratorInterface)) {
166 68
            $hydrator = HydratorFactory::build((array)$hydrator);
167 68
        }
168
169
        // Register the hydrator
170 68
        $this->hydrator = $hydrator;
171
172
        // Register the reader if available
173 68
        if ($reader instanceof ReaderInterface) {
174 47
            $this->load($reader);
175 47
        }
176 68
    }
177
178
    /**
179
     * Reset the file
180
     *
181
     * @return void
182
     */
183 48
    protected function reset()
184
    {
185 48
        $this->part = null;
186 48
    }
187
188
    /**
189
     * Lazy-hydrate and return the main file part
190
     *
191
     * @return PartInterface Main file part
192
     */
193 64
    protected function part()
194
    {
195 64
        if (!($this->part instanceof PartInterface)) {
196 64
            $this->part = $this->hydrator->hydrate(
197 64
                ($this->reader instanceof ReaderInterface) ? $this->reader->read() : ''
198 64
            );
199 64
        }
200 64
        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 66
    protected function partPath($path)
210
    {
211 66
        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 24
            explode('/', ltrim($path, '/'))
218 66
        );
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 Self reference
227
     */
228 31
    protected function callPartMethod(array $partMethod, array $arguments) {
229 31
        $partMethod = $partMethod[1];
230 31
        $isGetterMethod = (!strncmp('get', $partMethod, 3));
231 31
        $delegateArguments = $isGetterMethod ? array() : array_slice($arguments, 0, 1);
232 31
        $subpartPathArgIndex = $isGetterMethod ? 0 : 1;
233 31
        $subparts = $this->partPath(
234 31
            (count($arguments) > $subpartPathArgIndex) ? $arguments[$subpartPathArgIndex] : '/'
235 31
        );
236 31
        $delegateResult = $this->part()->delegate($partMethod, $subparts, $delegateArguments);
237
238 25
        if ($isGetterMethod) {
239 15
            return $delegateResult;
240
        }
241
242 14
        $this->part = $delegateResult;
243 14
        return $this;
244
    }
245
}
246