/ JSON Columns

JSON Columns

Miko ORM provides support for JSON columns with dot notation access. Store and manipulate JSON data directly in your database columns.


JSON Column Methods Summary

Method Description
getJson($column, $key)Get value from JSON column
setJson($column, $key, $value)Set value in JSON column
appendJson($column, $key, $value)Append to array in JSON
removeJson($column, $key)Remove key from JSON
hasJson($column, $key)Check if key exists
incrementJson($column, $key)Increment numeric value
decrementJson($column, $key)Decrement numeric value

Using JsonColumnTrait

Add the trait to your model to enable JSON column support.

use Miko\Database\ORM\Model;
use Miko\Database\ORM\JsonColumnTrait;

class User extends Model
{
    use JsonColumnTrait;
    
    // Define which columns contain JSON data
    protected array $jsonColumns = ['settings', 'metadata', 'preferences'];
}

Setting JSON Values

Set Entire JSON Object

$user = User::find(1);

// Set entire JSON column
$user->setJson('settings', [
    'theme' => 'dark',
    'language' => 'en',
    'notifications' => [
        'email' => true,
        'push' => false
    ]
]);

$user->save();

Set Specific Key

// Set single key
$user->setJson('settings', 'theme', 'light');

// Set nested key with dot notation
$user->setJson('settings', 'notifications.email', false);
$user->setJson('settings', 'notifications.sms', true);

$user->save();

Set Deep Nested Values

// Create deep nested structure
$user->setJson('metadata', 'social.twitter.username', '@johndoe');
$user->setJson('metadata', 'social.twitter.followers', 1500);
$user->setJson('metadata', 'social.linkedin.url', 'linkedin.com/in/johndoe');

$user->save();

// Result:
// {
//   "social": {
//     "twitter": { "username": "@johndoe", "followers": 1500 },
//     "linkedin": { "url": "linkedin.com/in/johndoe" }
//   }
// }

Getting JSON Values

Get Entire JSON

$user = User::find(1);

// Get entire JSON as array
$settings = $user->getJson('settings');

print_r($settings);
// Array ( [theme] => dark, [language] => en, ... )

Get Specific Key

// Get single key
$theme = $user->getJson('settings', 'theme');
echo $theme; // "dark"

// Get nested key with dot notation
$emailNotif = $user->getJson('settings', 'notifications.email');
echo $emailNotif; // true

Get with Default Value

// Returns default if key doesn't exist
$timezone = $user->getJson('settings', 'timezone', 'UTC');
$currency = $user->getJson('preferences', 'currency', 'USD');

Array Operations

Append to Array

// Append single value
$user->appendJson('settings', 'tags', 'vip');
$user->appendJson('settings', 'tags', 'premium');

// Result: { "tags": ["vip", "premium"] }

// Append to nested array
$user->appendJson('metadata', 'history.logins', date('Y-m-d H:i:s'));

Remove from JSON

// Remove key
$user->removeJson('settings', 'deprecated_option');

// Remove nested key
$user->removeJson('metadata', 'social.twitter');

$user->save();

Numeric Operations

Increment

// Increment by 1
$user->incrementJson('metadata', 'login_count');

// Increment by specific amount
$user->incrementJson('metadata', 'points', 50);

// Increment nested value
$user->incrementJson('stats', 'visits.total', 1);

$user->save();

Decrement

// Decrement by 1
$user->decrementJson('metadata', 'credits');

// Decrement by specific amount
$user->decrementJson('metadata', 'balance', 25.50);

$user->save();

Check Key Existence

// Check if key exists
if ($user->hasJson('settings', 'theme')) {
    echo "Theme is set";
}

// Check nested key
if ($user->hasJson('metadata', 'social.twitter')) {
    echo "Twitter connected";
}

JsonDictionary Class

A standalone class for working with JSON key-value data.

use Miko\Database\ORM\JsonDictionary;

// Create from array
$dict = new JsonDictionary([
    'name' => 'John',
    'age' => 30
]);

// Create from JSON string
$dict = new JsonDictionary('{"name":"John","age":30}');

