1. Go to this page and download the library: Download zero-to-prod/data-model library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
zero-to-prod / data-model example snippets
class User
{
use \Zerotoprod\DataModel\DataModel;
public string $name;
public int $age;
}
$user = User::from(['name' => 'Jane', 'age' => 30]);
#[\Zerotoprod\DataModel\Describe([
'from' => 'key', // Remap: read this context key instead of property name. Callable OK
'pre' => [self::class, 'hook'], // Pre-hook: void callable, runs before cast
'cast' => [self::class, 'method'], // Cast: callable, returns resolved value
'post' => [self::class, 'hook'], // Post-hook: void callable, runs after cast
'default' => 'value', // Default: used when context key absent. Callable OK
'assign' => 'value', // Assign: always set; context ignored. Callable OK
'
class Address
{
use \Zerotoprod\DataModel\DataModel;
public string $street;
public string $city;
}
class User
{
use \Zerotoprod\DataModel\DataModel;
public string $username;
public Address $address;
}
$User = User::from([
'username' => 'John Doe',
'address' => [
'street' => '123 Main St',
'city' => 'Hometown',
],
]);
echo $User->address->city; // 'Hometown'
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
#[Describe(['cast' => [self::class, 'firstName'], 'function' => 'strtoupper'])]
// Or with first-class callable (PHP 8.5+):
// #[Describe(['cast' => self::firstName(...), 'function' => 'strtoupper'])]
public string $first_name;
#[Describe(['cast' => 'uppercase'])]
public string $last_name;
#[Describe(['cast' => [self::class, 'fullName']])]
// Or: #[Describe(['cast' => self::fullName(...)])]
public string $full_name;
private static function firstName(mixed $value, array $context, ?\ReflectionAttribute $ReflectionAttribute, \ReflectionProperty $ReflectionProperty): string
{
return $ReflectionAttribute->getArguments()[0]['function']($value);
}
public static function fullName(mixed $value, array $context, ?\ReflectionAttribute $Attribute, \ReflectionProperty $Property): string
{
return "{$context['first_name']} {$context['last_name']}";
}
}
function uppercase(mixed $value, array $context){
return strtoupper($value);
}
$User = User::from([
'first_name' => 'Jane',
'last_name' => 'Doe',
]);
$User->first_name; // 'JANE'
$User->last_name; // 'DOE'
$User->full_name; // 'Jane Doe'
#[Describe(['cast' => static function ($value): string {
return strtoupper($value);
}])]
public string $last_name;
use Zerotoprod\DataModel\Describe;
class BaseClass
{
use \Zerotoprod\DataModel\DataModel;
#[Describe(['pre' => [self::class, 'pre'], 'message' => 'Value too large.'])]
public int $int;
public static function pre(mixed $value, array $context, ?\ReflectionAttribute $Attribute, \ReflectionProperty $Property): void
{
if ($value > 10) {
throw new \RuntimeException($Attribute->getArguments()[0]['message']);
}
}
}
#[Describe(['pre' => static function (mixed $value): void {
if ($value > 10) {
throw new \RuntimeException('Value too large.');
}
}])]
public int $int;
use Zerotoprod\DataModel\Describe;
class BaseClass
{
use \Zerotoprod\DataModel\DataModel;
public const int = 'int';
#[Describe(['post' => [self::class, 'post'], 'message' => 'Value too large.'])]
public int $int;
public static function post(mixed $value, array $context, ?\ReflectionAttribute $Attribute, \ReflectionProperty $Property): void
{
if ($value > 10) {
throw new \RuntimeException($value.$Attribute->getArguments()[0]['message']);
}
}
}
#[Describe(['post' => static function (mixed $value): void {
if ($value > 10) {
throw new \RuntimeException($value.' Value too large.');
}
}])]
public int $int;
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
public string $first_name;
public string $last_name;
public string $fullName;
#[Describe('last_name')]
public function lastName(mixed $value, array $context, ?\ReflectionAttribute $Attribute, \ReflectionProperty $Property): string
{
return strtoupper($value);
}
#[Describe('fullName')]
public function fullName(mixed $value, array $context, ?\ReflectionAttribute $Attribute, \ReflectionProperty $Property): string
{
return "{$context['first_name']} {$context['last_name']}";
}
}
$User = User::from([
'first_name' => 'Jane',
'last_name' => 'Doe',
]);
$User->first_name; // 'Jane'
$User->last_name; // 'DOE'
$User->fullName; // 'Jane Doe'
use Zerotoprod\DataModel\Describe;
function uppercase(mixed $value, array $context){
return strtoupper($value);
}
#[Describe([
'cast' => [
'string' => 'uppercase',
\DateTimeImmutable::class => [self::class, 'toDateTimeImmutable'],
]
])]
class User
{
use \Zerotoprod\DataModel\DataModel;
public string $first_name;
public DateTimeImmutable $registered;
public static function toDateTimeImmutable(mixed $value, array $context): DateTimeImmutable
{
return new DateTimeImmutable($value);
}
}
$User = User::from([
'first_name' => 'Jane',
'registered' => '2015-10-04 17:24:43.000000',
]);
$User->first_name; // 'JANE'
$User->registered->format('l'); // 'Sunday'
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
#[Describe(['Throws PropertyRequiredException: Property `$username` is
#[Describe(['rue;
}])]
public string $username;
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
#[Describe(['default' => 'N/A'])]
public string $username;
#[Describe(['default' => [self::class, 'newCollection']])]
public Collection $username;
public static function newCollection(): Collection
{
return new Collection();
}
}
$User = User::from();
echo $User->username // 'N/A'
#[Describe(['default' => static function (): array {
return myFunction();
}])]
public array $property;
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
#[Describe(['assign' => ['role' => 'admin']])]
public array $config;
}
$User = User::from();
// $User->config === ['role' => 'admin']
$User = User::from(['config' => ['role' => 'guest']]);
// $User->config === ['role' => 'admin'] (context value ignored)
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
#[Describe(['assign' => [self::class, 'account']])]
public string $account;
public static function account($value, array $context): string
{
return 'service-account';
}
}
$User = User::from(['account' => 'other']);
// $User->account === 'service-account' (context value ignored)
#[Describe(['assign' => static function (): string {
return 'service-account';
}])]
public string $account;
use Zerotoprod\DataModel\Describe;
#[Describe(['nullable' => true])]
class User
{
use \Zerotoprod\DataModel\DataModel;
public ?string $name;
#[Describe(['nullable' => true])]
public ?int $age;
}
$User = User::from();
echo $User->name; // null
echo $User->age; // null
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
#[Describe(['from' => 'firstName'])]
public string $first_name;
}
$User = User::from([
'firstName' => 'John',
]);
echo $User->first_name; // 'John'
#[Describe(['from' => static function (string $propertyName, array $context): string {
return isset($context['firstName']) ? 'firstName' : 'legacyFirstName';
}])]
public string $first_name;
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
public string $name;
#[Describe(['ignore'])]
public int $age;
}
$User = User::from([
'name' => 'John Doe',
'age' => '30',
]);
isset($User->age); // false
#[Describe(['ignore' => static function (): bool {
return true;
}])]
public int $age;
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
#[Describe(['cast' => [self::class, 'firstName'], 'function' => 'strtoupper'])]
public string $first_name;
private static function firstName(
mixed $value,
array $context,
?\ReflectionAttribute $Attribute,
\ReflectionProperty $Property
): string
{
// Access via reflection (still works)
$fn = $Attribute->getArguments()[0]['function'];
// Or access via extra (no reflection needed)
$Describe = $Attribute->newInstance();
$fn = $Describe->extra['function'];
return $fn($value);
}
}
class User
{
use \Zerotoprod\DataModel\DataModel;
public string $name;
public function __construct(array $data = [])
{
self::from($data, $this);
}
}
$User = new User([
'name' => 'Jane Doe',
]);
echo $User->name; // 'Jane Doe';
use Zerotoprod\DataModel\Describe;
class BaseClass
{
use DataModel;
#[Describe(['via' => 'via'])]
public ChildClass $ChildClass;
#[Describe(['via' => [ChildClass::class, 'via']])]
public ChildClass $ChildClass2;
}
class ChildClass
{
public function __construct(public int $int)
{
}
public static function via(array $context): self
{
return new self($context[self::int]);
}
}
$BaseClass = BaseClass::from([
'ChildClass' => ['int' => 1],
'ChildClass2' => ['int' => 1],
]);
$BaseClass->ChildClass->int; // 1
$BaseClass->ChildClass2->int; // 1
namespace App\DataModels;
trait DataModel
{
use \Zerotoprod\DataModel\DataModel;
public function toArray(): array
{
return collect($this)->toArray();
}
}
use Attribute;
use Zerotoprod\DataModel\Describe;
#[Attribute]
class MyDescribe extends Describe {}
readonly class Config
{
use \Zerotoprod\DataModel\DataModel;
#[MyDescribe(['default' => 'fallback'])]
public string $name;
#[MyDescribe(['nullable' => true])]
public ?string $label;
}
$Config = Config::from();
echo $Config->name; // 'fallback'
echo $Config->label; // null
class User
{
use \Zerotoprod\DataModel\DataModel;
#[Describe(['default' => 'guest'])]
public string $role;
#[Describe(['nullable' => true])]
public ?string $name;
}
$User = User::from('any_string');
echo $User->role; // 'guest'
echo $User->name; // null
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
use \Zerotoprod\DataModelHelper\DataModelHelper;
/** @var Alias[] $Aliases */
#[Describe([
'cast' => [self::class, 'mapOf'], // Use the mapOf helper method
// 'cast' => self::mapOf(...), // Or use first-class callable (PHP 8.5+)
'type' => Alias::class, // Target type for each item
])]
public array $Aliases;
}
class Alias
{
use \Zerotoprod\DataModel\DataModel;
public string $name;
}
$User = User::from([
'Aliases' => [
['name' => 'John Doe'],
['name' => 'John Smith'],
]
]);
echo $User->Aliases[0]->name; // 'John Doe'
echo $User->Aliases[1]->name; // 'John Smith'
use Zerotoprod\DataModel\Describe;
class User
{
use \Zerotoprod\DataModel\DataModel;
use \Zerotoprod\DataModelHelper\DataModelHelper;
/** @var Collection<int, Alias> $Aliases */
#[Describe([
'cast' => [self::class, 'mapOf'], // Or: self::mapOf(...) on PHP 8.5+
'type' => Alias::class,
])]
public \Illuminate\Support\Collection $Aliases;
}
class Alias
{
use \Zerotoprod\DataModel\DataModel;
public string $name;
}
$User = User::from([
'Aliases' => [
['name' => 'John Doe'],
['name' => 'John Smith'],
]
]);
echo $User->Aliases->first()->name; // 'John Doe'
use Illuminate\Support\Facades\Validator;
use Zerotoprod\DataModel\Describe;
readonly class FullName
{
use \Zerotoprod\DataModel\DataModel;
#[Describe([
'pre' => [self::class, 'validate'],
'rule' => 'min:2'
])]
public string $first_name;
public static function validate(mixed $value, array $context, ?\ReflectionAttribute $Attribute): void
{
$validator = Validator::make(['value' => $value], ['value' => $Attribute?->getArguments()[0]['rule']]);
if ($validator->fails()) {
throw new \RuntimeException($validator->errors()->toJson());
}
}
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.