Completed
Push — master ( d83be0...ef2acb )
by Joschi
03:42
created

SelectorFactory::getSelectorRegex()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 25
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 2

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 2
eloc 16
c 3
b 0
f 0
nc 2
nop 1
dl 0
loc 25
ccs 17
cts 17
cp 1
crap 2
rs 8.8571
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\Ports\Factory;
38
39
use Apparat\Kernel\Ports\Kernel;
40
use Apparat\Object\Domain\Model\Object\Revision;
41
use Apparat\Object\Domain\Repository\InvalidArgumentException;
42
use Apparat\Object\Domain\Repository\Selector;
43
use Apparat\Object\Domain\Repository\SelectorInterface;
44
45
/**
46
 * Object selector factory
47
 *
48
 * @package Apparat\Object
49
 * @subpackage Apparat\Object\Domain
50
 */
51
class SelectorFactory
52
{
53
    /**
54
     * Date PCRE pattern
55
     *
56
     * @var array
57
     * @see ObjectUrl::$datePattern
58
     */
59
    protected static $datePattern = [
60
        'Y' => '/(?P<year>\d{4}|\*)',
61
        'm' => '(?:/(?P<month>\d{2}|\*)',
62
        'd' => '(?:/(?P<day>\d{2}|\*)',
63
        'H' => '(?:/(?P<hour>\d{2}|\*)',
64
        'i' => '(?:/(?P<minute>\d{2}|\*)',
65
        's' => '(?:/(?P<second>\d{2}|\*)',
66
    ];
67
68
    /**
69
     * Parse and instantiate an object selector
70
     *
71
     * @param string $selector String selector
72
     * @return Selector Object selector
73
     * @throws InvalidArgumentException If the selector is invalid
74
     */
75 41
    public static function createFromString($selector)
76
    {
77
        // If the selector is invalid
78 41
        if (!strlen($selector) ||
79 41
            !preg_match(
80 41
                '%^'.self::getSelectorRegex(intval(getenv('OBJECT_DATE_PRECISION'))).'$%',
81 41
                $selector,
82
                $selectorParts
83 41
            ) ||
84 40
            !strlen($selectorParts[0])
85 41
        ) {
86 1
            throw new InvalidArgumentException(
87 1
                sprintf('Invalid repository selector "%s"', $selector),
88
                InvalidArgumentException::INVALID_REPOSITORY_SELECTOR
89 1
            );
90
        }
91
92 40
        return self::createFromParams($selectorParts);
93
    }
94
95
    /**
96
     * Return a regular expression for selector parsing
97
     *
98
     * @param int $datePrecision Object date precision
99
     * @return string Selector parsing regular expression
100
     */
101 41
    public static function getSelectorRegex($datePrecision)
102
    {
103 41
        $bothIndicator = preg_quote(SelectorInterface::INDICATOR_BOTH);
104 41
        $hiddenIndicator = preg_quote(SelectorInterface::INDICATOR_HIDDEN);
105 41
        $wildcard = preg_quote(SelectorInterface::WILDCARD);
106
107 41
        $revisionPart = '(?:-(?P<revision>(?:\d+)|'.$wildcard.'))?';
108
109 41
        $draftIndicator = preg_quote(SelectorInterface::INDICATOR_DRAFT);
110 41
        $draftPart = '(?P<draft>'.$bothIndicator.'|'.$draftIndicator.')?';
111 41
        $instancePart = '(?:/'.$draftPart.'(?:(?:\\k<id>)|'.$wildcard.')'.$revisionPart.')?';
112
113 41
        $typePart = '(?:(?:\-(?:(?P<type>(?:[a-z]+)|'.$wildcard.')))?'.$instancePart.')?';
114
115 41
        $hiddenPart = '(?P<visibility>'.$bothIndicator.'|'.$hiddenIndicator.')?';
116 41
        $idPart = '(?P<id>(?:\d+|'.$wildcard.'))';
117 41
        $selectorPattern = '/'.$hiddenPart.$idPart.$typePart;
118
119
        // If the creation date is used as selector component
120 41
        if ($datePrecision) {
121 41
            $selectorPattern = '(?:'.$selectorPattern.str_repeat(')?', $datePrecision);
122 41
            $selectorPattern = implode('', array_slice(self::$datePattern, 0, $datePrecision)).$selectorPattern;
123 41
        }
124 41
        return $selectorPattern;
125
    }
126
127
    /**
128
     * Instantiate an object selector from a list of parameters
129
     *
130
     * @param array $params Object selector parameters
131
     * @return Selector Object selector
132
     */
133 40
    public static function createFromParams(array $params)
134
    {
135 40
        $datePrecision = intval(getenv('OBJECT_DATE_PRECISION'));
136
137
        // Object visibility
138 40
        $visibility = empty($params['visibility']) ? SelectorInterface::VISIBLE
139 40
            : (($params['visibility'] == SelectorInterface::INDICATOR_HIDDEN) ?
140 40
                SelectorInterface::HIDDEN : SelectorInterface::ALL);
141
142
        // Object draft
143 40
        $draft = empty($params['draft']) ? SelectorInterface::PUBLISHED
144 40
            : (($params['draft'] == SelectorInterface::INDICATOR_DRAFT) ?
145 40
                SelectorInterface::DRAFT : SelectorInterface::ALL);
146
147 40
        $year = $month = $day = $hour = $minute = $second = null;
148 40
        if (($datePrecision > 0)) {
149 40
            $year = isset($params['year']) ? self::castInt(
150 40
                $params['year']
151 40
            ) : SelectorInterface::WILDCARD;
152 40
        }
153 40
        if (($datePrecision > 1)) {
154 40
            $month = isset($params['month']) ? self::castInt(
155 37
                $params['month']
156 40
            ) : SelectorInterface::WILDCARD;
157 40
        }
158 40
        if (($datePrecision > 2)) {
159 40
            $day = isset($params['day']) ? self::castInt($params['day']) : SelectorInterface::WILDCARD;
160 40
        }
161 40
        if (($datePrecision > 3)) {
162 2
            $hour = isset($params['hour']) ? self::castInt(
163 1
                $params['hour']
164 2
            ) : SelectorInterface::WILDCARD;
165 2
        }
166 40
        if (($datePrecision > 4)) {
167 2
            $minute = isset($params['minute']) ? self::castInt(
168 1
                $params['minute']
169 2
            ) : SelectorInterface::WILDCARD;
170 2
        }
171 40
        if (($datePrecision > 5)) {
172 2
            $second = isset($params['second']) ? self::castInt(
173 1
                $params['second']
174 2
            ) : SelectorInterface::WILDCARD;
175 2
        }
176 40
        $uid = isset($params['id']) ? self::castInt($params['id']) : SelectorInterface::WILDCARD;
177
178 40
        $type = empty($params['type']) ? SelectorInterface::WILDCARD : trim($params['type']);
179 40
        $revision = empty($params['revision']) ? Revision::CURRENT : self::castInt($params['revision']);
180
181 40
        return Kernel::create(
182 40
            Selector::class,
183 40
            [$year, $month, $day, $hour, $minute, $second, $uid, $type, $revision, $visibility, $draft]
184 40
        );
185
    }
186
187
    /**
188
     * Cast a value as integer if it's not a wildcard
189
     *
190
     * @param string $value Value
191
     * @return int|string Integer value or wildcard
192
     */
193 40
    protected static function castInt($value)
194
    {
195 40
        return ($value === SelectorInterface::WILDCARD) ? $value : intval($value);
196
    }
197
}
198