tedon/tooner

PHP TOON (Token-Oriented Object Notation) encoder/decoder

Installs: 9

Dependents: 1

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/tedon/tooner

v1.0.0 2025-11-19 20:38 UTC

This package is auto-updated.

Last update: 2025-11-20 12:34:02 UTC


README

A PHP library for encoding and decoding data in TOON format - a human-readable, YAML-like serialization format optimized for readability and efficiency.

Features

  • YAML-like syntax - Indentation-based structure for nested objects and arrays
  • Tabular arrays - Compact representation for arrays of uniform objects
  • Key folding - Flatten and unfold nested keys using dot notation
  • Type support - Handles primitives, objects, arrays, and DateTime objects
  • Configurable - Fine-tune encoding/decoding behavior via configuration
  • Laravel integration - Optional Laravel service provider and facade
  • PHP 8.2+ - Built for modern PHP with strict types and match expressions

What is TOON?

TOON (Token-Oriented Object Notation) is a serialization format that combines the readability of YAML with efficient encoding strategies:

user:
  name: John Doe
  email: john@example.com
  age: 30

tags[3]: php,laravel,api

posts[2]{id,title,views}:
  1,"Hello World",150
  2,"PHP Tips",320

Key Benefits

  • Human-readable - Easy to read and edit manually
  • Compact tabular format - Efficient for arrays of uniform objects
  • Type-aware - Preserves data types (strings, numbers, booleans, dates)
  • Configurable depth - Control nesting levels and output format

Installation

Install via Composer:

composer require tedon/tooner

Basic Usage

Standalone Usage

use Tedon\Tooner\Tooner;

// Create instance
$tooner = new Tooner();

// Encode data to TOON format
$data = [
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'age' => 30,
    'active' => true
];

$encoded = $tooner->encode($data);
echo $encoded;
// Output:
// name: John Doe
// email: john@example.com
// age: 30
// active: true

// Decode TOON string back to PHP
$decoded = $tooner->decode($encoded);
print_r($decoded);

Laravel Usage

For Laravel applications, the package automatically registers a service provider and facade.

Using the Facade

use Tedon\Tooner\Facades\Tooner;

// Encode
$toon = Tooner::encode(['key' => 'value']);

// Decode
$data = Tooner::decode($toon);

Using Dependency Injection

use Tedon\Tooner\Tooner;

class MyController extends Controller
{
    public function __construct(private Tooner $tooner)
    {
    }

    public function store(Request $request)
    {
        $encoded = $this->tooner->encode($request->all());
        // Store or process $encoded
    }
}

Configuration

Laravel Configuration

Publish the configuration file:

php artisan vendor:publish --provider="Tedon\Tooner\ToonerServiceProvider" --tag="config"

This creates config/tooner.php with the following options:

return [
    // Validate array lengths during decoding
    'validate_lengths' => true,

    // Attempt to restore DateTime objects from date strings
    'restore_dates' => true,

    // Maximum nesting depth for encoding/decoding
    'max_depth' => 100,

    // Return associative arrays instead of objects when decoding
    'object_as_array' => false,

    // Enable key folding (flatten nested keys with dots)
    'key_folding' => true,

    // Use tabular format for arrays of uniform objects
    'tabular_arrays' => true,

    // Number of spaces per indentation level
    'indentation' => 2,

    // Character to use for indentation (space or tab)
    'indent_char' => ' ',

    // Include explicit array lengths in output
    'explicit_lengths' => true,

    // Skip null values when encoding objects
    'skip_nulls' => false,

    // Normalize numeric string keys ("0", "1") to integers (0, 1)
    'normalize_numeric_keys' => true,
];

Standalone Configuration

Pass configuration as constructor parameter or method options:

$tooner = new Tooner([
    'indentation' => 4,
    'key_folding' => false,
]);

// Or per-operation
$encoded = $tooner->encode($data, [
    'tabular_arrays' => false,
    'explicit_lengths' => false,
]);

Advanced Examples

Simple Arrays

$data = ['apple', 'banana', 'cherry'];
$encoded = $tooner->encode($data);
// Output: [3]: apple,banana,cherry

Nested Objects

$data = [
    'user' => [
        'profile' => [
            'name' => 'Jane',
            'location' => 'NYC'
        ]
    ]
];

$encoded = $tooner->encode($data);
// Output:
// user:
//   profile:
//     name: Jane
//     location: NYC

Key Folding

$tooner = new Tooner(['key_folding' => true]);

$data = [
    'database' => [
        'host' => 'localhost',
        'port' => 3306
    ]
];

$encoded = $tooner->encode($data);
// Output:
// database.host: localhost
// database.port: 3306

Tabular Arrays

Perfect for arrays of uniform objects like database records:

$users = [
    ['id' => 1, 'name' => 'Alice', 'role' => 'admin'],
    ['id' => 2, 'name' => 'Bob', 'role' => 'user'],
    ['id' => 3, 'name' => 'Charlie', 'role' => 'user'],
];

