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

Restify Bundle Laravel Package

antoi/restify-bundle

Reusable Symfony bundle (6.4–8.x, PHP 8.2+) that provides a full REST CRUD stack: abstract repository/service/controller, automatic entity hydration, query filtering, eager-loading, and pick-based response enrichment. Six endpoints per resource, quickly wired.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require antoi/restify-bundle
    

    Register the bundle in config/bundles.php:

    Antoi\RestifyBundle\RestifyBundle::class => ['all' => true],
    
  2. First Use Case: Create a basic User resource with these 3 files:

    • Repository (src/Repository/UserRepository.php):
      use Antoi\RestifyBundle\Repository\AbstractRestRepository;
      
      class UserRepository extends AbstractRestRepository {
          public function __construct(ManagerRegistry $registry) {
              parent::__construct($registry, User::class);
          }
          protected function getFilterableFields(): array { return ['name', 'email']; }
      }
      
    • Service (src/Service/UserService.php):
      use Antoi\RestifyBundle\Service\AbstractRestService;
      
      class UserService extends AbstractRestService {
          protected function getEntityClass(): string { return User::class; }
          protected function getWritableFields(): array { return ['name', 'email']; }
      }
      
      Wire in config/services.yaml:
      App\Service\UserService:
        arguments:
          $repository: '@App\Repository\UserRepository'
      
    • Controller (src/Controller/UserController.php):
      use Antoi\RestifyBundle\Controller\AbstractRestController;
      
      #[Route('/api/users')]
      class UserController extends AbstractRestController {
          public function __construct(
              SerializerInterface $serializer,
              ValidatorInterface $validator,
              PickResolver $pickResolver,
              UserService $service
          ) {
              parent::__construct($serializer, $validator, $pickResolver, $service);
          }
          protected function getReadGroups(): array { return ['user:read']; }
      }
      
  3. Test Endpoints:

    • GET /api/users → Paginated list with filtering/sorting.
    • POST /api/users → Create with validation.
    • GET /api/users/1?pick=roles.name → Enriched response.

Where to Look First

  • README.md: Focus on the Full wiring example and Endpoints tables.
  • Repository Class: Override getFilterableFields() and getDefaultJoins() for query customization.
  • Controller: Extend AbstractRestController and define serialization groups (getReadGroups()).
  • Service: Whitelist writable fields in getWritableFields().
  • Pick Queries: Use ?pick= to dynamically add properties to responses (e.g., ?pick=lastLogin.ip).

Implementation Patterns

Core Workflows

1. CRUD Lifecycle

  • Create/Update: Data flows through: Controllerservice->hydrate()ValidatorRepositoryEntityManager. Override UserService::create() or update() for custom logic (e.g., audit logs).
  • List/Show: Queries are built dynamically: Controllerservice->list()Repository->applyFilters()Doctrine QueryBuilder. Extend AbstractRestRepository for complex DQL.

2. Filtering and Sorting

  • Dynamic Filters: Query params like ?status=active&createdAt_gte=2024-01-01 map to SQL via operator suffixes (_gte, _like).
    • Pattern: Use getFilterableFields() to whitelist safe fields.
    • Example: Block sensitive fields (e.g., password) from filtering.
  • Sorting: ?sort=name,-createdAtORDER BY name ASC, createdAt DESC.
    • Pattern: No explicit whitelisting; rely on Doctrine’s ORDER BY validation.

3. Serialization

  • Groups: Define getReadGroups() in the controller to scope serialized fields (e.g., ['user:read']).
    • Pattern: Use Symfony’s #[Groups] on entity properties.
  • Pick Queries: Add runtime properties via ?pick=ip,roles.name.
    • Pattern: Implement getIp() in User entity or extend PickResolver for custom logic.

4. Validation

  • Automatic: The service validates against getWritableFields() using Symfony’s Validator.
    • Pattern: Add #[Assert\Email] to User entity for field-level rules.
  • Custom: Override UserService::validate() for cross-field logic (e.g., "email must match domain").

5. Pagination

  • Automatic: ?page=2&limit=10PaginatedResponse with meta object.
    • Pattern: Customize pagination via Repository->setDefaultLimit() or override Controller->paginate().

Integration Tips

Symfony Ecosystem

  • Doctrine: Works seamlessly with Doctrine ORM. For custom repositories, extend AbstractRestRepository and override createQueryBuilder().
  • Serializer: Uses Symfony’s SerializerInterface. Extend with custom normalizers for non-standard types.
  • Validation: Integrates with Symfony’s Validator. Add constraints via #[Assert\...] or override Service->validate().
  • Security: Works with Symfony’s security component. Add @IsGranted("ROLE_ADMIN") to controller methods.

Customization Points

Component Extend/Override Use Case
Repository getFilterableFields() Whitelist safe filter fields.
getDefaultJoins() Pre-load relations (e.g., ['role']).
createQueryBuilder() Custom DQL for complex queries.
Service hydrate() Custom entity hydration logic.
validate() Cross-field validation.
prePersist()/postPersist() Audit logs, soft deletes.
Controller list()/show()/create() etc. Custom actions (e.g., bulk operations).
getReadGroups()/getListGroups() Dynamic serialization groups.
PickResolver resolve() Custom pick logic (e.g., computed fields).
ApiResponse create() Custom response envelopes.

Common Extensions

  1. Bulk Operations:
    #[Route('/api/users/bulk', methods: ['POST'])]
    public function bulkCreate(Request $request) {
        $data = json_decode($request->getContent(), true);
        $users = $this->service->bulkHydrate($data);
        $this->entityManager->persist($users);
        $this->entityManager->flush();
        return $this->json(['success' => true, 'data' => $users]);
    }
    
  2. Soft Deletes:
    // In UserService
    protected function prePersist(User $entity, array $data): void {
        if (isset($data['isDeleted']) && $data['isDeleted']) {
            $entity->setDeletedAt(new \DateTime());
        }
    }
    
  3. Custom Actions:
    #[Route('/api/users/{id}/activate', methods: ['PATCH'])]
    public function activate(User $user) {
        $user->setStatus('active');
        $this->entityManager->flush();
        return $this->json(['success' => true]);
    }
    

Testing Patterns

  • Unit Test Services: Mock AbstractRestRepository and test hydration/validation.
    $repository = $this->createMock(AbstractRestRepository::class);
    $service = new UserService($repository);
    $user = $service->hydrate(['name' => 'John']);
    $this->assertInstanceOf(User::class, $user);
    
  • Functional Test Controllers: Use ApiTestCase to test endpoints with query params.
    $client = static::createClient();
    $client->request('GET', '/api/users?status=active&pick=roles.name');
    $this->assertResponseIsSuccessful();
    $this->assertJsonContains(['data' => [...], 'meta' => ['total' => 1]]);
    
  • Integration Test Picks: Verify PickResolver behavior.
    $user = new User();
    $user->setIp('192.168.1.1');
    $resolver = new PickResolver();
    $picks = $resolver->resolve($user, ['ip']);
    $this->assertEquals('192.168.1.1', $picks['ip']);
    

Gotchas and Tips

Pitfalls

  1. Field Whitelisting Mismatches:
    • Issue: getWritableFields() in the service and #[Groups] in the entity must align. Validation errors may occur if they diverge.
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.
craftcms/url-validator
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony