@@ -447,6 +447,184 @@ The generated schema will include a `oneOf` section to reflect the union types:
447447> All supported types are automatically resolved from native PHP type declarations and reflected in the JSON Schema
448448> output using oneOf.
449449
450+ ## Constraint Attributes
451+
452+ Generator supports dedicated constraint attributes that provide a clean, modular approach to validation rules.
453+
454+ ### Available Constraint Attributes
455+
456+ #### String Constraints
457+
458+ - ` #[Pattern(regex)] ` - Regular expression pattern validation
459+ - ` #[Length(min, max)] ` - String length constraints
460+
461+ #### Numeric Constraints
462+
463+ - ` #[Range(min, max, exclusiveMin, exclusiveMax)] ` - Numeric range validation with optional exclusive bounds
464+ - ` #[MultipleOf(value)] ` - Multiple of validation for numbers
465+
466+ #### Array Constraints
467+
468+ - ` #[Items(min, max, unique)] ` - Array item constraints with optional uniqueness
469+ - ` #[Length(min, max)] ` - Array length constraints (same attribute as strings, auto-detects type)
470+
471+ #### General Constraints
472+
473+ - ` #[Enum(values)] ` - Enumeration validation with array of allowed values
474+
475+ ### Usage Examples
476+
477+ #### String Validation
478+
479+ ``` php
480+ namespace App\DTO;
481+
482+ use Spiral\JsonSchemaGenerator\Attribute\Field;
483+ use Spiral\JsonSchemaGenerator\Attribute\Constraint\Pattern;
484+ use Spiral\JsonSchemaGenerator\Attribute\Constraint\Length;
485+
486+ final readonly class User
487+ {
488+ public function __construct(
489+ #[Field(title: 'Full Name', description: 'User full name in Title Case')]
490+ #[Pattern('^[A-Z][a-z]+(?: [A-Z][a-z]+)*$')]
491+ #[Length(min: 2, max: 100)]
492+ public string $name,
493+
494+ #[Field(title: 'Username')]
495+ #[Pattern('^[a-zA-Z0-9_]{3,20}$')]
496+ #[Length(min: 3, max: 20)]
497+ public string $username,
498+
499+ #[Field(title: 'Email', format: Format::Email)]
500+ #[Pattern('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$')]
501+ public string $email,
502+ ) {}
503+ }
504+ ```
505+
506+ #### Numeric Validation
507+
508+ ``` php
509+ namespace App\DTO;
510+
511+ use Spiral\JsonSchemaGenerator\Attribute\Field;
512+ use Spiral\JsonSchemaGenerator\Attribute\Constraint\Range;
513+ use Spiral\JsonSchemaGenerator\Attribute\Constraint\MultipleOf;
514+
515+ final readonly class Product
516+ {
517+ public function __construct(
518+ #[Field(title: 'Price', description: 'Product price in USD')]
519+ #[Range(min: 0.01, max: 99999.99)]
520+ #[MultipleOf(0.01)]
521+ public float $price,
522+
523+ #[Field(title: 'Stock Quantity')]
524+ #[Range(min: 0, max: 10000)]
525+ public int $stock,
526+
527+ #[Field(title: 'Discount Percentage')]
528+ #[Range(min: 0, max: 100, exclusiveMax: true)]
529+ public float $discountPercent,
530+ ) {}
531+ }
532+ ```
533+
534+ #### Array and Enum Validation
535+
536+ ``` php
537+ namespace App\DTO;
538+
539+ use Spiral\JsonSchemaGenerator\Attribute\Field;
540+ use Spiral\JsonSchemaGenerator\Attribute\Constraint\Items;
541+ use Spiral\JsonSchemaGenerator\Attribute\Constraint\Length;
542+ use Spiral\JsonSchemaGenerator\Attribute\Constraint\Enum;
543+
544+ final readonly class BlogPost
545+ {
546+ public function __construct(
547+ #[Field(title: 'Tags', description: 'Post tags')]
548+ #[Items(min: 1, max: 10, unique: true)]
549+ public array $tags,
550+
551+ #[Field(title: 'Categories', description: 'Post categories')]
552+ #[Length(min: 1, max: 5)]
553+ public array $categories,
554+
555+ #[Field(title: 'Status')]
556+ #[Enum(['draft', 'published', 'archived', 'pending'])]
557+ public string $status,
558+
559+ #[Field(title: 'Priority')]
560+ #[Enum([1, 2, 3, 4, 5])]
561+ public int $priority,
562+ ) {}
563+ }
564+ ```
565+
566+ ### Generated Schema Output
567+
568+ The constraint attributes generate clean, standards-compliant JSON Schema validation rules:
569+
570+ ``` json
571+ {
572+ "type" : " object" ,
573+ "properties" : {
574+ "name" : {
575+ "title" : " Full Name" ,
576+ "description" : " User full name in Title Case" ,
577+ "type" : " string" ,
578+ "pattern" : " ^[A-Z][a-z]+(?: [A-Z][a-z]+)*$" ,
579+ "minLength" : 2 ,
580+ "maxLength" : 100
581+ },
582+ "price" : {
583+ "title" : " Price" ,
584+ "description" : " Product price in USD" ,
585+ "type" : " number" ,
586+ "minimum" : 0.01 ,
587+ "maximum" : 99999.99 ,
588+ "multipleOf" : 0.01
589+ },
590+ "tags" : {
591+ "title" : " Tags" ,
592+ "description" : " Post tags" ,
593+ "type" : " array" ,
594+ "minItems" : 1 ,
595+ "maxItems" : 10 ,
596+ "uniqueItems" : true
597+ },
598+ "status" : {
599+ "title" : " Status" ,
600+ "type" : " string" ,
601+ "enum" : [
602+ " draft" ,
603+ " published" ,
604+ " archived" ,
605+ " pending"
606+ ]
607+ }
608+ },
609+ "required" : [
610+ " name" ,
611+ " price" ,
612+ " tags" ,
613+ " status"
614+ ]
615+ }
616+ ```
617+
618+ ### Type Safety
619+
620+ Constraint attributes are automatically validated for type compatibility:
621+
622+ - ` Pattern ` only applies to string properties
623+ - ` Range ` and ` MultipleOf ` only apply to numeric properties (int, float)
624+ - ` Items ` constraints only apply to array properties
625+ - ` Length ` adapts behavior: ` minLength ` /` maxLength ` for strings, ` minItems ` /` maxItems ` for arrays
626+ - ` Enum ` works with any property type
627+
450628## PHPDoc Validation Constraints
451629
452630Generator supports extracting validation constraints from PHPDoc comments, providing rich validation
@@ -615,33 +793,89 @@ final class ContactInfo
615793
616794## Configuration Options
617795
618- You can configure the generator behavior using the ` GeneratorConfig ` class:
796+ You can configure the generator behavior using the ` GeneratorConfig ` class and custom property data extractors :
619797
620798``` php
621799use Spiral\JsonSchemaGenerator\Generator;
622800use Spiral\JsonSchemaGenerator\GeneratorConfig;
801+ use Spiral\JsonSchemaGenerator\Validation\AttributeConstraintExtractor;
802+ use Spiral\JsonSchemaGenerator\Validation\PhpDocValidationConstraintExtractor;
803+ use Spiral\JsonSchemaGenerator\Validation\CompositePropertyDataExtractor;
623804
624- // Enable validation constraints (default: true)
805+ // Basic configuration - enable/disable validation constraints
625806$config = new GeneratorConfig(enableValidationConstraints: true);
626807$generator = new Generator(config: $config);
627808
628- // Disable validation constraints for performance
629- $config = new GeneratorConfig(enableValidationConstraints: false);
630- $generator = new Generator(config: $config);
809+ // Advanced configuration - custom property data extractors
810+ $compositeExtractor = new CompositePropertyDataExtractor([
811+ new PhpDocValidationConstraintExtractor(),
812+ new AttributeConstraintExtractor(),
813+ ]);
814+
815+ $generator = new Generator(propertyDataExtractor: $compositeExtractor);
816+
817+ // Use default extractors (recommended for most cases)
818+ $generator = new Generator(propertyDataExtractor: CompositePropertyDataExtractor::createDefault());
819+ ```
820+
821+ #### Property Data Extractors
822+
823+ The generator uses a modular property data extractor system that allows you to customize how validation constraints are extracted from properties:
824+
825+ ** Available Extractors:**
826+
827+ - ` PhpDocValidationConstraintExtractor ` - Extracts constraints from PHPDoc comments
828+ - ` AttributeConstraintExtractor ` - Extracts constraints from PHP attributes
829+ - ` CompositePropertyDataExtractor ` - Combines multiple extractors
830+
831+ ** Usage Examples:**
832+
833+ ``` php
834+ // Use only PHPDoc constraints
835+ $generator = new Generator(propertyDataExtractor: new CompositePropertyDataExtractor([
836+ new PhpDocValidationConstraintExtractor(),
837+ ]));
838+
839+ // Use only attribute constraints
840+ $generator = new Generator(propertyDataExtractor: new CompositePropertyDataExtractor([
841+ new AttributeConstraintExtractor(),
842+ ]));
843+
844+ // Use both (default behavior)
845+ $generator = new Generator(propertyDataExtractor: CompositePropertyDataExtractor::createDefault());
846+
847+ // Disable all validation constraints for performance
848+ $generator = new Generator(propertyDataExtractor: new CompositePropertyDataExtractor([]));
631849```
632850
633- ### Configuration Options
851+ ### Custom Property Data Extractors
634852
635- - ` enableValidationConstraints ` (bool, default: true) - Enable/disable PHPDoc validation constraint extraction
853+ You can create custom property data extractors by implementing the ` PropertyDataExtractorInterface ` :
636854
637- When ` enableValidationConstraints ` is disabled, the generator will skip parsing PHPDoc comments for validation rules,
638- which can improve performance for large schemas where validation constraints are not needed.
855+ ``` php
856+ use Spiral\JsonSchemaGenerator\Validation\PropertyDataExtractorInterface;
857+ use Spiral\JsonSchemaGenerator\Parser\PropertyInterface;
858+ use Spiral\JsonSchemaGenerator\Schema\Type;
639859
640- ## Integration with Valinor
860+ class CustomConstraintExtractor implements PropertyDataExtractorInterface
861+ {
862+ public function extractValidationRules(PropertyInterface $property, Type $jsonSchemaType): array
863+ {
864+ $rules = [];
865+
866+ // Your custom constraint extraction logic here
867+ // For example, extract constraints from custom attributes or naming conventions
868+
869+ return $rules;
870+ }
871+ }
872+
873+ // Use your custom extractor
874+ $generator = new Generator(
875+ propertyDataExtractor: CompositePropertyDataExtractor::createDefault()
876+ ->withExtractor(new CustomConstraintExtractor())
877+ );
641878
642- The JSON Schema Generator works perfectly with the [ Valinor PHP package] ( https://github.com/CuyZ/Valinor ) for complete
643- data mapping and validation workflows. Valinor can validate incoming data based on the same PHPDoc constraints that the
644- generator uses to create JSON schemas.
645879
646880### Installation
647881
0 commit comments