1. Go to this page and download the library: Download diego-ninja/granite 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/ */
diego-ninja / granite example snippets
use Ninja\Granite\GraniteVO;
use Ninja\Granite\Validation\Attributes\Required;
use Ninja\Granite\Validation\Attributes\Email;
use Ninja\Granite\Validation\Attributes\Min;
use Ninja\Granite\Serialization\Attributes\SerializedName;
use Ninja\Granite\Serialization\Attributes\Hidden;
// Create a Value Object with validation
final readonly class User extends GraniteVO
{
public function __construct(
public ?int $id,
#[Required]
#[Min(2)]
public string $name,
#[Required]
#[Email]
public string $email,
#[Hidden] // Won't appear in JSON
public ?string $password = null,
#[SerializedName('created_at')]
public DateTime $createdAt = new DateTime()
) {}
}
// Create and validate
$user = User::from([
'name' => 'John Doe',
'email' => '[email protected]',
'password' => 'secret123'
]);
// Immutable updates
$updatedUser = $user->with(['name' => 'Jane Doe']);
// Serialization
$json = $user->json();
// {"id":null,"name":"John Doe","email":"[email protected]","created_at":"2024-01-15T10:30:00+00:00"}
$array = $user->array();
// password is hidden, created_at uses custom name
// Request validation
final readonly class CreateUserRequest extends GraniteVO
{
public function __construct(
#[Required]
#[StringType]
#[Min(2)]
public string $name,
#[Required]
#[Email]
public string $email,
#[Required]
#[Min(8)]
#[Regex('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/', 'Password must contain uppercase, lowercase, and number')]
public string $password
) {}
}
// API Response
final readonly class UserResponse extends GraniteDTO
{
public function __construct(
public int $id,
public string $name,
public string $email,
#[SerializedName('member_since')]
public DateTime $createdAt
) {}
public static function fromEntity(User $user): self
{
return new self(
id: $user->id,
name: $user->name,
email: $user->email,
createdAt: $user->createdAt
);
}
}
// Value Objects
final readonly class Money extends GraniteVO
{
public function __construct(
#[Required]
#[NumberType]
#[Min(0)]
public float $amount,
#[Required]
#[StringType]
#[Min(3)]
#[Max(3)]
public string $currency
) {}
public function add(Money $other): Money
{
if ($this->currency !== $other->currency) {
throw new InvalidArgumentException('Cannot add different currencies');
}
return new Money($this->amount + $other->amount, $this->currency);
}
}
// Aggregates
final readonly class Order extends GraniteVO
{
public function __construct(
public ?int $id,
#[Required]
public int $customerId,
#[Required]
#[ArrayType]
#[Each(new Rules\Callback(fn($item) => OrderItem::from($item)))]
public array $items,
#[Required]
public OrderStatus $status = OrderStatus::PENDING
) {}
public function getTotal(): Money
{
$total = new Money(0.0, 'USD');
foreach ($this->items as $item) {
$total = $total->add($item->getTotal());
}
return $total;
}
}
use Ninja\Granite\Mapping\ObjectMapper;
use Ninja\Granite\Mapping\ObjectMapperConfig;
use Ninja\Granite\Mapping\Attributes\MapFrom;
// Source entity
final readonly class UserEntity extends GraniteDTO
{
public function __construct(
public int $userId,
public string $fullName,
public string $emailAddress,
public DateTime $createdAt
) {}
}
// Destination DTO with mapping attributes
final readonly class UserSummary extends GraniteDTO
{
public function __construct(
#[MapFrom('userId')]
public int $id,
#[MapFrom('fullName')]
public string $name,
#[MapFrom('emailAddress')]
public string $email
) {}
}
// Create ObjectMapper with clean configuration
$mapper = new ObjectMapper(
ObjectMapperConfig::forProduction()
->withConventions(true, 0.8)
->withSharedCache()
);
// Automatic mapping
$summary = $mapper->map($userEntity, UserSummary::class);
// Automatically maps between different naming conventions
class SourceClass {
public string $firstName; // camelCase
public string $email_address; // snake_case
public string $UserID; // PascalCase
}
class DestinationClass {
public string $first_name; // snake_case
public string $emailAddress; // camelCase
public string $user_id; // snake_case
}
$mapper = new ObjectMapper(
ObjectMapperConfig::create()
->withConventions(true, 0.8)
);
$result = $mapper->map($source, DestinationClass::class);
// Properties automatically mapped based on naming conventions!
use Ninja\Granite\Mapping\ObjectMapperConfig;
use Ninja\Granite\Mapping\MappingProfile;
// Fluent configuration with builder pattern
$mapper = new ObjectMapper(
ObjectMapperConfig::forProduction()
->withSharedCache()
->withConventions(true, 0.8)
->withProfile(new UserMappingProfile())
->withProfile(new ProductMappingProfile())
->withWarmup()
);
// Predefined configurations
$devMapper = new ObjectMapper(ObjectMapperConfig::forDevelopment());
$prodMapper = new ObjectMapper(ObjectMapperConfig::forProduction());
$testMapper = new ObjectMapper(ObjectMapperConfig::forTesting());
final readonly class CreditCard extends GraniteVO
{
public function __construct(
#[Required]
#[Regex('/^\d{4}\s?\d{4}\s?\d{4}\s?\d{4}$/', 'Invalid card number format')]
public string $number,
#[Required]
#[Regex('/^(0[1-9]|1[0-2])\/([0-9]{2})$/', 'Invalid expiry format (MM/YY)')]
public string $expiry,
#[Required]
#[Regex('/^\d{3,4}$/', 'Invalid CVV')]
public string $cvv,
#[When(
condition: fn($value, $data) => $data['type'] === 'business',
rule: new Required()
)]
public ?string $companyName = null
) {}
protected static function rules(): array
{
return [
'number' => [
new Callback(function($number) {
// Luhn algorithm validation
return $this->isValidLuhn(str_replace(' ', '', $number));
}, 'Invalid credit card number')
]
];
}
}
// Configure once at application startup
ObjectMapper::configure(function(ObjectMapperConfig $config) {
$config->withSharedCache()
->withConventions(true, 0.8)
->withProfiles([
new UserMappingProfile(),
new ProductMappingProfile(),
new OrderMappingProfile()
])
->withWarmup();
});
// Use anywhere in your application
$mapper = ObjectMapper::getInstance();
$userDto = $mapper->map($userEntity, UserDto::class);
// Use shared cache for web applications
$mapper = new ObjectMapper(
ObjectMapperConfig::forProduction()
->withSharedCache()
->withWarmup() // Preload configurations
);
// Preload mappings for better performance
use Ninja\Granite\Mapping\MappingPreloader;
MappingPreloader::preload($mapper, [
[UserEntity::class, UserResponse::class],
[ProductEntity::class, ProductResponse::class]
]);
class UserTest extends PHPUnit\Framework\TestCase
{
public function testUserCreation(): void
{
$user = User::from([
'name' => 'John Doe',
'email' => '[email protected]'
]);
$this->assertEquals('John Doe', $user->name);
$this->assertEquals('[email protected]', $user->email);
}
public function testObjectMapping(): void
{
$mapper = new ObjectMapper(ObjectMapperConfig::forTesting());
$entity = new UserEntity(1, 'John Doe', '[email protected]', new DateTime());
$dto = $mapper->map($entity, UserDto::class);
$this->assertInstanceOf(UserDto::class, $dto);
$this->assertEquals(1, $dto->id);
}
public function testImmutability(): void
{
$user = User::from(['name' => 'John', 'email' => '[email protected]']);
$updated = $user->with(['name' => 'Jane']);
// Original unchanged
$this->assertEquals('John', $user->name);
// New instance created
$this->assertEquals('Jane', $updated->name);
}
}
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.