Completed
Push — master ( 532905...375f27 )
by Todd
02:03
created

Config::count()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 2
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace Logikos\Util;
4
5
/**
6
 * This is largely inspired by \Phalcon\Config - https://docs.phalconphp.com/hr/3.2/api/Phalcon_Config
7
 * NOTICE: \Phalcon\Config will be much faster than this class and you are encouraged to use it
8
 * @see ../docs/config/README.md
9
 */
10
abstract class Config implements \ArrayAccess, \Countable, \Iterator {
11
  private $locked   = false;
12
  private $values   = [];
13
14 49
  public function __construct(array $arrayConfig = []) {
15 49
    foreach($arrayConfig as $key => $value)
16 44
      $this->offsetSet($key, $value);
17
18 49
    $this->onConstruct();
19 49
  }
20
21
  // override this if you want to
22
  protected function onConstruct() {}
23
24 44
  public function isLocked() {
25 44
    return $this->locked;
26
  }
27
28 7
  public function get($key, $default = null) {
29 7
    return $this->offsetExists($key) ? $this->offsetGet($key) : $default;
30
  }
31
32 1
  public function has($key) {
33 1
    return $this->offsetExists($key);
34
  }
35
36 6
  public function toArray() {
37 6
    return array_map(
38 6
        function ($value) {
39 6
          return $this->hasToArray($value) ? $value->toArray() : $value;
40 6
        },
41 6
        $this->values
42
    );
43
  }
44
45 6
  private function hasToArray($value): bool {
46 6
    return is_object($value) && method_exists($value, 'toArray');
47
  }
48
49 4
  public function path($path, $default = null, $delimiter = '.') {
50 4
    if ($this->pathStartsWithConfig($path, $delimiter))
51 2
      return $this->evalSubPath($path, $delimiter, $default);
52
53 4
    return $this->get($this->getFirstToken($path, $delimiter), $default);
54
  }
55
56 4
  private function pathStartsWithConfig($path, $delimiter) {
57 4
    return $this->getFirstTokenValue($path, $delimiter) instanceof self;
58
  }
59
60 4
  private function getFirstTokenValue($path, $delimiter) {
61 4
    return $this->get($this->getFirstToken($path, $delimiter));
62
  }
63
64 4
  private function getFirstToken($path, $delimiter) {
65 4
    return $this->subtok($path, $delimiter, 0, 1);
66
  }
67
68 2
  private function evalSubPath($path, $delimiter, $default) {
69 2
    return $this->getFirstTokenValue($path, $delimiter)->path(
70 2
        $this->subtok($path, $delimiter, 1),
71 2
        $default,
72 2
        $delimiter
73
    );
74
  }
75
76
  /**
77
   * subtok(string, delimiter, offset, length)
78
   *
79
   * Usage:
80
   *  subtok('a.b.c.d.e','.',0)     = 'a.b.c.d.e'
81
   *  subtok('a.b.c.d.e','.',0,2)   = 'a.b'
82
   *  subtok('a.b.c.d.e','.',2,1)   = 'c'
83
   *  subtok('a.b.c.d.e','.',2,-1)  = 'c.d'
84
   *  subtok('a.b.c.d.e','.',-4)    = 'b.c.d.e'
85
   *  subtok('a.b.c.d.e','.',-4,2)  = 'b.c'
86
   *  subtok('a.b.c.d.e','.',-4,-1) = 'b.c.d'
87
   *
88
   * @param  string   $string    The input string
89
   * @param  string   $delimiter The boundary string
90
   * @param  int      $offset    starting position, like in substr
91
   * @param  int|null $length    length, like in substr
92
   * @return string
93
   */
94 4
  function subtok($string, $delimiter, $offset, $length = NULL) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
95 4
    return implode($delimiter, array_slice(explode($delimiter, $string), $offset, $length));
96
  }
97
98
  # Countable
99 3
  public function count() {
100 3
    return count($this->values);
101
  }
102
103
104
  # ArrayAccess
105 30
  public function offsetExists($offset) {
106 30
    return array_key_exists($offset, $this->values);
107
  }
108
109 18
  public function offsetGet($offset) {
110 18
    if (!$this->offsetExists($offset))
111 2
      throw new \OutOfBoundsException("offset '{$offset}' does not exist");
112 16
    return $this->values[$offset];
113
  }
114
115 44
  public function offsetSet($offset, $value) {
116 44
    $this->blockIfLocked();
117 44
    $this->values[strval($offset)] = is_array($value)
118 10
        ? new static($value)
119 44
        : $value;
120 44
  }
121
122 4
  public function offsetUnset($offset) {
123 4
    $this->blockIfLocked();
124 2
    unset($this->values[strval($offset)]);
125 2
  }
126
127
128
  # Iterator
129
  public function rewind()  { return reset($this->values);        }
130
  public function key()     { return key($this->values);          }
131
  public function current() { return current($this->values);      }
132
  public function next()    { return next($this->values);         }
133
  public function valid()   { return key($this->values) !== null; }
134
135
136
  # Magic Property Access
137
  public function __set($offset, $value) { $this->offsetSet($offset, $value);   }
138
  public function __unset($offset)       { $this->offsetUnset($offset);         }
139
  public function __get($offset)         { return $this->offsetGet($offset);    }
140
  public function __isset($offset)       { return $this->offsetExists($offset); }
141
142
  /**
143
   * @param array $data
144
   * @return static
145
   */
146 1
  public static function __set_state(array $data): Config {
147 1
    return new static($data);
148
  }
149
150 12
  public function lock() {
151 12
    $this->locked = true;
152 12
  }
153
154 5
  protected function rawValues() {
155 5
    return $this->values;
156
  }
157
158 5
  protected function isConfigObject($value) {
159 5
    return $value instanceof Config;
160
  }
161
162 44
  private function blockIfLocked() {
163 44
    if ($this->isLocked())
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->isLocked() targeting Logikos\Util\Config::isLocked() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
164 6
      throw new CanNotMutateException();
165
  }
166
}