Completed
Push — master ( 68c6f3...91ba10 )
by Joschi
02:27
created

LocalPath::setDraft()   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 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
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
     * Object draft mode
91
     *
92
     * @var boolean
93
     */
94
    protected $draft = false;
95
96
    /*******************************************************************************
97
     * PUBLIC METHODS
98
     *******************************************************************************/
99
100
    /**
101
     * Object URL constructor
102
     *
103
     * @param null|string $path Object path
104
     * @param null|boolean|int $datePrecision Date precision [NULL = local default, TRUE = any precision (remote object
105
     *     URLs)]
106
     * @param string $leader Leading base path
107
     * @throws InvalidArgumentException If the date precision is invalid
108
     * @throws InvalidArgumentException If the object URL path is invalid
109
     */
110 46
    public function __construct($path = null, $datePrecision = null, &$leader = '')
111
    {
112 46
        if (!empty($path)) {
113
            // If the local default date precision should be used
114 45
            if ($datePrecision === null) {
115 27
                $datePrecision = intval(getenv('OBJECT_DATE_PRECISION'));
116 27
            }
117
118 45
            $pathPattern = null;
119
120
            // If a valid integer date precision is given
121 45
            if (is_int($datePrecision) && ($datePrecision >= 0) && ($datePrecision < 7)) {
122
                $pathPattern = '%^(?P<leader>(/[^/]+)*)?/'.
123 27
                    implode(
124 27
                        '/',
125 27
                        array_slice(self::$datePattern, 0, $datePrecision)
126 27
                    ).($datePrecision ? '/' : '');
127
128
                // Else if the date precision may be arbitrary
129 45
            } elseif ($datePrecision === true) {
130 26
                $pathPattern = '%(?:/'.implode('(?:/', self::$datePattern);
131 26
                $pathPattern .= str_repeat(')?', count(self::$datePattern));
132 26
                $pathPattern .= '/';
133 26
            }
134
135
            // If the date precision is invalid
136 45
            if ($pathPattern === null) {
137 1
                throw new InvalidArgumentException(
138 1
                    sprintf(
139 1
                        'Invalid date precision "%s" (%s)',
140 1
                        strval($datePrecision),
141 1
                        gettype($datePrecision)
142 1
                    ),
143
                    InvalidArgumentException::INVALID_DATE_PRECISION
144 1
                );
145
            }
146
147 44
            $pathPattern .= '(?P<id>\d+)\.(?P<type>[a-z]+)(?:/(.*\.)?\\k';
148 44
            $pathPattern .= '<id>(?:(?P<draft>\+)|(?:-(?P<revision>\d+)))?(?P<extension>\.[a-z0-9]+)?)?$%';
149
150 44
            if (!preg_match($pathPattern, $path, $pathParts)) {
151 15
                throw new InvalidArgumentException(
152 15
                    sprintf('Invalid object URL path "%s"', $path),
153
                    InvalidArgumentException::INVALID_OBJECT_URL_PATH
154 15
                );
155
            }
156
157
            // If date components are used
158 44
            if ($datePrecision) {
159 44
                $year = $pathParts['year'];
160 44
                $month = isset($pathParts['month']) ? $pathParts['month'] ?: '01' : '01';
161 44
                $day = isset($pathParts['day']) ? $pathParts['day'] ?: '01' : '01';
162 44
                $hour = isset($pathParts['hour']) ? $pathParts['hour'] ?: '00' : '00';
163 44
                $minute = isset($pathParts['minute']) ? $pathParts['minute'] ?: '00' : '00';
164 44
                $second = isset($pathParts['second']) ? $pathParts['second'] ?: '00' : '00';
165 44
                $this->creationDate = new \DateTimeImmutable("$year-$month-$day".'T'."$hour:$minute:$second+00:00");
166 44
            }
167
168
            // Determine the leader
169 44
            $leader = ($datePrecision === true) ? substr(
170 25
                $path,
171 25
                0,
172 25
                strlen($path) - strlen($pathParts[0])
173 44
            ) : $pathParts['leader'];
174
175
            // Set the ID
176
177 44
            $this->uid = Kernel::create(Id::class, [intval($pathParts['id'])]);
178
179
            // Set the type
180 44
            $this->type = Kernel::create(Type::class, [$pathParts['type']]);
181
182
            // Set the revision
183 44
            $this->revision = Kernel::create(
184 44
                Revision::class,
185 44
                [empty($pathParts['revision']) ? Revision::CURRENT : intval($pathParts['revision'])]
186 44
            );
187
188
            // Set the draft mode
189 44
            $this->draft = !empty($pathParts['draft']);
190 44
        }
191 45
    }
