rkt/magento-data

Data Object & Data Transfer Objects for Magento 2

Installs: 20

Dependents: 3

Suggesters: 0

Security: 0

Stars: 1

Watchers: 1

Forks: 1

Open Issues: 0

Type:magento2-module

dev-main 2025-06-01 10:36 UTC

This package is auto-updated.

Last update: 2025-06-01 10:36:19 UTC


README

A powerful, lightweight Data Object & DTO (Data Transfer Object) system for Magento 2 β€” supporting smart instantiation, validation, and serialization.

πŸš€ Installation

composer require rkt/magento-data

✨ Features Overview

1. βœ… Easy Data Object Instantiation

Use the static from() or create() methods to easily instantiate data objects.

Example

use Rkt\MageData\Data;

class ProductImageData extends Data
{
    public function __construct(
        public string $src,
        public ?string $alt = null,
    ) {}
}

You can instantiate it like this:

$image = ProductImageData::from([
    'src' => 'https://example.com/image.jpg',
    'alt' => 'Awesome image'
]);

Or using create():

$image = ProductImageData::create([
    'src' => 'https://example.com/image.jpg',
    'alt' => 'Awesome image'
]);

2. πŸ›‘ Validation Built In

This module includes built-in validation using rakit/validation.

πŸ”Ή Basic Validation

Just define a rules() method in your data object:

class Customer extends Data
{
    public function __construct(
        public string $email,
        public string $firstname,
        public string $lastname,
        public array $street,
    ) {}

    public function rules(): array
    {
        return [
            'email' => 'email|required',
            'firstname' => 'required|min:1|max:250',
            'lastname' => 'required|min:1|max:250',
            'street.0' => 'required',
        ];
    }
}

You can validate array elements (like street.0) using dot notation.

πŸ”Ή Custom Validation Messages

Override messages():

public function messages(): array
{
    return [
        'email:email' => __('Customer email is invalid.'),
        'firstname:required' => __('First name cannot be empty.'),
    ];
}

πŸ”Ή Custom Field Aliases

Override aliases():

public function aliases(): array
{
    return [
        'email' => __('Email Address'),
    ];
}

In error messages, email will now appear as "Email Address".

3. 🧩 Nested Object Validation

Nested and recursive validation works out of the box:

class Person extends Data
{
    public function __construct(public string $firstname) {}

    public function rules(): array
    {
        return ['firstname' => 'required'];
    }
}

class Family extends Data
{
    public function __construct(
        public Person $father,
        public Person $mother,
        public ?array $children = [],
    ) {}

    public function rules(): array
    {
        return [
            'father' => 'required',
            'mother' => 'required',
        ];
    }
}

βœ… In this setup:

  • father and mother are required and must pass Person validation.
  • children can be a list of Person, and they’ll be validated too (if provided).

4. πŸ”Ή Custom Validation Rules via customRules()

You can define reusable or inline validation rules using customRules(). Two types of custom rules are supported:

βœ… 1. Closure-Based Rules

Use closures for simple, inline validation logic.

public function rules(): array
{
    return [
        'email' => 'required|company_email',
    ];
}

public function customRules(): array
{
    return [
        'company_email' => function ($value) {
            return str_ends_with($value, '@example.com');
        },
    ];
}

ℹ️ The closure is automatically registered using the callback rule provided by rakit/validation.

βœ… 2. Custom Rule Class

For more reusable or complex logic, use a rule class. The given rule must be in compliance with rakit/validation. Basically the rule class must extend Rakit\Validation\Rule.

use Rakit\Validation\Rule;

class CompanyEmailRule extends Rule
{
    protected $message = ':attribute must be a company email (e.g. @example.com).';

    public function check($value): bool
    {
        return str_ends_with($value, '@example.com');
    }
}
public function rules(): array
{
    return [
        'email' => 'required|company_email',
    ];
}

public function customRules(): array
{
    return [
        'company_email' => CompanyEmailRule::class,
    ];
}

βœ… You can also return an instantiated object if needed β€” it will be registered directly.

5. 🧡 Event-Driven Rule Customization

You can dynamically modify validation rules/messages/aliases using Magento events.

πŸ”Ή Example

namespace Rkt\Example\Data;

class MyData extends Data
{
    public function __construct(public string $email) {}

    public function rules(): array
    {
        return ['email' => 'required'];
    }
}

πŸ”Έ Event Name

When validate() is called, the event rkt_example_data_mydata_validate_before is dispatched.

πŸ”Ή Observer Configuration (events.xml)

<event name="rkt_example_data_mydata_validate_before">
    <observer name="update_mydata_validation_data"
              instance="Rkt\Example\Observer\UpdateMyDataValidation" />
</event>

πŸ”Ή Sample Observer

class UpdateMyDataValidation implements ObserverInterface
{
    public function execute(Observer $observer)
    {
        $transport = $observer->getData('transport');

        $rules = $transport->getData('rules');
        $rules['email'] = 'required|email';

        $aliases = $transport->getData('aliases');
        $aliases['email'] = 'Email Address';

        $transport->setData('rules', $rules);
        $transport->setData('aliases', $aliases);
    }
}

βœ… Now your validation dynamically adds the email rule and alias based on observer logic.

6. πŸ”„ Serialization Support

Convert data objects to array or JSON easily:

$data->toArray(); // β†’ returns an array representation

$data->toJson(); // β†’ returns a JSON string

7. Fetch validations rules applicable to the data

You can get the validation rules applicable for a payload like this.

class Family extends Data
{
    public function __construct(
        public Person $father,
        public Person $mother,
        public ?array $children = [],
    ) {
    }

    public function rules(): array
    {
        return [
            'father' => 'required',
            'mother' => 'required',
            'children' => 'array|nullable'
        ];
    }
}

class Person extends Data
{
    use UseValidation;

    public function __construct(
        public string $firstname,
        public string $lastname,
        public string $email,
    ) {
    }

    public function rules(): array
    {
        return [
            'email' => 'required|email',
            'firstname' => 'required',
            'lastname' => 'required',
        ];
    }
}

Now if you call

$rules = Family::getValidationRules([
    'father' => ['firstname' => 'John', 'lastname' => 'Doe', 'email' => 'john@example.com'],
    'mother' => ['firstname' => 'Jane', 'lastname' => 'Doe', 'email' => 'jane@example.com'],
    'children' => [
        ['firstname' => 'Jimmy', 'lastname' => 'Doe', 'email' => 'jimmy@example.com'],
    ],
]);

Will provide you below result:

$rules = [
    'father' => 'required',
    'father.firstname' => 'required',
    'father.lastname' => 'required',
    'father.email' => 'required|email',
    'mother' => 'required',
    'mother.firstname' => 'required',
    'mother.lastname' => 'required',
    'mother.email' => 'required|email',
    'children' => 'array|null',
]

πŸ“Œ Notes

  • This module is under active development β€” more features and integrations are coming soon!
  • Built for flexibility, testability, and ease of use in Magento 2 backend and frontend service layers.

πŸ’¬ Stay Connected

Got feedback or feature requests? PRs and ideas are welcome!