$encoded = $tooner->encode($users);
// Output:
// [3]{id,name,role}:
//   1,Alice,admin
//   2,Bob,user
//   3,Charlie,user

Complex Nested Structures

$data = [
    'project' => 'My App',
    'version' => '1.0.0',
    'features' => [
        ['name' => 'Auth', 'status' => 'complete'],
        ['name' => 'API', 'status' => 'in-progress'],
    ],
    'config' => [
        'debug' => true,
        'cache' => [
            'driver' => 'redis',
            'ttl' => 3600
        ]
    ]
];

$encoded = $tooner->encode($data);
// Output:
// project: My App
// version: 1.0.0
// features[2]{name,status}:
//   Auth,complete
//   API,in-progress
// config:
//   debug: true
//   cache:
//     driver: redis
//     ttl: 3600

DateTime Support

use DateTime;

$data = [
    'created_at' => new DateTime('2025-01-15 10:30:00'),
    'updated_at' => new DateTime('2025-01-16 15:45:00'),
];

$encoded = $tooner->encode($data);
// Dates are encoded as ISO 8601 strings
// Output:
// created_at: "2025-01-15T10:30:00+00:00"
// updated_at: "2025-01-16T15:45:00+00:00"

// Decode with date restoration
$tooner = new Tooner(['restore_dates' => true]);
$decoded = $tooner->decode($encoded);
// DateTime objects are automatically restored

Skipping Null Values

When working with database records or APIs, you often have null values that you want to omit from the output:

$users = [
    [
        'id' => 7,
        'first_name' => 'John',
        'last_name' => 'Doe',
        'email' => 'test@yahoo.com',
        'status' => 0,
    ],
    [
        'id' => 13,
        'first_name' => 'Jolie',
        'last_name' => 'Diss',
        'email' => 'example@gmail.com',
        'status' => 1,
    ],
];

// Enable skip_nulls to omit null values
$tooner = new Tooner(['skip_nulls' => true]);
$encoded = $tooner->encode($users);

// Output - only non-null fields are shown.

Direct Encoder/Decoder Access

For more control, use the encoder and decoder directly:

use Tedon\Tooner\ToonEncoder;
use Tedon\Tooner\ToonDecoder;

$encoder = new ToonEncoder(['indentation' => 4]);
$encoded = $encoder->encode($data);

$decoder = new ToonDecoder(['validate_lengths' => false]);
$decoded = $decoder->decode($encoded);

Error Handling

The library throws specific exceptions for encoding and decoding errors:

use Tedon\Tooner\Exceptions\ToonEncodingException;
use Tedon\Tooner\Exceptions\ToonDecodingException;

try {
    $encoded = $tooner->encode($complexData);
} catch (ToonEncodingException $e) {
    // Handle encoding errors (e.g., max depth exceeded, unsupported types)
    echo "Encoding failed: " . $e->getMessage();
}

try {
    $decoded = $tooner->decode($toonString);
} catch (ToonDecodingException $e) {
    // Handle decoding errors (e.g., invalid format, length mismatch)
    echo "Decoding failed: " . $e->getMessage();
}

Configuration Options Reference

Option Type Default Description
validate_lengths bool true Validate array lengths match declared lengths during decoding
restore_dates bool true Attempt to convert ISO 8601 strings back to DateTime objects
max_depth int 100 Maximum nesting depth allowed for encoding/decoding
object_as_array bool false Return associative arrays instead of stdClass objects when decoding
key_folding bool true Flatten nested single-value objects using dot notation
tabular_arrays bool true Use compact tabular format for arrays of uniform objects
indentation int 2 Number of indent characters per level
indent_char string ' ' Character used for indentation (space or tab)
explicit_lengths bool true Include [n] length indicators in array declarations
skip_nulls bool false Skip properties with null values when encoding objects
normalize_numeric_keys bool true Convert numeric string keys ("0", "1") to integer keys for proper array formatting

Use Cases

Configuration Files

TOON's readable format makes it ideal for configuration files:

$config = $tooner->decode(file_get_contents('config.toon'));

Data Export

Export database records in a human-readable format:

$users = User::all()->toArray();
file_put_contents('users.toon', $tooner->encode($users));

API Responses

Alternative to JSON for APIs where readability matters:

return response($tooner->encode($data))
    ->header('Content-Type', 'application/toon');

Data Transfer

Compact format for transferring structured data between systems:

$serialized = $tooner->encode($largeDataset);
// Transfer $serialized
$restored = $tooner->decode($serialized);

Requirements

  • PHP 8.2 or higher
  • Optional: Laravel 10.x, 11.x, or 12.x for framework integration

Testing

composer test

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see the LICENSE file for details.

Author

Pouya Zouravand

Credits

Inspired by YAML and JSON, TOON aims to provide a balanced approach between human readability and efficient data representation.