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

Ecentria Rest Bundle Laravel Package

ecentria/ecentria-rest-bundle

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require ecentria/ecentria-rest-bundle

Enable the bundle in config/bundles.php:

return [
    // ...
    Ecentria\RestBundle\EcentriaRestBundle::class => ['all' => true],
];
  1. First Use Case: Create a RESTful resource controller for a Post entity:

    php bin/console generate:bundle --namespace=App/Bundle/PostBundle --format=yml --dir=src --bundle=PostBundle
    

    Extend EcentriaRestBundle's RestController:

    // src/PostBundle/Controller/PostController.php
    namespace App\Bundle\PostBundle\Controller;
    
    use Ecentria\RestBundle\Controller\RestController;
    use App\Bundle\PostBundle\Entity\Post;
    
    class PostController extends RestController
    {
        public function getEntityFQCN(): string
        {
            return Post::class;
        }
    }
    
  2. Routing: Configure routes in config/routes.yaml:

    app_post:
        resource: "@PostBundle/Resources/config/routing.yml"
        prefix: /api/posts
    
  3. Verify: Access endpoints like:

    • GET /api/posts (List)
    • POST /api/posts (Create)
    • GET /api/posts/{id} (Read)
    • PUT/PATCH /api/posts/{id} (Update)
    • DELETE /api/posts/{id} (Delete)

Implementation Patterns

1. Resource-Oriented Controllers

  • Pattern: Extend RestController and implement getEntityFQCN() to define the managed entity.
    class UserController extends RestController
    {
        public function getEntityFQCN(): string
        {
            return User::class;
        }
    }
    
  • Custom Actions: Override methods like getList(), getItem(), or postItem() for custom logic.
    public function getList(): Response
    {
        $users = $this->getDoctrine()->getRepository(User::class)->findActiveUsers();
        return $this->handleList($users);
    }
    

2. HATEOAS Integration

  • Automatic Links: The bundle auto-generates HATEOAS links (e.g., _links.self, _links.collection) in responses.
  • Custom Links: Add custom links via addLink() in controllers:
    public function getItem(User $user): Response
    {
        $response = $this->handleItem($user);
        $response->getData()->addLink('profile', '/api/users/'.$user->getId().'/profile');
        return $response;
    }
    

3. Serialization Groups

  • Symfony Serializer: Use @Groups annotations to control serialization:
    use Symfony\Component\Serializer\Annotation\Groups;
    
    class User
    {
        #[Groups(['user:read'])]
        private string $name;
    }
    
  • Configure in Controller:
    public function getItem(User $user): Response
    {
        return $this->handleItem($user, ['groups' => ['user:read']]);
    }
    

4. Validation

  • Auto-Validation: The bundle validates incoming data against entity constraints (e.g., @Assert\NotBlank).
  • Custom Validation: Override validate() in controllers or use Symfony’s ValidatorInterface.

5. Pagination

  • KnpuOAuth2Client Bundle: Integrate with knplabs/knp-paginator-bundle for pagination:
    # config/packages/ecentria_rest.yaml
    ecentria_rest:
        pagination:
            enabled: true
            items_per_page: 20
    
  • Custom Pagination: Pass a Paginator object to handleList():
    public function getList(): Response
    {
        $paginator = $this->get('knp_paginator');
        $users = $paginator->paginate(
            $this->getDoctrine()->getRepository(User::class)->findAll(),
            $this->getRequest()->query->getInt('page', 1),
            10
        );
        return $this->handleList($users);
    }
    

6. Event Listeners

  • Lifecycle Events: Hook into events like prePersist, preUpdate, or postRemove:
    // src/EventListener/UserListener.php
    namespace App\EventListener;
    
    use Ecentria\RestBundle\Event\RestEvent;
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    
    class UserListener implements EventSubscriberInterface
    {
        public static function getSubscribedEvents(): array
        {
            return [
                'ecentria_rest.pre_persist' => 'onPrePersist',
            ];
        }
    
        public function onPrePersist(RestEvent $event): void
        {
            $user = $event->getEntity();
            $user->setCreatedAt(new \DateTime());
        }
    }
    

7. Authentication & Authorization

  • Symfony Security: Integrate with Symfony’s security system:
    # config/packages/security.yaml
    access_control:
        - { path: ^/api/users, roles: ROLE_USER }
    
  • Custom Guards: Extend RestController to add authentication logic:
    public function postItem(): Response
    {
        if (!$this->isGranted('ROLE_ADMIN')) {
            throw $this->createAccessDeniedException();
        }
        return parent::postItem();
    }
    

8. Testing

  • Functional Tests: Use Client to test endpoints:
    public function testGetPosts(): void
    {
        $client = static::createClient();
        $client->request('GET', '/api/posts');
        $this->assertResponseIsSuccessful();
        $this->assertJsonContains([
            '@context' => '/api/contexts/Post',
            '@id' => '/api/posts',
        ]);
    }
    
  • Mocking: Mock RestController in unit tests:
    $controller = $this->getMockBuilder(RestController::class)
        ->setMethods(['getEntityFQCN'])
        ->getMock();
    $controller->method('getEntityFQCN')->willReturn(Post::class);
    

Gotchas and Tips

Common Pitfalls

  1. Entity Not Found:

    • Issue: 404 when accessing /api/resource/{id} even if the entity exists.
    • Fix: Ensure getItem() in your controller is properly annotated or overridden. Verify the find() method in the repository returns the entity.
    • Debug: Add logging in getItem():
      public function getItem($id): Response
      {
          $entity = $this->getDoctrine()->getRepository($this->getEntityFQCN())->find($id);
          if (!$entity) {
              throw $this->createNotFoundException('Entity not found');
          }
          return $this->handleItem($entity);
      }
      
  2. Serialization Errors:

    • Issue: 500 Internal Server Error with "Unable to serialize object" in responses.
    • Fix: Ensure all properties in your entity are serializable or use @Ignore for non-serializable properties:
      use Symfony\Component\Serializer\Annotation\Ignore;
      
      class User
      {
          #[Ignore]
          private $sensitiveData;
      }
      
    • Tip: Use NormalizerInterface to customize serialization:
      // src/Serializer/UserNormalizer.php
      namespace App\Serializer;
      
      use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
      
      class UserNormalizer implements NormalizerInterface
      {
          public function normalize($object, $format = null, array $context = [])
          {
              return [
                  'id' => $object->getId(),
                  'name' => $object->getName(),
              ];
          }
      }
      
      Register it in config/packages/ecentria_rest.yaml:
      ecentria_rest:
          normalizers:
              - App\Serializer\UserNormalizer
      
  3. HATEOAS Links Missing:

    • Issue: _links section is empty in responses.
    • Fix: Ensure the bundle is properly configured in config/packages/ecentria_rest.yaml:
      ecentria_rest:
          hateoas:
              enabled: true
      
    • Debug: Check if the RestResponse object is being returned correctly. Override handleItem() or handleList() to inspect the response:
      public function getItem(User $user): Response
      {
          $response = $this->handleItem($user);
          $data = $response->getData();
          dump($data->getLinks()); // Debug links
          return $response;
      }
      
  4. **Pagination Not Working

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