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

Schema Generator Laravel Package

apie/schema-generator

Generates JSON Schema components from PHP objects with type hints, tailored for Apie entities, value objects, DTOs, enums, lists, and hashmaps. Produces cebe/php-openapi schema objects, focusing on schema sections (not full OpenAPI documents).

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require apie/schema-generator
    

    Ensure cebe/php-openapi is also installed (dependency for schema generation):

    composer require cebe/php-openapi
    
  2. First Use Case Generate a schema for a simple DTO or Value Object:

    use Apie\SchemaGenerator\ComponentsBuilderFactory;
    
    $factory = ComponentsBuilderFactory::createComponentsBuilderFactory();
    $schema = $factory->addCreationSchemaFor(\App\Dto\YourDto::class);
    $components = $factory->getComponents()->schemas;
    
  3. Where to Look First

    • ComponentsBuilderFactory: Entry point for schema generation.
    • addCreationSchemaFor(): Core method to generate schemas for classes.
    • getComponents(): Retrieve all generated schemas (useful for OpenAPI components section).
    • Documentation: Focus on the README and OpenAPI spec for reference patterns.

Implementation Patterns

1. DTO Schema Generation

Leverage DTOs to define API request/response structures with minimal boilerplate:

use Apie\Core\Attributes\Optional;
use Apie\Core\Dto\DtoInterface;

class UserDto implements DtoInterface {
    public string $name;
    public int $age = 30; // Default value → optional in schema
    #[Optional]
    public ?string $bio = null;
}

Schema Output:

UserDto-post:
  required: ['name']
  properties:
    name: { type: string }
    age: { type: integer }
    bio: { type: string, nullable: true }

2. Entity Schema Generation

For Eloquent models or domain entities, use constructor args and set*/with* methods:

class User {
    public function __construct(
        public string $name,
        public ?int $age = null
    ) {}

    public function setEmail(string $email): self {
        $this->email = $email;
        return $this;
    }
}

Schema Output:

User-post:
  required: ['name']
  properties:
    name: { type: string }
    age: { type: integer, nullable: true }
    email: { type: string }

3. Value Objects

Handle complex types (e.g., Email, Money) with traits/interfaces:

use Apie\Core\ValueObjects\Interfaces\StringValueObjectInterface;
use Apie\Core\ValueObjects\IsStringValueObject;

class Email implements StringValueObjectInterface {
    use IsStringValueObject;
}

Schema Output:

Email-post:
  type: string
  format: Email

4. Enum Support

Automatically map enums to enum schemas:

enum Status {
    case ACTIVE;
    case INACTIVE;
}

Schema Output:

Status-post:
  type: string
  enum: ['ACTIVE', 'INACTIVE']

5. Custom Schema Overrides

Use #[SchemaMethod] for full control:

#[SchemaMethod('getCustomSchema')]
class Password {
    public static function getCustomSchema(): array {
        return [
            'type' => 'string',
            'format' => 'password',
            'minLength' => 8,
        ];
    }
}

6. Integration with OpenAPI

Combine with cebe/php-openapi for full API docs:

use OpenApi\Generator;

$generator = new Generator();
$generator->addSchema($factory->getComponents()->schemas);
$openapi = $generator->generate();

7. Batch Processing

Generate schemas for multiple classes at once:

$factory = ComponentsBuilderFactory::createComponentsBuilderFactory();
$factory->addCreationSchemaFor(UserDto::class);
$factory->addCreationSchemaFor(OrderDto::class);
$components = $factory->getComponents()->schemas;

Gotchas and Tips

Pitfalls

  1. Circular References

    • If two entities reference each other (e.g., User has Address, Address has User), the generator may fail or produce incomplete schemas.
    • Fix: Use $ref sparingly or restructure your models to avoid cycles.
  2. Unsupported Types

    • Custom types without proper type hints (e.g., array without generics) may not generate valid schemas.
    • Fix: Use #[SchemaMethod] or ensure types are explicitly hinted (e.g., array<string>).
  3. Backed Enums

    • Backed enums use their values, not names, in the schema. This can be unintuitive if values differ from names.
    • Example:
      enum Priority {
          case HIGH = 'high_priority';
          case LOW = 'low_priority';
      }
      
      Schema Output:
      Priority-post:
        type: string
        enum: ['high_priority', 'low_priority']
      
  4. Default Values in DTOs

    • Default values (e.g., int $age = 30) make fields optional in the schema, even if they’re required logically.
    • Fix: Use #[Optional] explicitly if you want to enforce this behavior.
  5. Composite Value Objects

    • The CompositeValueObject trait maps to objects, but nested properties may not resolve correctly if they’re not properly typed.
    • Fix: Ensure all nested properties have explicit type hints.

Debugging Tips

  1. Inspect Generated Schemas Use dd($factory->getComponents()->schemas) to debug intermediate outputs.

  2. Validate with OpenAPI Tools Use tools like Swagger Editor to validate generated schemas.

  3. Check for Missing References If a schema references a non-existent component (e.g., $ref: '#/components/schemas/NonExistent'), verify all classes are processed in the same ComponentsBuilderFactory instance.

Extension Points

  1. Custom Schema Methods Override schema generation for specific classes using #[SchemaMethod].

  2. Post-Processing Modify schemas after generation using cebe/php-openapi's Schema class:

    $schema = $factory->addCreationSchemaFor(UserDto::class);
    $schema->addEnum(['active', 'inactive']); // Extend dynamically
    
  3. Integration with Laravel

    • Service Provider: Register the factory as a singleton:
      $this->app->singleton(ComponentsBuilderFactory::class, fn() => ComponentsBuilderFactory::createComponentsBuilderFactory());
      
    • Facades: Create a facade for cleaner usage:
      Schema::generate(UserDto::class);
      
  4. Performance

    • Reuse the ComponentsBuilderFactory instance for multiple schema generations to avoid reprocessing.
    • Cache generated schemas if your API is static (e.g., using Laravel’s cache).
  5. Testing Test schema generation with PHPUnit:

    public function testSchemaGeneration() {
        $factory = ComponentsBuilderFactory::createComponentsBuilderFactory();
        $schema = $factory->addCreationSchemaFor(UserDto::class);
        $this->assertArrayHasKey('required', $schema);
        $this->assertContains('name', $schema['required']);
    }
    
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.
craftcms/url-validator
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony