Advanced Selector Syntax Guide

This guide covers the advanced selector syntax features that make Derafu Selector powerful for complex data manipulation.

String Literals and Concatenation

You can include literal strings in your selectors and concatenate them with values from your data:

$data = ['user' => ['name' => 'John']];

// Simple string concatenation.
$greeting = Selector::get($data, '"Hello, "(user.name)"!"');
// "Hello, John!"

// Multiple concatenations.
$message = Selector::get($data, '"User "(user.name)" logged in at "(timestamp)');
// "User John logged in at 2023-04-15 10:30:45"

OR Operator for Fallbacks

The || operator provides fallback values when a selector path doesn’t exist or returns null:

$data = [
    'user' => [
        'name' => 'John',
        'email' => '[email protected]',
        // phone is not set
    ],
];

// Use email if phone doesn't exist.
$contact = Selector::get($data, 'user.phone||user.email');
// "[email protected]"

// Chains of fallbacks.
$identifier = Selector::get($data, 'user.id||user.username||user.email');
// "[email protected]"

// Fallback to a literal string.
$phone = Selector::get($data, 'user.phone||"Not provided"');
// "Not provided"

// Combine with string concatenation.
$phoneDisplay = Selector::get($data, '"Phone: "(user.phone||"N/A")');
// "Phone: N/A"

Conditional (Ternary) Selectors

Conditionals let you choose between different selector paths based on conditions:

$data = [
    'user' => [
        'type' => 'admin',
        'admin_role' => 'super_admin',
        'user_role' => 'regular',
    ],
];

// Simple condition using equality.
$role = Selector::get($data,
    '((user.type) = "admin" ? (user.admin_role) : (user.user_role))'
); // "super_admin"

// Using not equal.
$accessLevel = Selector::get($data,
    '((user.type) != "guest" ? ("authenticated") : ("anonymous"))'
); // "authenticated"

// Numeric comparisons.
$data = ['score' => 85];
$grade = Selector::get($data,
    '((score) >= "90" ? ("A") : ((score) >= "80" ? ("B") : ("C")))'
); // "B"

Dependent Selectors

Find and access specific elements in arrays based on key/value matching:

$data = [
    'users' => [
        ['id' => 101, 'name' => 'John', 'email' => '[email protected]'],
        ['id' => 102, 'name' => 'Jane', 'email' => '[email protected]'],
        ['id' => 103, 'name' => 'Bob', 'email' => '[email protected]'],
    ],
];

// Get the name of user with id 102.
$name = Selector::get($data, 'users[id=102:name]');
// "Jane"

// Get the email of user with id 101.
$email = Selector::get($data, 'users[id=101:email]');
// "[email protected]"

// Nested properties.
$data = [
    'orders' => [
        [
            'id' => 1001,
            'customer' => ['id' => 101, 'name' => 'John'],
            'items' => [['product' => 'Laptop', 'price' => 999]],
        ],
        [
            'id' => 1002,
            'customer' => ['id' => 102, 'name' => 'Jane'],
            'items' => [['product' => 'Phone', 'price' => 699]],
        ],
    ],
];

// Get Jane's first order item.
$janeProduct = Selector::get($data, 'orders[id=1002:items][0].product');
// "Phone"

// Access by string values with special characters.
$data = [
    'categories' => [
        ['id' => 'cat-1', 'name' => 'Electronics'],
        ['id' => 'cat-2', 'name' => 'Books']
    ]
];

$catName = Selector::get($data, 'categories[id=cat-1:name]');
// "Electronics"

Comparison Operators

Conditional selectors support several comparison operators:

$data = [
    'product' => [
        'price' => 50,
        'stock' => 10,
        'name' => 'Gadget',
        'tags' => ['electronics', 'new'],
    ],
];

// Equality.
$isGadget = Selector::get($data,
    '((product.name) = "Gadget" ? ("Yes") : ("No"))'
); // "Yes"

// Not equal.
$isExpensive = Selector::get($data,
    '((product.price) != "100" ? ("Affordable") : ("Expensive"))'
); // "Affordable"

// Greater than.
$priceTier = Selector::get($data,
    '((product.price) > "75" ? ("Premium") : ("Standard"))'
); // "Standard"

// Less than or equal.
$stockStatus = Selector::get($data,
    '((product.stock) <= "5" ? ("Low Stock") : ("In Stock"))'
); // "In Stock"

// Contains (for arrays and strings).
$isNew = Selector::get($data,
    '((product.tags) contains "new" ? ("New Arrival") : ("Regular Item"))'
); // "New Arrival"

// Length check.
$nameLength = Selector::get($data,
    '((product.name) length "6" ? ("Six Letters") : ("Other Length"))'
); // "Six Letters"

// Null check.
$data['product']['description'] = null;
$hasDescription = Selector::get($data,
    '((product.description) is "null" ? ("No Description") : ("Has Description"))'
); // "No Description"

Special Functions

The selector syntax includes several special functions:

$data = [
    'product' => [
        'name' => 'Gadget',
        'price' => 49.99,
        'tags' => ['electronics', 'gadget', 'new'],
    ],
];

// contains - check if an array or string contains a value.
$hasTag = Selector::get($data,
    '((product.tags) contains "gadget" ? ("Tagged as gadget") : ("Not tagged"))'
); // "Tagged as gadget"

// length - check the length of a string or array.
$tagCount = Selector::get($data,
    '((product.tags) length "3" ? ("Has 3 tags") : ("Has another tag count"))'
); // "Has 3 tags"

$nameLength = Selector::get($data,
    '((product.name) length "6" ? ("Name has 6 chars") : ("Name has different length"))'
); // "Name has 6 chars"

// is - check the type of a value (currently supports null checks).
$hasDescription = Selector::get($data,
    '((product.description) is "null" ? ("No description") : ("Has description"))'
); // "No description"

Parentheses and Escaping

The selector syntax uses parentheses and quotes extensively:

// (selector) extracts a value from the data
// "string" is a literal string

$data = ['message' => 'Hello World'];

// Simple extraction.
$msg = Selector::get($data, '(message)'); // "Hello World"

// Literal string.
$literal = Selector::get($data, '"Static text"'); // "Static text"

// Concatenating extractions and literals.
$full = Selector::get($data, '(message)" - welcome!"'); // "Hello World - welcome!"

// Escaping quotes and parentheses.
$escaped = Selector::get($data, '"This is a \\"quoted\\" string"'); // 'This is a "quoted" string'
$parentheses = Selector::get($data, '"Formula: (x + y)"'); // "Formula: (x + y)"

// Nested parentheses for complex expressions.
$nested = Selector::get($data, '((message) = "Hello World" ? ("Greeting") : ("Other message"))');
// "Greeting"

For even more advanced capabilities, explore the integration with JSONPath and JMESPath in their respective guides.