1. Go to this page and download the library: Download andydefer/domain-structures 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/ */
andydefer / domain-structures example snippets
use AndyDefer\DomainStructures\Abstracts\AbstractValueObject;
final class EmailAddress extends AbstractValueObject
{
public function __construct(
private readonly string $value
) {
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException("Invalid email address");
}
}
public function getValue(): string
{
return $this->value;
}
public function getDomain(): string
{
return substr(strrchr($this->value, "@"), 1);
}
public function isGmail(): bool
{
return $this->getDomain() === 'gmail.com';
}
}
// Utilisation
$email = new EmailAddress('[email protected]');
echo $email->getDomain(); // 'example.com'
use AndyDefer\DomainStructures\Abstracts\AbstractRecord;
final class UserRecord extends AbstractRecord
{
public function __construct(
public readonly ?int $id,
public readonly string $name,
public readonly EmailAddress $email,
public readonly UserRole $role,
public readonly Iso8601DateTime $createdAt,
) {}
}
use AndyDefer\DomainStructures\Abstracts\AbstractData;
final class UserData extends AbstractData
{
public function __construct(
public readonly UserId $id,
public readonly PersonName $name,
public readonly EmailAddress $email,
public readonly Iso8601DateTime $createdAt,
public readonly UserRole $role,
) {}
}
use AndyDefer\DomainStructures\Collections\Utility\StringTypedCollection;
// Création et ajout
$strings = new StringTypedCollection();
$strings->add('hello', 'world', 'foo');
// Accès
foreach ($strings as $string) {
echo $string;
}
// Création de collection spécialisée
final class UserRecordCollection extends TypedCollection
{
public function __construct()
{
parent::__construct(UserRecord::class);
}
public function getAdmins(): self
{
return $this->filter(fn(UserRecord $user) => $user->role === UserRole::ADMIN);
}
}
use AndyDefer\DomainStructures\Services\HydrationService;
use AndyDefer\DomainStructures\Normalizers\NormalizerChain;
use AndyDefer\DomainStructures\Utils\DataObject;
// 1. Définir les Value Objects
final class EmailAddress extends AbstractValueObject
{
public function __construct(private readonly string $value)
{
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException("Invalid email");
}
}
public function getValue(): string { return $this->value; }
}
final class Iso8601DateTime extends AbstractValueObject
{
public function __construct(private readonly string $value)
{
if (!strtotime($value)) {
throw new \InvalidArgumentException("Invalid date");
}
}
public function getValue(): string { return $this->value; }
}
// 2. Définir l'Enum
enum UserRole: string
{
case ADMIN = 'admin';
case USER = 'user';
}
// 3. Définir le Record
final class UserRecord extends AbstractRecord
{
public function __construct(
public readonly ?int $id,
public readonly string $name,
public readonly EmailAddress $email,
public readonly UserRole $role,
public readonly Iso8601DateTime $createdAt,
) {}
}
// 4. Définir la collection spécialisée
final class UserRecordCollection extends TypedCollection
{
public function __construct()
{
parent::__construct(UserRecord::class);
}
public function getAdmins(): self
{
return $this->filter(fn(UserRecord $user) => $user->role === UserRole::ADMIN);
}
}
// 5. Définir le Data DTO pour l'API
final class UserData extends AbstractData
{
public function __construct(
public readonly int $id,
public readonly string $name,
public readonly string $email,
public readonly string $role,
public readonly string $createdAt,
) {}
}
// 6. Utilisation dans un Repository
class UserRepository
{
private HydrationService $hydration;
public function __construct(HydrationService $hydration)
{
$this->hydration = $hydration;
}
public function find(int $id): ?UserRecord
{
$row = $this->db->fetchAssoc('SELECT * FROM users WHERE id = ?', [$id]);
if (!$row) return null;
return $this->hydration->hydrate(UserRecord::class, $row);
}
public function findAll(): UserRecordCollection
{
$rows = $this->db->fetchAllAssoc('SELECT * FROM users');
return $this->hydration->collect($rows, UserRecordCollection::class);
}
}
// 7. Utilisation dans un Controller
class UserController
{
public function show(int $id): JsonResponse
{
$user = $this->userRepository->find($id);
// Convertir Record en Data DTO pour l'API
$userData = new UserData(
id: $user->id,
name: $user->name,
email: $user->email->getValue(),
role: $user->role->value,
createdAt: $user->createdAt->getValue()
);
// Normalisation automatique (camelCase pour le client)
return response()->json(NormalizerChain::get()->normalize($userData));
}
}
// 8. Utilisation de DataObject pour les sources externes
$apiResponse = new DataObject([
'user_id' => 123,
'first_name' => 'John',
'last_name' => 'Doe'
]);
echo $apiResponse->user_id; // 123
echo $apiResponse->firstName; // 'John'
echo $apiResponse->last_name; // 'Doe'
// ✅ BON - Validation centralisée dans le constructeur
final class EmailAddress extends AbstractValueObject
{
public function __construct(private readonly string $value)
{
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new \InvalidArgumentException("Invalid email");
}
}
}
// ❌ MAUVAIS - Validation dispersée
$email = $_POST['email'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { /* ... */ }
// ✅ BON - Uniquement pour la communication interne
public function find(int $id): UserRecord
// ❌ MAUVAIS - Dans une réponse API (utilisez Data DTO)
return response()->json($userRecord);
// ✅ BON - Pour les réponses API
return response()->json($userData);
// ❌ MAUVAIS - Avec des types primitifs
public readonly int $id; // Interdit ! Utilisez UserId $id
// ✅ BON - Collection spécialisée avec comportement métier
final class ProductRecordCollection extends TypedCollection
{
public function getActive(): self { /* ... */ }
}
// ❌ MAUVAIS - TypedCollection générique sans comportement
public readonly TypedCollection $products;
// ✅ BON - Utilisation du service d'hydratation
$hydration = new HydrationService();
$user = $hydration->hydrate(UserRecord::class, $data);
// ❌ MAUVAIS - Hydratation manuelle
$user = new UserRecord(
id: $data['id'],
name: $data['name'],
// ... des dizaines de champs à mapper manuellement
);
// ✅ BON - Utilisation du constructeur
$data = new DataObject($source);
// ❌ MAUVAIS - Utilisation de ::from() (déprécié)
$data = DataObject::from($source);
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.