// Set values
$dict->set('email', 'john@example.com');
$dict['phone'] = '555-1234';  // Array access

// Get values
echo $dict->get('name');      // "John"
echo $dict['age'];            // 30
echo $dict->get('missing', 'default');  // "default"

// Check existence
if ($dict->has('email')) {
    echo "Has email";
}

// Remove
$dict->remove('phone');

// Convert
$array = $dict->toArray();
$json = $dict->toJson();

// Iterate
foreach ($dict as $key => $value) {
    echo "$key: $value\n";
}

// Count
echo count($dict);  // 3

JsonList Class

A standalone class for working with JSON arrays.

use Miko\Database\ORM\JsonList;

// Create from array
$list = new JsonList(['apple', 'banana', 'orange']);

// Create from JSON string
$list = new JsonList('["apple","banana","orange"]');

// Add items
$list->add('grape');
$list->addRange(['mango', 'kiwi']);
$list[] = 'pear';  // Array access

// Get items
echo $list->get(0);     // "apple"
echo $list[1];          // "banana"
echo $list->first();    // "apple"
echo $list->last();     // "pear"

// Check & Find
if ($list->contains('banana')) {
    echo "Has banana";
}
$index = $list->indexOf('orange');  // 2

// Remove
$list->remove('banana');     // Remove by value
$list->removeAt(0);          // Remove by index

// Clear
$list->clear();

// Convert
$array = $list->toArray();
$json = $list->toJson();

// Iterate
foreach ($list as $item) {
    echo $item . "\n";
}

// Count
echo count($list);

Practical Examples

User Settings

class User extends Model
{
    use JsonColumnTrait;
    
    protected array $jsonColumns = ['settings'];
    
    // Helper methods
    public function getTheme(): string
    {
        return $this->getJson('settings', 'theme', 'light');
    }
    
    public function setTheme(string $theme): void
    {
        $this->setJson('settings', 'theme', $theme);
    }
    
    public function isNotificationEnabled(string $type): bool
    {
        return $this->getJson('settings', "notifications.$type", true);
    }
    
    public function toggleNotification(string $type): void
    {
        $current = $this->isNotificationEnabled($type);
        $this->setJson('settings', "notifications.$type", !$current);
    }
}

// Usage
$user = User::find(1);
$user->setTheme('dark');
$user->toggleNotification('email');
$user->save();

Product Attributes

class Product extends Model
{
    use JsonColumnTrait;
    
    protected array $jsonColumns = ['attributes', 'specifications'];
    
    public function getAttribute(string $key, $default = null)
    {
        return $this->getJson('attributes', $key, $default);
    }
    
    public function setAttributes(array $attributes): void
    {
        foreach ($attributes as $key => $value) {
            $this->setJson('attributes', $key, $value);
        }
    }
}

// Usage
$product = Product::find(1);
$product->setAttributes([
    'color' => 'red',
    'size' => 'large',
    'weight' => 2.5
]);
$product->setJson('specifications', 'dimensions', [
    'width' => 10,
    'height' => 20,
    'depth' => 5
]);
$product->save();

echo $product->getAttribute('color');  // "red"

Activity Log

class User extends Model
{
    use JsonColumnTrait;
    
    protected array $jsonColumns = ['activity_log'];
    
    public function logActivity(string $action, array $data = []): void
    {
        $entry = [
            'action' => $action,
            'data' => $data,
            'timestamp' => date('Y-m-d H:i:s'),
            'ip' => $_SERVER['REMOTE_ADDR'] ?? null
        ];
        
        $this->appendJson('activity_log', 'entries', $entry);
        $this->incrementJson('activity_log', 'total_actions');
        $this->save();
    }
    
    public function getRecentActivity(int $limit = 10): array
    {
        $entries = $this->getJson('activity_log', 'entries', []);
        return array_slice(array_reverse($entries), 0, $limit);
    }
}

// Usage
$user = User::find(1);
$user->logActivity('login', ['browser' => 'Chrome']);
$user->logActivity('view_product', ['product_id' => 123]);

$recent = $user->getRecentActivity(5);