@@ -447,6 +447,184 @@ The generated schema will include a `oneOf` section to reflect the union types:
447
447
> All supported types are automatically resolved from native PHP type declarations and reflected in the JSON Schema
448
448
> output using oneOf.
449
449
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
+
450
628
## PHPDoc Validation Constraints
451
629
452
630
Generator supports extracting validation constraints from PHPDoc comments, providing rich validation
@@ -615,33 +793,89 @@ final class ContactInfo
615
793
616
794
## Configuration Options
617
795
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 :
619
797
620
798
``` php
621
799
use Spiral\JsonSchemaGenerator\Generator;
622
800
use Spiral\JsonSchemaGenerator\GeneratorConfig;
801
+ use Spiral\JsonSchemaGenerator\Validation\AttributeConstraintExtractor;
802
+ use Spiral\JsonSchemaGenerator\Validation\PhpDocValidationConstraintExtractor;
803
+ use Spiral\JsonSchemaGenerator\Validation\CompositePropertyDataExtractor;
623
804
624
- // Enable validation constraints (default: true)
805
+ // Basic configuration - enable/disable validation constraints
625
806
$config = new GeneratorConfig(enableValidationConstraints: true);
626
807
$generator = new Generator(config: $config);
627
808
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([]));
631
849
```
632
850
633
- ### Configuration Options
851
+ ### Custom Property Data Extractors
634
852
635
- - ` enableValidationConstraints ` (bool, default: true) - Enable/disable PHPDoc validation constraint extraction
853
+ You can create custom property data extractors by implementing the ` PropertyDataExtractorInterface ` :
636
854
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;
639
859
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
+ );
641
878
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.
645
879
646
880
### Installation
647
881
0 commit comments