Overview

Namespaces

  • DSchoenbauer
    • DotNotation
      • Enum
      • Exception

Classes

  • DSchoenbauer\DotNotation\ArrayDotNotation
  • DSchoenbauer\DotNotation\Enum\ExceptionMessage

Interfaces

  • DSchoenbauer\DotNotation\Exception\ExceptionInterface

Exceptions

  • DSchoenbauer\DotNotation\Exception\InvalidArgumentException
  • DSchoenbauer\DotNotation\Exception\PathNotArrayException
  • DSchoenbauer\DotNotation\Exception\PathNotFoundException
  • DSchoenbauer\DotNotation\Exception\TargetNotArrayException
  • DSchoenbauer\DotNotation\Exception\UnexpectedValueException
  • Overview
  • Namespace
  • Class
  1: <?php
  2: 
  3: /*
  4:  * The MIT License
  5:  *
  6:  * Copyright 2016 David Schoenbauer <dschoenbauer@gmail.com>.
  7:  *
  8:  * Permission is hereby granted, free of charge, to any person obtaining a copy
  9:  * of this software and associated documentation files (the "Software"), to deal
 10:  * in the Software without restriction, including without limitation the rights
 11:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12:  * copies of the Software, and to permit persons to whom the Software is
 13:  * furnished to do so, subject to the following conditions:
 14:  *
 15:  * The above copyright notice and this permission notice shall be included in
 16:  * all copies or substantial portions of the Software.
 17:  *
 18:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21:  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24:  * THE SOFTWARE.
 25:  */
 26: 
 27: namespace DSchoenbauer\DotNotation;
 28: 
 29: use DSchoenbauer\DotNotation\Exception\PathNotArrayException;
 30: use DSchoenbauer\DotNotation\Exception\PathNotFoundException;
 31: use DSchoenbauer\DotNotation\Exception\TargetNotArrayException;
 32: use DSchoenbauer\DotNotation\Exception\UnexpectedValueException;
 33: 
 34: /**
 35:  * An easier way to deal with complex PHP arrays
 36:  * 
 37:  * @author David Schoenbauer
 38:  * @version 1.1.1
 39:  */
 40: class ArrayDotNotation {
 41: 
 42:     /**
 43:      * Property that houses the data that the dot notation should access
 44:      * @var array
 45:      */
 46:     private $_data = [];
 47:     private $_notationType = ".";
 48: 
 49:     /**
 50:      * Sets the data to parse in a chain
 51:      * @param array $data optional  Array of data that will be accessed via dot notation.
 52:      * @author John Smart
 53:      * @author David Schoenbauer
 54:      * @return \static
 55:      */
 56:     public static function with(array $data = []) {
 57:         return new static($data);
 58:     }
 59: 
 60:     /**
 61:      * An alias for setData 
 62:      * 
 63:      * @see ArrayDotNotation::setData()
 64:      * @since 1.0.0
 65:      * @param array $data optional Array of data that will be accessed via dot notation.
 66:      */
 67:     public function __construct(array $data = []) {
 68:         $this->setData($data);
 69:     }
 70: 
 71:     /**
 72:      * returns the array
 73:      * 
 74:      * returns the array that the dot notation has been used on.
 75:      * 
 76:      * @since 1.0.0
 77:      * @return array Array of data that will be accessed via dot notation.
 78:      */
 79:     public function getData() {
 80:         return $this->_data;
 81:     }
 82: 
 83:     /**
 84:      * sets the array that the dot notation will be used on.
 85:      * 
 86:      * @since 1.0.0
 87:      * @param array $data Array of data that will be accessed via dot notation.
 88:      * @return $this
 89:      */
 90:     public function setData(array $data) {
 91:         $this->_data = $data;
 92:         return $this;
 93:     }
 94: 
 95:     /**
 96:      * Retrieves a value from an array structure as defined by a dot notation string
 97:      * 
 98:      * Returns a value from an array. 
 99:      * 
100:      * @since 1.0.0
101:      * @param string $dotNotation a string of keys concatenated together by a dot that represent different levels of an array
102:      * @param mixed $defaultValue value to return if the dot notation does not find a valid key
103:      * @return mixed value found via dot notation in the array of data
104:      */
105:     public function get($dotNotation, $defaultValue = null) {
106:         return $this->recursiveGet($this->getData(), $this->getKeys($dotNotation), $defaultValue);
107:     }
108: 
109:     /**
110:      * Recursively works though an array level by level until the final key is found. Once key is found the keys value is returned.
111:      * @since 1.0.0
112:      * @param array $data array that has value to be retrieved
113:      * @param array $keys array of keys for each level of the array
114:      * @param mixed $defaultValue value to return when a key is not found
115:      * @return mixed value that the keys find in the data array
116:      */
117:     protected function recursiveGet($data, $keys, $defaultValue) {
118:         $key = array_shift($keys);
119:         if (is_array($data) && $key && count($keys) == 0) { //Last Key
120:             return array_key_exists($key, $data) ? $data[$key] : $defaultValue;
121:         } elseif (is_array($data) && array_key_exists($key, $data)) {
122:             return $this->recursiveGet($data[$key], $keys, $defaultValue);
123:         }
124:         return $defaultValue;
125:     }
126: 
127:     /**
128:      * sets a value into a complicated array data structure
129:      * 
130:      * Places a value into a tiered array. A dot notation of "one.two.three" 
131:      * would place the value at ['one' => ['two' => ['three' => 'valueHere' ]]]
132:      * If the array does not exist it will be added. Indexed arrays can be used,
133:      * and referenced by number. i.e. "one.0" would return the first item of the 
134:      * one array.
135:      * 
136:      * @since 1.0.0
137:      * @param string $dotNotation dot notation representation of keys of where to set a value
138:      * @param mixed $value any value to be stored with in a key structure of dot notation
139:      * @return $this
140:      * @throws PathNotArrayException if a value in the dot notation path is not an array
141:      */
142:     public function set($dotNotation, $value) {
143:         $this->recursiveSet($this->_data, $this->getKeys($dotNotation), $value);
144:         return $this;
145:     }
146: 
147:     /**
148:      * Transverses the keys array until it reaches the appropriate key in the data array and sets that key to the value.
149:      * If the keys don't exist they are created.
150:      * 
151:      * @since 1.0.0
152:      * @param array $data data to be traversed
153:      * @param array $keys the remaining keys of focus for the data array
154:      * @param mixed $value the value to be placed at the final key
155:      * @throws PathNotArrayException if a value in the dot notation path is not an array
156:      */
157:     protected function recursiveSet(array &$data, array $keys, $value) {
158:         $key = array_shift($keys);
159:         if ($key && count($keys) == 0) { //Last Key
160:             $data[$key] = $value;
161:         } else {
162:             if (!array_key_exists($key, $data)) {
163:                 $data[$key] = [];
164:             } elseif (!is_array($data[$key])) {
165:                 throw new Exception\PathNotArrayException($key);
166:             }
167:             $this->recursiveSet($data[$key], $keys, $value);
168:         }
169:     }
170: 
171:     /**
172:      * Merges two arrays together over writing existing values with new values, while adding new array structure to the data 
173:      * 
174:      * @since 1.1.0
175:      * @param string $dotNotation dot notation representation of keys of where to set a value
176:      * @param array $value array to be merged with an existing array
177:      * @return $this
178:      * @throws UnexpectedValueException if a value in the dot notation path is not an array
179:      * @throws TargetNotArrayException if the value in the dot notation target is not an array
180:      */
181:     public function merge($dotNotation, array $value) {
182:         $target = $this->get($dotNotation, []);
183:         if (!is_array($target)) {
184:             throw new Exception\TargetNotArrayException($dotNotation);
185:         }
186:         $this->set($dotNotation, array_merge_recursive($target, $value));
187:         return $this;
188:     }
189: 
190:     /**
191:      * Removes data from the array
192:      * 
193:      * @since 1.1.0
194:      * @param string $dotNotation dot notation representation of keys of where to remove a value
195:      * @return $this
196:      */
197:     public function remove($dotNotation) {
198:         $this->recursiveRemove($this->_data, $this->getKeys($dotNotation));
199:         return $this;
200:     }
201: 
202:     /**
203:      * Transverses the keys array until it reaches the appropriate key in the 
204:      * data array and then deletes the value from the key.
205:      * 
206:      * @since 1.1.0
207:      * @param array $data data to be traversed
208:      * @param array $keys the remaining keys of focus for the data array
209:      * @throws UnexpectedValueException if a value in the dot notation path is 
210:      * not an array
211:      */
212:     protected function recursiveRemove(array &$data, array $keys) {
213:         $key = array_shift($keys);
214:         if (!array_key_exists($key, $data)) {
215:             throw new PathNotFoundException($key);
216:         } elseif ($key && count($keys) == 0) { //Last Key
217:             unset($data[$key]);
218:         } elseif (!is_array($data[$key])) {
219:             throw new PathNotArrayException($key);
220:         } else {
221:             $this->recursiveRemove($data[$key], $keys);
222:         }
223:     }
224: 
225:     /**
226:      * consistently parses notation keys
227:      * @param type $notation key path to a value in an array
228:      * @return array array of keys as delimited by the notation type
229:      */
230:     protected function getKeys($notation) {
231:         return explode($this->getNotationType(), $notation);
232:     }
233: 
234:     /**
235:      * Returns the current notation type that delimits the notation path. 
236:      * Default: "."
237:      * @return string current notation character delimiting the notation path
238:      */
239:     public function getNotationType() {
240:         return $this->_notationType;
241:     }
242: 
243:     /**
244:      * Sets the current notation type used to delimit the notation path.
245:      * @param string $notationType
246:      * @return $this
247:      */
248:     public function setNotationType($notationType = ".") {
249:         $this->_notationType = $notationType;
250:         return $this;
251:     }
252: 
253:     /**
254:      * Checks to see if a dot notation path is present in the data set.
255:      * @param string $dotNotation dot notation representation of keys of where to remove a value
256:      * @return boolean returns true if the do notation path exists in the data
257:      */
258:     public function has($dotNotation) {
259:         $keys = $this->getKeys($dotNotation);
260:         $dataRef = &$this->_data;
261:         foreach ($keys as $key) {
262:             if (!is_array($dataRef) || !array_key_exists($key, $dataRef)) {
263:                 return false;
264:             } else {
265:                 $dataRef = &$dataRef[$key];
266:             }
267:         }
268:         return true;
269:     }
270: 
271: }
272: 
API documentation generated by ApiGen