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

Rapid Form Bundle Laravel Package

ansien/rapid-form-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require ansien/rapid-form-bundle
    

    Ensure your config/bundles.php includes the bundle (auto-registered in Symfony 5.1+).

  2. First Form Class: Create a DTO class with #[Form] attribute and annotate properties with #[FormField]:

    use Ansien\RapidFormBundle\Attribute\Form;
    use Ansien\RapidFormBundle\Attribute\FormField;
    use Symfony\Component\Form\Extension\Core\Type\TextType;
    
    #[Form]
    class UserForm {
        #[FormField(TextType::class)]
        public ?string $username = null;
    }
    
  3. Controller Integration: Inject RapidFormBuilderInterface and create the form:

    use Ansien\RapidFormBundle\Form\RapidFormBuilderInterface;
    
    class UserController {
        public function __construct(private RapidFormBuilderInterface $formBuilder) {}
    
        public function create(Request $request): Response {
            $form = $this->formBuilder->create(new UserForm())->handleRequest($request);
            // ...
        }
    }
    
  4. Twig Rendering: Pass the form view to your template:

    {{ form_start(form) }}
        {{ form_row(form.username) }}
        <button type="submit">Submit</button>
    {{ form_end(form) }}
    

First Use Case

Quick CRUD Form: For a User entity, create a UserForm DTO with #[FormField] for each field (e.g., TextType, EmailType). The bundle auto-generates the form type, eliminating the need for a separate UserType class.


Implementation Patterns

Core Workflow

  1. DTO-First Design: Define forms as DTOs with #[Form] and #[FormField] attributes. Example:

    #[Form]
    class LoginForm {
        #[FormField(TextType::class, ['label' => 'Email'])]
        #[Assert\Email]
        public ?string $email = null;
    
        #[FormField(RepeatedType::class, [
            'type' => PasswordType::class,
            'first_options' => ['label' => 'Password'],
            'second_options' => ['label' => 'Repeat Password'],
        ])]
        public ?string $password = null;
    }
    
  2. Nested Forms: Use #[FormField] with EmbeddedType for nested DTOs:

    #[Form]
    class ProfileForm {
        #[FormField(EmbeddedType::class, ['class' => AddressForm::class])]
        public ?AddressForm $address = null;
    }
    
  3. Dynamic Options: Pass closures for dynamic options (e.g., query-based choices):

    #[FormField(ChoiceType::class, [
        'choices' => fn(EntityManagerInterface $em) => $em->getRepository(User::class)->findAll(),
        'choice_label' => 'username',
    ])]
    public ?User $owner = null;
    
  4. Validation Integration: Combine Symfony’s #[Assert\*] constraints with form fields:

    #[FormField(TextType::class)]
    #[Assert\Length(min: 3, max: 20)]
    public ?string $nickname = null;
    

Integration Tips

  • Event Listeners: Attach form events (e.g., PRE_SET_DATA) via Symfony’s event dispatcher:

    $form = $this->formBuilder->create($data)
        ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
            $event->getData()->setDefaultValue('default');
        });
    
  • Custom Form Types: Extend AbstractType and register it as a service. Reference it in #[FormField]:

    #[FormField(MyCustomType::class)]
    public ?string $customField = null;
    
  • Collection Handling: Use CollectionType for arrays of DTOs:

    #[Form]
    class OrderForm {
        #[FormField(CollectionType::class, [
            'entry_type' => ProductForm::class,
            'allow_add' => true,
            'allow_delete' => true,
        ])]
        public array $products = [];
    }
    
  • Form Theming: Override Twig templates in templates/AnsienRapidFormBundle/ to customize rendering.


Gotchas and Tips

Pitfalls

  1. Attribute Targets: Ensure #[FormField] is applied to properties, not methods. The bundle uses reflection to inspect properties only.

    // ❌ Won't work (method)
    #[FormField(TextType::class)]
    public function getName(): string { ... }
    
    // ✅ Works (property)
    #[FormField(TextType::class)]
    public ?string $name = null;
    
  2. Circular References: Avoid circular references in nested forms (e.g., UserForm containing ProfileForm which references UserForm). Use #[Assert\Valid] carefully.

  3. RepeatedType Quirks: For RepeatedType, ensure the same field name is used in the DTO (e.g., $password and $passwordConfirm). The bundle auto-maps the second field to {field}_confirm.

  4. Validation Order: Form validation runs after Symfony’s validator. Use #[Assert\Callback] for complex validation that depends on form state.

  5. Dynamic Options Dependencies: Closures in #[FormField] options (e.g., choices) must accept container services as arguments. Example:

    #[FormField(ChoiceType::class, [
        'choices' => fn(EntityManagerInterface $em) => $em->getRepository(...),
    ])]
    

Debugging

  • Form Dump: Use Symfony’s FormDebugBuilder to inspect the generated form structure:

    $form = $this->formBuilder->create($data);
    $debugBuilder = new FormDebugBuilder();
    $debugBuilder->buildForm($form);
    
  • Attribute Reflection: Verify attributes are parsed correctly:

    $reflection = new ReflectionClass(UserForm::class);
    $attributes = $reflection->getProperty('username')->getAttributes(FormField::class);
    
  • Event Debugging: Log form events to trace issues:

    $form->addEventListener(FormEvents::SUBMIT, function (FormEvent $event) {
        error_log('Form submitted: ' . print_r($event->getData(), true));
    });
    

Tips

  1. Reuse Form Logic: Create base DTOs with common fields (e.g., BaseForm) and extend them:

    #[Form]
    class BaseForm {
        #[FormField(TextType::class)]
        public ?string $createdAt = null;
    }
    
    #[Form]
    class UserForm extends BaseForm {
        #[FormField(TextType::class)]
        public ?string $username = null;
    }
    
  2. Partial Updates: Use data_class in #[Form] to map to an entity:

    #[Form(data_class: User::class)]
    class UserForm {
        #[FormField(TextType::class)]
        public ?string $email = null;
    }
    

    Then bind the form to an entity:

    $form = $this->formBuilder->create(new UserForm(), $userEntity);
    
  3. Performance: Cache form builders for complex forms:

    $form = $this->formBuilder->create($data, [
        'cache_key' => 'user_form_' . $user->getId(),
    ]);
    
  4. Testing: Mock RapidFormBuilderInterface in tests:

    $builder = $this->createMock(RapidFormBuilderInterface::class);
    $builder->method('create')->willReturn($form);
    $controller = new UserController($builder);
    
  5. Symfony 7+: Leverage Symfony’s new #[AsneakPreview] attributes for future-proofing:

    #[Form]
    #[AsneakPreview('form_builder_v2')]
    class UserForm { ... }
    
  6. Extension Points: Override the bundle’s compiler pass to customize form generation:

    # config/services.yaml
    Ansien\RapidFormBundle\Form\Compiler\FormCompilerPass:
        tags: [kernel.event_subscriber]
        arguments:
            $customOptions: ['your_value']
    
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.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle