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

Api First Bundle Laravel Package

bentools/api-first-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require bpolaszek/apifirst-bundle
    

    Add to config/bundles.php:

    return [
        // ...
        Bentools\ApiFirstBundle\BentoolsApiFirstBundle::class => ['all' => true],
    ];
    
  2. Define a Resource Entity Create an entity implementing Bentools\ApiFirstBundle\Model\ResourceInterface:

    use Bentools\ApiFirstBundle\Model\ResourceInterface;
    
    class User implements ResourceInterface
    {
        private $id;
        private $name;
    
        public function getId(): ?int
        {
            return $this->id;
        }
    }
    
  3. Generate Handler & Actions Use the bundle’s CLI or manually create:

    • UserHandler extending AbstractResourceHandler
    • UserAction (e.g., UserCreateAction, UserUpdateAction) extending AbstractAction
  4. Route & Use

    # config/routes.yaml
    user_create:
        path: /users
        controller: Bentools\ApiFirstBundle\Controller\ActionController::handle
        defaults:
            action: App\Action\UserCreateAction
    

First Use Case

Create a RESTful API endpoint for a User resource:

  1. Extend AbstractResourceHandler for UserHandler:
    class UserHandler extends AbstractResourceHandler
    {
        protected function getFormType(): string
        {
            return UserType::class; // Custom form type
        }
    }
    
  2. Implement UserCreateAction:
    class UserCreateAction extends AbstractAction
    {
        public function __invoke(Request $request, UserHandler $handler)
        {
            return $this ->handle($request, $handler, new User());
        }
    }
    
  3. Test via HTTP:
    curl -X POST http://your-app/users -d '{"name":"John"}'
    

Implementation Patterns

Core Workflows

  1. Form Handling (HTTP-Agnostic)

    • Use AbstractResourceHandler for validation/logic, decoupled from HTTP layer.
    • Example: Bulk updates via CLI:
      $handler = $container->get(UserHandler::class);
      $users = $handler->processBulk($rawDataArray); // No Request needed
      
  2. Action Composition

    • Chain actions for workflows (e.g., createsendWelcomeEmail):
      class UserCreateAction extends AbstractAction
      {
          public function __invoke(Request $request, UserHandler $handler, EmailService $email)
          {
              $user = $this->handle($request, $handler, new User());
              $email->sendWelcome($user);
              return $this->json($user);
          }
      }
      
  3. Resource Relationships

    • Handle nested resources via AbstractResourceHandler:
      $handler = $container->get(PostHandler::class);
      $post = $handler->process($request, $postEntity);
      $handler->handleRelated('author', $post, $authorData); // Attach author
      

Integration Tips

  1. Symfony Forms Integration

    • Extend AbstractType for forms:
      class UserType extends AbstractType
      {
          public function buildForm(FormBuilderInterface $builder, array $options)
          {
              $builder->add('name', TextType::class);
          }
      }
      
    • Link to handler via getFormType() in UserHandler.
  2. API Responses

    • Use AbstractAction’s handle() to auto-serialize resources (via Serializer):
      return $this->json($this->handle($request, $handler, $user));
      
  3. Testing

    • Mock AbstractResourceHandler for unit tests:
      $handler = $this->createMock(UserHandler::class);
      $handler->method('process')->willReturn($user);
      
  4. Event Listeners

    • Attach listeners to ResourceEvents (e.g., PRE_VALIDATE, POST_CREATE):
      $dispatcher->addListener(
          ResourceEvents::POST_CREATE,
          [$this, 'onUserCreated']
      );
      

Gotchas and Tips

Pitfalls

  1. Deprecation Risk

  2. ORM Assumptions

    • Assumes Doctrine ORM/ODM. For custom storage (e.g., Elasticsearch), override:
      class CustomHandler extends AbstractResourceHandler
      {
          protected function getEntityManager(): EntityManagerInterface
          {
              return $this->container->get('custom.manager');
          }
      }
      
  3. Validation Overrides

    • Forms may conflict with Symfony Validator. Explicitly disable one:
      $builder->get('name')->setConstraint(null); // Disable Symfony Validator
      
  4. Circular Dependencies

    • Avoid circular references in AbstractAction/AbstractResourceHandler:
      // Bad: Handler injects Action which injects Handler
      // Good: Use DTOs or services for decoupling.
      

Debugging

  1. Validation Errors

    • Catch ValidationFormException for form errors:
      try {
          $user = $handler->process($request, $user);
      } catch (ValidationFormException $e) {
          return $this->json($e->getErrors(), 400);
      }
      
  2. Handler Not Found

    • Ensure services are autowired:
      # config/services.yaml
      App\Handler\UserHandler: ~
      
  3. Serialization Issues

    • Override serialize() in ResourceInterface:
      public function serialize(): array
      {
          return [
              'id' => $this->id,
              'name' => $this->name,
          ];
      }
      

Extension Points

  1. Custom Actions

    • Extend AbstractAction for non-CRUD logic:
      class UserExportAction extends AbstractAction
      {
          public function __invoke(UserHandler $handler)
          {
              $users = $handler->findAll();
              return $this->file($users->toCsv());
          }
      }
      
  2. Dynamic Handlers

    • Use AbstractResourceHandler as a base for dynamic routes:
      $handler = $container->get(sprintf('%sHandler', $resourceClass));
      
  3. Event Customization

    • Dispatch custom events:
      $dispatcher->dispatch(new ResourceEvent($resource, 'CUSTOM_EVENT'));
      
  4. Testing Utilities

    • Create a ResourceTestCase base class:
      abstract class ResourceTestCase extends WebTestCase
      {
          protected function createHandler(): AbstractResourceHandler
          {
              return $this->getContainer()->get(UserHandler::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.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware