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

Doctrine Extensions Resource Laravel Package

anh/doctrine-extensions-resource

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Install the Package

    composer require anh/doctrine-extensions-resource:0.4.*
    

    Ensure your Laravel project uses Doctrine ORM (e.g., via doctrine/orm or a bundle like anh/doctrine-resource-bundle).

  2. Define Resources Create a configuration array in config/doctrine-resources.php (or equivalent):

    return [
        'article' => [
            'model' => App\Models\Article::class,
            'rules' => [
                'isPublished' => [
                    'isDraft' => false,
                    'publishedSince <= current_timestamp()',
                ],
            ],
        ],
        'category' => [
            'model' => App\Models\Category::class,
        ],
    ];
    
  3. Initialize the Resource Manager In a service provider (e.g., AppServiceProvider):

    use Anh\DoctrineResource\ORM\ResourceRepositoryFactory;
    use Anh\DoctrineResource\ORM\EventListener\LoadMetadataSubscriber;
    use Anh\DoctrineResource\ORM\ResourceManagerFactory;
    use Doctrine\ORM\EntityManagerInterface;
    
    public function register()
    {
        $resources = config('doctrine-resources');
        $repositoryFactory = new ResourceRepositoryFactory($resources, new Paginator());
        $this->app->singleton(ResourceRepositoryFactory::class, fn() => $repositoryFactory);
    
        // Bind ResourceManagerFactory to Laravel's container
        $this->app->singleton(ResourceManagerFactory::class, function ($app) {
            $entityManager = $app->make(EntityManagerInterface::class);
            $eventDispatcher = $app->make(EventDispatcherInterface::class);
            return new ResourceManagerFactory($resources, $eventDispatcher);
        });
    }
    
  4. First Use Case: Fetching Resources Inject ResourceManagerFactory into a controller or service:

    public function index(ResourceManagerFactory $resourceManagerFactory)
    {
        $articleManager = $resourceManagerFactory->create('article', $entityManager);
        $publishedArticles = $articleManager->getRepository()->paginate(1, 10, ['[isPublished]']);
        return view('articles.index', compact('publishedArticles'));
    }
    

Implementation Patterns

Workflows

  1. CRUD Operations Use ResourceManager for standardized CRUD:

    // Create
    $article = $manager->createResource();
    $article->setTitle('Hello World');
    $manager->create($article);
    
    // Update
    $article->setTitle('Updated Title');
    $manager->update($article);
    
    // Delete
    $manager->delete($article);
    
  2. Querying with Criteria Leverage the advanced criteria format for flexible queries:

    // Basic filtering
    $articles = $repository->fetch(['section' => 'tech']);
    
    // Complex criteria with rules
    $publishedTechArticles = $repository->fetch([
        '[isPublished]',
        'section' => 'tech',
        '#or' => [
            '%rating' => ['>', 5],
            'views' => ['>', 1000],
        ],
    ]);
    
    // Pagination
    $paginatedArticles = $repository->paginate(1, 20, ['[isPublished]']);
    
  3. Event-Driven Extensions Subscribe to resource events (e.g., anh_resource.article.pre_create) to add logic:

    $dispatcher->addListener('anh_resource.article.pre_create', function ($event) {
        $article = $event->getResource();
        $article->setCreatedAt(new \DateTime());
    });
    
  4. Repository Overrides Override default repositories per resource:

    $resources = [
        'article' => [
            'model' => App\Models\Article::class,
            'repository' => App\Repositories\CustomArticleRepository::class,
        ],
    ];
    

Integration Tips

  • Laravel Service Container: Bind EntityManager and ResourceManagerFactory as singletons for dependency injection.
  • Form Requests: Use ResourceManager in form requests to validate and persist entities:
    public function store(StoreArticleRequest $request, ResourceManagerFactory $factory)
    {
        $manager = $factory->create('article', $entityManager);
        $article = $manager->createResource();
        $request->persistToEntity($article);
        $manager->create($article);
    }
    
  • API Resources: Combine with Laravel API Resources for JSON serialization:
    public function show(Article $article)
    {
        return new ArticleResource($article);
    }
    

Gotchas and Tips

Pitfalls

  1. Driver-Specific Operators Not all comparison operators (e.g., like, in) are supported across Doctrine drivers (ORM, MongoDB, PHPCR). Test queries thoroughly.

  2. Rule Syntax Errors Rules in resource config must use valid Doctrine query syntax. Example:

    // Invalid (syntax error)
    'isPublished' => ['publishedAt > NOW()'],
    
    // Valid
    'isPublished' => ['publishedAt > current_timestamp()'],
    
  3. Circular Dependencies Avoid defining resources in a circular manner (e.g., Article depends on Category, which depends on Article). Use lazy-loading or separate configurations.

  4. Event Dispatcher Conflicts Ensure the EventDispatcher used in ResourceManagerFactory is the same instance as Doctrine’s to avoid missed events.

Debugging

  • Query Logging: Enable Doctrine logging to debug complex criteria:
    $entityManager->getConnection()->getConfiguration()->setSQLLogger(new \Doctrine\DBAL\Logging\EchoSQLLogger());
    
  • Criteria Validation: Use ResourceRepository::getQueryBuilder() to inspect generated queries:
    $qb = $repository->getQueryBuilder(['[isPublished]']);
    dump($qb->getDQL());
    

Extension Points

  1. Custom Paginator Implement ResourcePaginatorInterface for non-standard pagination (e.g., cursor-based):

    class CustomPaginator implements ResourcePaginatorInterface {
        public function paginate(array $query, $page, $limit) { ... }
    }
    
  2. Dynamic Rules Override RuleResolver to add runtime rules:

    $ruleResolver = new CustomRuleResolver($resources);
    $repositoryFactory = new ResourceRepositoryFactory($resources, $paginator, $ruleResolver);
    
  3. Metadata Subscribers Extend LoadMetadataSubscriber to add custom metadata (e.g., indexes) during entity loading:

    class CustomMetadataSubscriber extends LoadMetadataSubscriber {
        public function loadClassMetadata(ClassMetadata $metadata, $className) {
            if ($className === Article::class) {
                $metadata->addIndex(['title'], 'idx_title');
            }
        }
    }
    

Configuration Quirks

  • Case Sensitivity: Resource names in config must match exactly (e.g., 'Article' vs 'article').
  • Namespace Resolution: Ensure model paths in resources are fully qualified (e.g., App\Models\Article, not Article).
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.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui