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 Twig Bundle Laravel Package

antalaron/doctrine-twig-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle

    composer require antalaron/doctrine-twig-bundle
    
  2. Enable the Bundle Add to config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 2/3):

    Antalaron\DoctrineTwigBundle\AntalaronDoctrineTwigBundle::class => ['all' => true],
    
  3. Configure the Bundle Add to config/packages/antalaron_doctrine_twig.yaml (Symfony 4+):

    antalaron_doctrine_twig:
        entity: App\Entity\TemplateEntity  # Your Doctrine entity storing templates
        template_field: content           # Field containing Twig template content
        id_field: id                      # Field used as template ID
    
  4. Create a Template Entity Define a Doctrine entity (e.g., TemplateEntity) with fields like:

    // src/Entity/TemplateEntity.php
    #[ORM\Entity]
    class TemplateEntity {
        #[ORM\Id, ORM\GeneratedValue, ORM\Column]
        private ?int $id = null;
    
        #[ORM\Column(type: 'text')]
        private string $content; // Twig template content
    
        // Getters/setters...
    }
    
  5. First Use Case: Render a Template

    use Antalaron\DoctrineTwigBundle\Loader\DoctrineLoader;
    
    // In a controller/service:
    $template = $entityManager->getRepository(TemplateEntity::class)
        ->findOneBy(['id' => 1]);
    
    $twig = $this->container->get('twig');
    $rendered = $twig->render('doctrine://1', ['name' => 'John']);
    

Implementation Patterns

1. Dynamic Template Loading

  • Workflow: Store reusable templates (e.g., emails, dynamic UI components) in the database.
  • Example:
    // Fetch and render a template dynamically
    $templateId = $request->get('template_id');
    $rendered = $twig->render("doctrine://{$templateId}", $context);
    

2. Integration with Twig Extensions

  • Extend Twig Globals:
    // src/Twig/AppExtension.php
    class AppExtension extends \Twig\Extension\AbstractExtension {
        public function getGlobals() {
            return [
                'dynamic_templates' => $this->getTemplatesFromDB(),
            ];
        }
    }
    
    Register the extension in config/packages/twig.yaml:
    twig:
        extensions:
            - App\Twig\AppExtension
    

3. Caching Strategies

  • Leverage Twig’s Cache: The bundle integrates with Twig’s cache system. Ensure your TemplateEntity is cached appropriately:

    # config/packages/framework.yaml
    framework:
        twig:
            cache: '%kernel.cache_dir%/twig'
    
  • Manual Cache Invalidation: Clear Twig cache when templates are updated:

    $this->container->get('twig')->getEnvironment()->clearCacheFile(
        $this->container->getParameter('kernel.cache_dir').'/twig/doctrine_*.php'
    );
    

4. Security Context

  • Sanitize Template Input: Use Twig’s auto-escaping and validate template content before saving:
    // In a form type or service
    $template->setContent($sanitizedTwigContent);
    

5. Bulk Template Management

  • Admin Interface: Create a CRUD interface (e.g., with EasyAdmin or API Platform) to manage templates:
    # config/packages/easy_admin.yaml
    easy_admin:
        entities:
            TemplateEntity:
                class: App\Entity\TemplateEntity
                list: [id, name]
                form: [content]
    

Gotchas and Tips

Pitfalls

  1. Template Parsing Errors:

    • Issue: Twig fails to parse templates stored in the DB due to malformed syntax.
    • Fix: Validate templates before saving (e.g., use Twig_Loader_Filesystem to test parsing):
      $loader = new \Twig\Loader\Filesystem([], '/tmp');
      $twig = new \Twig\Environment($loader);
      try {
          $twig->createTemplate($templateContent);
      } catch (\Twig_Error_Syntax $e) {
          throw new \RuntimeException("Invalid Twig syntax: {$e->getMessage()}");
      }
      
  2. Circular Dependencies:

    • Issue: Templates referencing other templates (e.g., {% include 'doctrine://2' %}) may cause infinite loops.
    • Fix: Limit recursion depth in Twig or use absolute paths:
      {% include 'doctrine://' ~ templateId %}
      
  3. Performance Overhead:

    • Issue: Querying the DB for every template render is slow.
    • Fix: Cache frequently used templates in memory (e.g., with Symfony\Component\Cache):
      $cache = $this->container->get('cache.app');
      $cached = $cache->get("template_{$templateId}", function() use ($templateId) {
          return $this->getTemplateFromDB($templateId);
      });
      
  4. Symfony 4+ Kernel Awareness:

    • Issue: Bundle assumes AppKernel (Symfony 2/3). For Symfony 4+, ensure the bundle is registered in config/bundles.php.
    • Fix: Use autoconfigure: true in config/packages/framework.yaml if needed.

Debugging Tips

  1. Enable Twig Debugging:

    # config/packages/twig.yaml
    twig:
        debug: '%kernel.debug%'
        strict_variables: '%kernel.debug%'
    
    • Check Twig errors in the browser or logs for syntax issues.
  2. Log Template Renders:

    $twig->addExtension(new \Twig\Extension\DebugExtension());
    
    • Useful for tracking which templates are being loaded.
  3. SQL Queries:

    • Enable Doctrine profiling to monitor DB queries:
      # config/packages/dev/doctrine.yaml
      doctrine:
          dbal:
              profiling: true
      

Extension Points

  1. Custom Loader: Extend the DoctrineLoader to add logic (e.g., ACL checks):

    class CustomDoctrineLoader extends DoctrineLoader {
        public function getSourceContext($name) {
            $template = parent::getSourceContext($name);
            if (!$this->isAllowed($template->getId())) {
                throw new \Twig_Error_Loader("Access denied");
            }
            return $template;
        }
    }
    

    Register it in services.yaml:

    services:
        Antalaron\DoctrineTwigBundle\Loader\DoctrineLoader:
            class: App\Twig\CustomDoctrineLoader
    
  2. Event Listeners: Trigger actions when templates are rendered (e.g., analytics):

    // src/EventListener/TemplateRenderListener.php
    class TemplateRenderListener implements \Twig\EventListenerInterface {
        public function onLoad(\Twig\Event\LoadEvent $event) {
            if (strpos($event->getTemplate()->getSourceContext()->getName(), 'doctrine://') === 0) {
                // Log or track template usage
            }
        }
    }
    

    Register the listener in services.yaml:

    services:
        App\EventListener\TemplateRenderListener:
            tags: ['twig.event_listener']
    
  3. Template Versioning: Add a version field to TemplateEntity and implement a custom loader to handle updates:

    class VersionedDoctrineLoader extends DoctrineLoader {
        public function getSourceContext($name) {
            $template = parent::getSourceContext($name);
            if ($this->hasNewerVersion($template->getId())) {
                return $this->getLatestVersion($template->getId());
            }
            return $template;
        }
    }
    
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