Name::start()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
4
namespace Stratadox\EntityState\Internal;
5
6
use function get_class;
7
use function gettype;
8
use function is_object;
9
use function sprintf;
10
use function str_replace;
11
12
/**
13
 * Potentially prefixed property name.
14
 *
15
 * @internal
16
 * @author Stratadox
17
 */
18
final class Name
19
{
20
    private const PROBLEMS = ['\\', '[', ']'];
21
    private const SOLUTIONS = ['\\\\', '\\[', '\\]'];
22
    private $prefix;
23
    private $name;
24
25
    private function __construct(string $prefix, string $name)
26
    {
27
        $this->prefix = $prefix;
28
        $this->name = $name;
29
    }
30
31
    public static function start(): self
32
    {
33
        return new self('', '');
34
    }
35
36
    /**
37
     * Returns a name for the collection key.
38
     *
39
     * @param iterable $collection The collection where the item is in.
40
     * @param string   $key        The position of the item in the collection.
41
     * @return Name                The array key property name.
42
     */
43
    public function forItem(iterable $collection, string $key): Name
44
    {
45
        return new Name(
46
            $this->prefix,
47
            sprintf(
48
                '%s%s[%s]',
49
                is_object($collection) ? get_class($collection) : gettype($collection),
50
                $this->nameWithColon(),
51
                $this->escape($key)
52
            )
53
        );
54
    }
55
56
    /**
57
     * Adds the class of the object to the property name definition.
58
     *
59
     * @param object $object The object whose class to add.
60
     * @return Name          The name with added class.
61
     */
62
    public function for(object $object): Name
63
    {
64
        return new Name(
65
            $this->prefix,
66
            sprintf('%s%s', get_class($object), $this->nameWithColon())
67
        );
68
    }
69
70
    /**
71
     * Returns a name for the nested property.
72
     *
73
     * @param ReflectionProperty $property The nested property.
74
     * @return Name                        The prefixed property name.
75
     */
76
    public function forReflected(ReflectionProperty $property): Name
77
    {
78
        return new Name($this->asPrefix(), $property->getName());
79
    }
80
81
    /**
82
     * Returns a name for the semi-magic property to count the collection.
83
     *
84
     * @param iterable $collection The collection to store the count of.
85
     * @return Name                The collection counting name.
86
     */
87
    public function toCount(iterable $collection): Name
88
    {
89
        return new Name(
90
            $this->prefix,
91
            sprintf(
92
                'count(%s%s)',
93
                is_object($collection) ? get_class($collection) : gettype($collection),
94
                $this->nameWithColon()
95
            )
96
        );
97
    }
98
99
    /**
100
     * Returns the string representation of the name.
101
     *
102
     * @return string
103
     */
104
    public function __toString()
105
    {
106
        return $this->prefix . $this->name;
107
    }
108
109
    private function escape(string $key): string
110
    {
111
        return str_replace(self::PROBLEMS, self::SOLUTIONS, $key);
112
    }
113
114
    private function asPrefix(): string
115
    {
116
        if ($this->prefix === '' && $this->name === '') {
117
            return '';
118
        }
119
        return sprintf('%s.', $this);
120
    }
121
122
    private function nameWithColon(): string
123
    {
124
        return $this->name ? sprintf(':%s', $this->name) : '';
125
    }
126
}
127