Dot allows you to get & set array keys or object properties using dot notation.
composer require noj/dot
First construct a new Dot instance:
$dot = new Dot($data);
$dot = Dot::from($data); // alternative
All the examples are using the following data structure unless otherwise specified:
$data = [
'groups' => [
(object)[
'name' => 'group1',
'items' => [
[
'name' => 'item1',
'rare' => false,
],
[
'name' => 'item3',
'rare' => true,
],
]
],
(object)[
'name' => 'group2',
'items' => []
],
(object)[
'name' => 'group3',
'items' => [
[
'name' => 'item2',
'rare' => true,
],
]
],
]
];
Count the number of items at a given path.
$dot->count('groups.0.items'); // 2
$dot->count('groups.*.items'); // 3
Find items that pass the given truth test.
// find where property === value
$dot->find('groups.*.items.*.rare', true)->get();
/*
[
['name' => 'item3', 'rare' => true],
['name' => 'item2', 'rare' => true],
]
*/
// pass a callback for custom comparisons
$dot->find('groups.*.items.*.name', function (string $name) {
return $name === 'item2' || $name === 'item3';
})->get(); // returns same as above
// leave off the property to receive the whole item
$dot->find('groups.*.items.*', function (array $item) {
return $item['name'] === 'item3' && $item['rare'];
})->get();
Find the first item that passes the given truth test.
$dot->first('groups.*.items.*.rare', true)->get(); // ['name' => 'item3', 'rare' => true]
$dot->first('groups.*.items.*', function (array $item) {
return $item['rare'] === true;
})->get(); // same as above
Access nested array keys and object properties using dot syntax:
$dot->get('groups.0.items.1.name'); // 'item3'
Dot safely returns null if the key or property doesn't exist:
$dot->get('groups.3.items.1.name'); // null
You can use a wildcard *
to pluck values from multiple paths:
$dot->get('groups.*.items.*.name'); // ['item1', 'item3', 'item2']
$dot->get('groups.*.items'); /* [
['name' => 'item1', 'rare' => false],
['name' => 'item3', 'rare' => true],
['name' => 'item2', 'rare' => true],
] */
You can call functions using the @
prefix:
$data = [
'foo' => new class {
public function getBar() {
return ['bar' => 'value'];
}
}
];
(new Dot($data))->get('foo.@getBar.bar'); // 'value'
If no argument is passed it will return the underlying data:
$dot->get() === $data; // true
Returns true if path exists, false otherwise:
$dot->has('groups.0.items.1.name'); // true
Push a value onto an existing array:
$dot->push('groups.0.items', ['name' => 'another item']);
// supports wildcards
$dot->push('groups.*.items', ['name' => 'another item']);
You can set nested values using the same syntax:
$dot->set('groups.2.items.0.name', 'a different name');
echo $data['groups'][2]->items[0]['name']; // 'a different name'
Set nested keys from multiple paths using a wildcard *
:
$dot->set('groups.*.items.*.name', 'set all to same name');
Keys will be created if they don't already exist:
$dot->set('groups.0.items.2.name', 'a new item');
By default, set will initialise missing values as empty arrays. To indicate that something should be an object use the ->
delimiter:
$dot->set('groups.3->items.2.name', 'a new item');
You can set multiple values at once by passing an array:
$dot->set([
'groups.0.items.1.name' => 'something',
'groups.2.items.0.name' => 'something else',
]):
You can call a method:
$data = [
'foo' => new class {
public $bars = [];
public function addBar($bar) {
$this->bar[] = $bar;
}
}
];
$dot = new Dot($data);
$dot->set('foo.@addBar', 'value');
echo $data['foo']->bars; // ['value']
Or call a method for each value of an array:
$dot->set('foo.@addBar*', ['value1', 'value2']);
echo $data['foo']->bars; // ['value1', 'value2']
All methods have non-chained versions of themselves as a standalone function, i.e:
// instead of
$filtered = \Noj\Dot\Dot::from($data)
->find('groups.*.items.*.rare', true)
->get();
// you can do
$filtered = \Noj\Dot\find($data, 'groups.*.items.*.rare', true');