192
193
    /**
194
     * Create and return the object URL path
195
     *
196
     * @return string Object path
197
     */
198 20
    public function __toString()
199
    {
200 20
        $path = [];
201 20
        $datePrecision = intval(getenv('OBJECT_DATE_PRECISION'));
202
203
        // Add the creation date
204 20
        foreach (array_slice(array_keys(self::$datePattern), 0, $datePrecision) as $dateFormat) {
205 20
            $path[] = $this->creationDate->format($dateFormat);
206 20
        }
207
208
        // Add the object ID and type
209 20
        $path[] = $this->uid->getId().'.'.$this->type->getType();
210
211
        // Add the ID, draft mode and revision
212 20
        $id = $this->uid->getId();
213 20
        $path[] = $this->draft ? $id.'+' : rtrim($id.'-'.$this->revision->getRevision(), '-');
214
215 20
        return '/'.implode('/', $path);
216
    }
217
218
    /**
219
     * Return the object's creation date
220
     *
221
     * @return \DateTimeImmutable Object creation date
222
     */
223 21
    public function getCreationDate()
224
    {
225 21
        return $this->creationDate;
226
    }
227
228
    /**
229
     * Set the object's creation date
230
     *
231
     * @param \DateTimeImmutable $creationDate
232
     * @return PathInterface|LocalPath New object path
233
     */
234 2
    public function setCreationDate(\DateTimeImmutable $creationDate)
235
    {
236 2
        $path = clone $this;
237 2
        $path->creationDate = $creationDate;
238 2
        return $path;
239
    }
240
241
    /**
242
     * Return the object type
243
     *
244
     * @return Type Object type
245
     */
246 23
    public function getType()
247
    {
248 23
        return $this->type;
249
    }
250
251
    /**
252
     * Set the object type
253
     *
254
     * @param Type $type Object type
255
     * @return PathInterface|LocalPath New object path
256
     */
257 2
    public function setType(Type $type)
258
    {
259 2
        $path = clone $this;
260 2
        $path->type = $type;
261 2
        return $path;
262
    }
263
264
    /**
265
     * Return the object ID
266
     *
267
     * @return Id Object ID
268
     */
269 24
    public function getId()
270
    {
271 24
        return $this->uid;
272
    }
273
274
    /**
275
     * Set the object ID
276
     *
277
     * @param Id $uid Object ID
278
     * @return PathInterface|LocalPath New object path
279
     */
280 2
    public function setId(Id $uid)
281
    {
282 2
        $path = clone $this;
283 2
        $path->uid = $uid;
284 2
        return $path;
285
    }
286
287
    /**
288
     * Return the object revision
289
     *
290
     * @return Revision Object revision
291
     */
292 21
    public function getRevision()
293
    {
294 21
        return $this->revision;
295
    }
296
297
    /**
298
     * Set the object revision
299
     *
300
     * @param Revision $revision Object revision
301
     * @return PathInterface|LocalPath New object path
302
     */
303 19
    public function setRevision(Revision $revision)
304
    {
305 19
        $path = clone $this;
306 19
        $path->revision = $revision;
307 19
        return $path;
308
    }
309
310
    /**
311
     * Return the object draft mode
312
     *
313
     * @return boolean Object draft mode
314
     */
315 1
    public function isDraft()
316
    {
317 1
        return $this->draft;
318
    }
319
320
    /**
321
     * Set the object draft mode
322
     *
323
     * @param boolean $draft Object draft mode
324
     */
325 1
    public function setDraft($draft)
326
    {
327 1
        $path = clone $this;
328 1
        $path->draft = (boolean)$draft;
329 1
        return $path;
330
    }
331
}
332