Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Types Laravel Package

atournayre/types

Lightweight PHP library providing reusable types/value objects. Installable via Composer, intended to standardize and validate common domain data. Open-source on GitHub with issue tracker and MIT license.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require atournayre/types
    

    Add the service provider to config/app.php (if not auto-discovered):

    'providers' => [
        // ...
        ATournayre\Types\TypesServiceProvider::class,
    ],
    
  2. Basic Usage Define a custom type in a PHP class:

    use ATournayre\Types\Type;
    
    class UserId extends Type
    {
        public static function validate($value): bool
        {
            return is_string($value) && preg_match('/^[a-f0-9]{24}$/', $value);
        }
    }
    

    New in 0.9.0: Use the built-in EmailAddress type for email validation:

    use ATournayre\Types\EmailAddress;
    
    // No need to define your own email validation
    
  3. First Use Case Validate input in a Laravel request:

    use ATournayre\Types\Type;
    use ATournayre\Types\EmailAddress;
    
    public function store(Request $request)
    {
        $request->validate([
            'user_id' => ['required', function ($attribute, $value, $fail) {
                if (!UserId::validate($value)) {
                    $fail('The '.$attribute.' must be a valid UserId.');
                }
            }],
            'email' => ['required', EmailAddress::class], // Directly use EmailAddress
        ]);
    }
    

Implementation Patterns

Type Definition Patterns

  1. Basic Type

    class Age extends Type
    {
        public static function validate($value, $min = 18, $max = 120): bool
        {
            return is_int($value) && $value >= $min && $value <= $max;
        }
    }
    
  2. Predefined Types (New in 0.9.0) Use built-in types like EmailAddress instead of reinventing:

    use ATournayre\Types\EmailAddress;
    
    // No need to define your own email validation
    
  3. Type with Conversion

    class Json extends Type
    {
        public static function validate($value): bool
        {
            return is_string($value) && is_array(json_decode($value, true));
        }
    
        public static function convert($value)
        {
            return json_decode($value, true);
        }
    }
    

Integration with Laravel

  1. Form Request Validation

    use ATournayre\Types\EmailAddress;
    
    public function rules()
    {
        return [
            'email' => ['required', EmailAddress::class], // Directly use EmailAddress
            'user_id' => ['required', function ($attribute, $value, $fail) {
                if (!UserId::validate($value)) {
                    $fail('The '.$attribute.' must be a valid UserId.');
                }
            }]
        ];
    }
    
  2. Model Casting

    use ATournayre\Types\EmailAddress;
    
    protected $casts = [
        'email' => EmailAddress::class,
        'user_id' => UserId::class,
    ];
    
  3. API Resource Formatting

    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'email' => EmailAddress::convert($this->email),
            'user_id' => UserId::convert($this->user_id),
        ];
    }
    
  4. Middleware for Type Enforcement

    public function handle($request, Closure $next)
    {
        if (!$request->has('email') || !EmailAddress::validate($request->email)) {
            abort(400, 'Invalid EmailAddress');
        }
        return $next($request);
    }
    

Gotchas and Tips

Pitfalls

  1. Avoid Redundant Validation New in 0.9.0: Do not redefine EmailAddress validation. Use the built-in type instead:

    // ❌ Avoid this (redundant)
    class Email extends Type { ... }
    
    // ✅ Use this instead
    use ATournayre\Types\EmailAddress;
    
  2. Performance Overhead Custom types add minor overhead. Cache type definitions if used extensively in hot paths:

    class CachedType extends Type
    {
        protected static $cache = [];
    
        public static function validate($value)
        {
            $cacheKey = static::class . serialize($value);
            if (!isset(self::$cache[$cacheKey])) {
                self::$cache[$cacheKey] = parent::validate($value);
            }
            return self::$cache[$cacheKey];
        }
    }
    
  3. Type Conversion Pitfalls Ensure convert() methods handle edge cases (e.g., invalid input):

    public static function convert($value)
    {
        if (!self::validate($value)) {
            throw new \InvalidArgumentException('Invalid type value');
        }
        return json_decode($value, true);
    }
    

Debugging

  1. Validation Failures Log type validation failures for debugging:

    public static function validate($value): bool
    {
        $isValid = /* validation logic */;
        if (!$isValid) {
            \Log::debug('Type validation failed for ' . static::class, ['value' => $value]);
        }
        return $isValid;
    }
    
  2. Type Hierarchy Issues If extending types, ensure parent methods are called:

    class ExtendedEmail extends EmailAddress
    {
        public static function validate($value): bool
        {
            return parent::validate($value) && /* additional logic */;
        }
    }
    

Extension Points

  1. Custom Type Collections Group related types for easier management:

    class TypeCollection
    {
        public static function getTypes(): array
        {
            return [
                UserId::class,
                EmailAddress::class, // Include built-in types
                // ...
            ];
        }
    }
    
  2. Type Registry Register types globally for reuse:

    $types = app()->make('types');
    $types->register(UserId::class);
    $types->register(EmailAddress::class); // Register built-in types
    
  3. Dynamic Type Loading Load types dynamically from a config file:

    $types = config('types.custom');
    foreach ($types as $type) {
        $types->register($type);
    }
    

Configuration Quirks

  1. Service Provider Binding Ensure the service provider binds the Type class correctly. Override bindings if needed:

    $this->app->bind('types', function () {
        return new CustomTypeRegistry();
    });
    
  2. Autoloading If types are in a custom namespace, ensure composer.json autoloads them:

    {
        "autoload": {
            "psr-4": {
                "App\\Types\\": "app/Types/"
            }
        }
    }
    }
    
  3. Built-in Type Usage New in 0.9.0: The EmailAddress type is now available out-of-the-box. No additional setup is required.

    // Works directly in validation rules
    $request->validate(['email' => EmailAddress::class]);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky