Completed
Push — master ( e31061...1587a0 )
by Joschi
02:44
created

LocalPath::setCreationDate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 6
ccs 4
cts 4
cp 1
rs 9.4285
cc 1
eloc 4
nc 1
nop 1
crap 1
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\Path;
38
39
use Apparat\Kernel\Ports\Kernel;
40
use Apparat\Object\Domain\Model\Object\Id;
41
use Apparat\Object\Domain\Model\Object\Revision;
42
use Apparat\Object\Domain\Model\Object\Type;
43
44
/**
45
 * Object path
46
 *
47
 * @package Apparat\Object
48
 * @subpackage Apparat\Object\Domain
49
 */
50
class LocalPath implements PathInterface
51
{
52
    /**
53
     * Date PCRE pattern
54
     *
55
     * @var array
56
     */
57
    protected static $datePattern = [
58
        'Y' => '(?P<year>\d{4})',
59
        'm' => '(?P<month>\d{2})',
60
        'd' => '(?P<day>\d{2})',
61
        'H' => '(?P<hour>\d{2})',
62
        'i' => '(?P<minute>\d{2})',
63
        's' => '(?P<second>\d{2})',
64
    ];
65
    /**
66
     * Creation date
67
     *
68
     * @var \DateTimeImmutable
69
     */
70
    protected $creationDate = null;
71
    /**
72
     * Object ID
73
     *
74
     * @var Id
75
     */
76
    protected $uid = null;
77
    /**
78
     * Object type
79
     *
80
     * @var Type
81
     */
82
    protected $type = null;
83
    /**
84
     * Object revision
85
     *
86
     * @var Revision
87
     */
88
    protected $revision = null;
89
90
    /*******************************************************************************
91
     * PUBLIC METHODS
92
     *******************************************************************************/
93
94
    /**
95
     * Object URL constructor
96
     *
97
     * @param string $path Object path
98
     * @param NULL|boolean|int $datePrecision Date precision [NULL = local default, TRUE = any precision (remote object
99
     *     URLs)]
100
     * @param string $leader Leading base path
101
     * @throws InvalidArgumentException If the date precision is invalid
102
     * @throws InvalidArgumentException If the object URL path is invalid
103
     */
104 45
    public function __construct($path, $datePrecision = null, &$leader = '')
105
    {
106
        // If the local default date precision should be used
107 45
        if ($datePrecision === null) {
108 26
            $datePrecision = intval(getenv('OBJECT_DATE_PRECISION'));
109
        }
110
111 45
        $pathPattern = null;
112
113
        // If a valid integer date precision is given
114 45
        if (is_int($datePrecision) && ($datePrecision >= 0) && ($datePrecision < 7)) {
115
            $pathPattern = '%^(?P<leader>(/[^/]+)*)?/'.
116 26
                implode(
117 26
                    '/',
118 26
                    array_slice(self::$datePattern, 0, $datePrecision)
119 26
                ).($datePrecision ? '/' : '');
120
121
            // Else if the date precision may be arbitrary
122 22
        } elseif ($datePrecision === true) {
123 21
            $pathPattern = '%(?:/'.implode('(?:/', self::$datePattern);
124 21
            $pathPattern .= str_repeat(')?', count(self::$datePattern));
125 21
            $pathPattern .= '/';
126
        }
127
128
        // If the date precision is invalid
129 45
        if ($pathPattern === null) {
130 1
            throw new InvalidArgumentException(
131
                sprintf(
132 1
                    'Invalid date precision "%s" (%s)',
133
                    strval($datePrecision),
134
                    gettype($datePrecision)
135
                ),
136 1
                InvalidArgumentException::INVALID_DATE_PRECISION
137
            );
138
        }
139
140 44
        $pathPattern .= '(?P<id>\d+)\.(?P<type>[a-z]+)(?:/(.*\.)?\\k';
141 44
        $pathPattern .= '<id>(?:-(?P<revision>\d+))?(?P<extension>\.[a-z0-9]+)?)?$%';
142
143 44
        if (empty($path) || !preg_match($pathPattern, $path, $pathParts)) {
144 7
            throw new InvalidArgumentException(
145
                sprintf(
146 7
                    'Invalid object URL path "%s"',
147 7
                    empty($path) ? '(empty)' : $path
148
                ),
149 7
                InvalidArgumentException::INVALID_OBJECT_URL_PATH
150
            );
151
        }
152
153
        // If date components are used
154 42
        if ($datePrecision) {
155 42
            $year = $pathParts['year'];
156 42
            $month = isset($pathParts['month']) ? $pathParts['month'] ?: '01' : '01';
157 42
            $day = isset($pathParts['day']) ? $pathParts['day'] ?: '01' : '01';
158 42
            $hour = isset($pathParts['hour']) ? $pathParts['hour'] ?: '00' : '00';
159 42
            $minute = isset($pathParts['minute']) ? $pathParts['minute'] ?: '00' : '00';
160 42
            $second = isset($pathParts['second']) ? $pathParts['second'] ?: '00' : '00';
161 42
            $this->creationDate = new \DateTimeImmutable("$year-$month-$day".'T'."$hour:$minute:$second+00:00");
162
        }
163
164
        // Determine the leader
165 42
        $leader = ($datePrecision === true) ? substr(
166
            $path,
167 18
            0,
168 18
            strlen($path) - strlen($pathParts[0])
169 42
        ) : $pathParts['leader'];
170
171
        // Set the ID
172
173 42
        $this->uid = Kernel::create(Id::class, [intval($pathParts['id'])]);
174
175
        // Set the type
176 42
        $this->type = Kernel::create(Type::class, [$pathParts['type']]);
177
178
        // Set the revision
179 42
        $this->revision = Kernel::create(
180 42
            Revision::class,
181 42
            [empty($pathParts['revision']) ? Revision::CURRENT : intval($pathParts['revision'])]
182
        );
183 42
    }
184
185
    /**
186
     * Create and return the object URL path
187
     *
188
     * @return string Object path
189
     */
190 10
    public function __toString()
191
    {
192 10
        $path = [];
193 10
        $datePrecision = intval(getenv('OBJECT_DATE_PRECISION'));
194
195
        // Add the creation date
196 10
        foreach (array_slice(array_keys(self::$datePattern), 0, $datePrecision) as $dateFormat) {
197 10
            $path[] = $this->creationDate->format($dateFormat);
198
        }
199
200
        // Add the object ID and type
201 10
        $path[] = $this->uid->getId().'.'.$this->type->getType();
202
203
        // Add the ID and revision
204 10
        $path[] = rtrim($this->uid->getId().'-'.$this->revision->getRevision(), '-');
205
206 10
        return '/'.implode('/', $path);
207
    }
208
209
    /**
210
     * Return the object's creation date
211
     *
212
     * @return \DateTimeImmutable Object creation date
213
     */
214 9
    public function getCreationDate()
215
    {
216 9
        return $this->creationDate;
217
    }
218
219
    /**
220
     * Set the object's creation date
221
     *
222
     * @param \DateTimeImmutable $creationDate
223
     * @return PathInterface|LocalPath New object path
224
     */
225 1
    public function setCreationDate(\DateTimeImmutable $creationDate)
226
    {
227 1
        $path = clone $this;
228 1
        $path->creationDate = $creationDate;
229 1
        return $path;
230
    }
231
232
    /**
233
     * Return the object type
234
     *
235
     * @return Type Object type
236
     */
237 11
    public function getType()
238
    {
239 11
        return $this->type;
240
    }
241
242
    /**
243
     * Set the object type
244
     *
245
     * @param Type $type Object type
246
     * @return PathInterface|LocalPath New object path
247
     */
248 1
    public function setType(Type $type)
249
    {
250 1
        $path = clone $this;
251 1
        $path->type = $type;
252 1
        return $path;
253
    }
254
255
    /**
256
     * Return the object ID
257
     *
258
     * @return Id Object ID
259
     */
260 22
    public function getId()
261
    {
262 22
        return $this->uid;
263
    }
264
265
    /**
266
     * Set the object ID
267
     *
268
     * @param Id $uid Object ID
269
     * @return PathInterface|LocalPath New object path
270
     */
271 1
    public function setId(Id $uid)
272
    {
273 1
        $path = clone $this;
274 1
        $path->uid = $uid;
275 1
        return $path;
276
    }
277
278
    /**
279
     * Return the object revision
280
     *
281
     * @return Revision Object revision
282
     */
283 9
    public function getRevision()
284
    {
285 9
        return $this->revision;
286
    }
287
288
    /**
289
     * Set the object revision
290
     *
291
     * @param Revision $revision Object revision
292
     * @return PathInterface|LocalPath New object path
293
     */
294 1
    public function setRevision(Revision $revision)
295
    {
296 1
        $path = clone $this;
297 1
        $path->revision = $revision;
298 1
        return $path;
299
    }
300
}
301