Skip to content

Instantly share code, notes, and snippets.

@antonmedv
Last active August 11, 2022 13:47

Revisions

  1. @Elfet Elfet revised this gist Nov 13, 2013. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion DotNotation.php
    Original file line number Diff line number Diff line change
    @@ -66,7 +66,11 @@ public function set($path, $value)

    while (count($keys) > 0) {
    if (count($keys) === 1) {
    $at[array_shift($keys)] = $value;
    if (is_array($at)) {
    $at[array_shift($keys)] = $value;
    } else {
    throw new \RuntimeException("Can not set value at this path ($path) because is not array.");
    }
    } else {
    $key = array_shift($keys);

  2. @Elfet Elfet revised this gist Nov 13, 2013. 2 changed files with 7 additions and 6 deletions.
    2 changes: 1 addition & 1 deletion DotNotation.php
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@
    * $dn->add('bar.baz', ['boo'=>true]); // ['foo'=>false,'boo'=>true]
    *
    * @author Anton Medvedev <anton (at) elfet (dot) ru>
    * @version 1.0
    * @version 2.0
    * @license MIT
    */
    class DotNotation
    11 changes: 6 additions & 5 deletions DotNotationTest.php
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,11 @@
    <?php
    /* (c) Anton Medvedev <[email protected]>
    *
    * For the full copyright and license information, please view the LICENSE
    * file that was distributed with this source code.
    /**
    * Tests for DotNotation class.
    *
    * @author Anton Medvedev <anton (at) elfet (dot) ru>
    * @version 2.0
    * @license MIT
    */

    class DotNotationTest extends \PHPUnit_Framework_TestCase
    {
    public function testSet()
  3. @Elfet Elfet revised this gist Nov 13, 2013. 2 changed files with 136 additions and 17 deletions.
    58 changes: 41 additions & 17 deletions DotNotation.php
    Original file line number Diff line number Diff line change
    @@ -16,11 +16,13 @@
    */
    class DotNotation
    {
    const SEPARATOR = '/[:\.]/';

    /**
    * @var array
    */
    protected $values = array();

    /**
    * @var array
    */
    @@ -39,7 +41,7 @@ public function get($path, $default = null)
    $array = $this->values;

    if (!empty($path)) {
    $keys = explode('.', $path);
    $keys = $this->explode($path);
    foreach ($keys as $key) {
    if (isset($array[$key])) {
    $array = $array[$key];
    @@ -58,25 +60,26 @@ public function get($path, $default = null)
    */
    public function set($path, $value)
    {
    $link = & $this->values;

    if (!empty($path)) {
    $keys = explode('.', $path);
    foreach ($keys as $key) {
    $at = & $this->values;
    $keys = $this->explode($path);

    if (!isset($link[$key])) {
    $link[$key] = array();
    }
    while (count($keys) > 0) {
    if (count($keys) === 1) {
    $at[array_shift($keys)] = $value;
    } else {
    $key = array_shift($keys);

    if (!is_array($link[$key])) {
    throw new \RuntimeException("Can not set value for `$key` in `$path` path because it is not array.");
    }
    if (!isset($at[$key])) {
    $at[$key] = array();
    }

    $link = & $link[$key];
    $at = & $at[$key];
    }
    }
    } else {
    $this->values = $value;
    }

    $link = $value;
    }

    /**
    @@ -95,7 +98,7 @@ public function add($path, array $values)
    */
    public function have($path)
    {
    $keys = explode('.', $path);
    $keys = $this->explode($path);
    $array = $this->values;
    foreach ($keys as $key) {
    if (isset($array[$key])) {
    @@ -108,6 +111,27 @@ public function have($path)
    return true;
    }

    /**
    * @param array $values
    */
    public function setValues($values)
    {
    $this->values = $values;
    }

    /**
    * @return array
    */
    public function getValues()
    {
    return $this->values;
    }

    protected function explode($path)
    {
    return preg_split(self::SEPARATOR, $path);
    }

    /**
    * array_merge_recursive does indeed merge arrays, but it converts values with duplicate
    * keys to arrays rather than overwriting the value in the first array with the duplicate
    @@ -160,4 +184,4 @@ protected function arrayMergeRecursiveDistinct(array &$array1, array &$array2)

    return $merged;
    }
    }
    }
    95 changes: 95 additions & 0 deletions DotNotationTest.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,95 @@
    <?php
    /* (c) Anton Medvedev <[email protected]>
    *
    * For the full copyright and license information, please view the LICENSE
    * file that was distributed with this source code.
    */

    class DotNotationTest extends \PHPUnit_Framework_TestCase
    {
    public function testSet()
    {
    $d = new DotNotation([]);
    $d->set('one', 1);
    $this->assertEquals(['one' => 1], $d->getValues());
    }

    public function testSetOverride()
    {
    $d = new DotNotation(['one' => 1]);
    $d->set('one', 2);
    $this->assertEquals(['one' => 2], $d->getValues());
    }

    public function testSetPath()
    {
    $d = new DotNotation(['one' => ['two' => 1]]);
    $d->set('one.two', 2);
    $this->assertEquals(['one' => ['two' => 2]], $d->getValues());
    }

    public function testPathAppend()
    {
    $d = new DotNotation(['one' => ['two' => 1]]);
    $d->set('one.other', 1);
    $this->assertEquals(['one' => ['two' => 1, 'other' => 1]], $d->getValues());
    }

    public function testSetAppend()
    {
    $d = new DotNotation(['one' => ['two' => 1]]);
    $d->set('two', 2);
    $this->assertEquals(['one' => ['two' => 1], 'two' => 2], $d->getValues());
    }

    public function testSetAppendArray()
    {
    $d = new DotNotation(['one' => ['two' => 1]]);
    $d->set('one', ['two' => 2]);
    $this->assertEquals(['one' => ['two' => 2]], $d->getValues());
    }

    public function testSetOverrideAndAppend()
    {
    $d = new DotNotation(['one' => ['two' => 1]]);
    $d->set('one', ['two' => 2, 'other' => 3]);
    $this->assertEquals(['one' => ['two' => 2, 'other' => 3]], $d->getValues());
    }

    public function testSetOverrideByArray()
    {
    $d = new DotNotation(['one' => ['two' => 1]]);
    $d->set('one', ['other' => 3]);
    $this->assertEquals(['one' => ['other' => 3]], $d->getValues());
    }

    public function testSetPathByDoubleDots()
    {
    $d = new DotNotation(['one' => ['two' => ['three' => 1]]]);
    $d->set('one:two:three', 3);
    $this->assertEquals(['one' => ['two' => ['three' => 3]]], $d->getValues());
    }

    public function testGet()
    {
    $d = new DotNotation(['one' => ['two' => ['three' => 1]]]);
    $this->assertEquals(['one' => ['two' => ['three' => 1]]], $d->get(null));
    $this->assertEquals(['two' => ['three' => 1]], $d->get('one'));
    $this->assertEquals(['three' => 1], $d->get('one.two'));
    $this->assertEquals(1, $d->get('one.two.three'));
    $this->assertEquals(false, $d->get('one.two.three.next', false));
    }


    public function testHave()
    {
    $d = new DotNotation(['one' => ['two' => ['three' => 1]]]);
    $this->assertTrue($d->have('one'));
    $this->assertTrue($d->have('one.two'));
    $this->assertTrue($d->have('one.two.three'));
    $this->assertFalse($d->have('one.two.three.false'));
    $this->assertFalse($d->have('one.false.three'));
    $this->assertFalse($d->have('false'));
    }
    }

  4. Elfet revised this gist Feb 5, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion DotNotation.php
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    <?php
    /**
    * Dot notation for assecc multidimensional arrays.
    * Dot notation for access multidimensional arrays.
    *
    * $dn = new DotNotation(['bar'=>['baz'=>['foo'=>true]]]);
    *
  5. Elfet created this gist Feb 5, 2013.
    163 changes: 163 additions & 0 deletions DotNotation.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,163 @@
    <?php
    /**
    * Dot notation for assecc multidimensional arrays.
    *
    * $dn = new DotNotation(['bar'=>['baz'=>['foo'=>true]]]);
    *
    * $value = $dn->get('bar.baz.foo'); // $value == true
    *
    * $dn->set('bar.baz.foo', false); // ['foo'=>false]
    *
    * $dn->add('bar.baz', ['boo'=>true]); // ['foo'=>false,'boo'=>true]
    *
    * @author Anton Medvedev <anton (at) elfet (dot) ru>
    * @version 1.0
    * @license MIT
    */
    class DotNotation
    {
    /**
    * @var array
    */
    protected $values = array();

    /**
    * @var array
    */
    public function __construct(array $values)
    {
    $this->values = $values;
    }

    /**
    * @param string $path
    * @param string $default
    * @return mixed
    */
    public function get($path, $default = null)
    {
    $array = $this->values;

    if (!empty($path)) {
    $keys = explode('.', $path);
    foreach ($keys as $key) {
    if (isset($array[$key])) {
    $array = $array[$key];
    } else {
    return $default;
    }
    }
    }

    return $array;
    }

    /**
    * @param string $path
    * @param mixed $value
    */
    public function set($path, $value)
    {
    $link = & $this->values;

    if (!empty($path)) {
    $keys = explode('.', $path);
    foreach ($keys as $key) {

    if (!isset($link[$key])) {
    $link[$key] = array();
    }

    if (!is_array($link[$key])) {
    throw new \RuntimeException("Can not set value for `$key` in `$path` path because it is not array.");
    }

    $link = & $link[$key];
    }
    }

    $link = $value;
    }

    /**
    * @param $path
    * @param array $values
    */
    public function add($path, array $values)
    {
    $get = (array)$this->get($path);
    $this->set($path, $this->arrayMergeRecursiveDistinct($get, $values));
    }

    /**
    * @param string $path
    * @return bool
    */
    public function have($path)
    {
    $keys = explode('.', $path);
    $array = $this->values;
    foreach ($keys as $key) {
    if (isset($array[$key])) {
    $array = $array[$key];
    } else {
    return false;
    }
    }

    return true;
    }

    /**
    * array_merge_recursive does indeed merge arrays, but it converts values with duplicate
    * keys to arrays rather than overwriting the value in the first array with the duplicate
    * value in the second array, as array_merge does. I.e., with array_merge_recursive,
    * this happens (documented behavior):
    *
    * array_merge_recursive(array('key' => 'org value'), array('key' => 'new value'));
    * => array('key' => array('org value', 'new value'));
    *
    * arrayMergeRecursiveDistinct does not change the datatypes of the values in the arrays.
    * Matching keys' values in the second array overwrite those in the first array, as is the
    * case with array_merge, i.e.:
    *
    * arrayMergeRecursiveDistinct(array('key' => 'org value'), array('key' => 'new value'));
    * => array('key' => array('new value'));
    *
    * Parameters are passed by reference, though only for performance reasons. They're not
    * altered by this function.
    *
    * If key is integer, it will be merged like array_merge do:
    * arrayMergeRecursiveDistinct(array(0 => 'org value'), array(0 => 'new value'));
    * => array(0 => 'org value', 1 => 'new value');
    *
    * @param array $array1
    * @param array $array2
    * @return array
    * @author Daniel <daniel (at) danielsmedegaardbuus (dot) dk>
    * @author Gabriel Sobrinho <gabriel (dot) sobrinho (at) gmail (dot) com>
    * @author Anton Medvedev <anton (at) elfet (dot) ru>
    */
    protected function arrayMergeRecursiveDistinct(array &$array1, array &$array2)
    {
    $merged = $array1;

    foreach ($array2 as $key => &$value) {
    if (is_array($value) && isset ($merged[$key]) && is_array($merged[$key])) {
    if (is_int($key)) {
    $merged[] = $this->arrayMergeRecursiveDistinct($merged[$key], $value);
    } else {
    $merged[$key] = $this->arrayMergeRecursiveDistinct($merged[$key], $value);
    }
    } else {
    if (is_int($key)) {
    $merged[] = $value;
    } else {
    $merged[$key] = $value;
    }
    }
    }

    return $merged;
    }
    }