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

Base Laravel Package

backsystem/base

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require backsystem/base
    

    Add the bundle to config/bundles.php:

    Backsystem\Base\BaseBundle::class => ['all' => true],
    
  2. First Use Case: Doctrine Entity Base Extend BaseEntity for automatic timestamping, soft deletes, and UUID support:

    use Backsystem\Base\Entity\BaseEntity;
    
    #[ORM\Entity]
    class User extends BaseEntity
    {
        #[ORM\Column]
        private string $name;
    }
    
    • Key Features Activated:
      • createdAt, updatedAt fields (via BaseEntity traits)
      • UUID primary key (configured in BaseBundle config)
      • Soft deletes (via SoftDeletable trait)
  3. Configuration Override defaults in config/packages/backsystem_base.yaml:

    backsystem_base:
        use_uuid: true
        soft_deletes: true
        default_locale: 'en'
    

Implementation Patterns

1. Entity Layer Patterns

  • Traits for Reusability Combine traits in your entities for modular behavior:

    use Backsystem\Base\Entity\Traits\{
        SoftDeletable,
        Sluggable,
        Translatable
    };
    
    class Product extends BaseEntity
    {
        use SoftDeletable, Sluggable;
    }
    
    • Sluggable: Auto-generates slug from name (configurable separator).
    • Translatable: Supports locale-specific fields (e.g., name_en, name_fr).
  • Repository Integration Extend BaseRepository for common CRUD operations:

    use Backsystem\Base\Repository\BaseRepository;
    
    class UserRepository extends BaseRepository
    {
        public function findByEmail(string $email): ?User
        {
            return $this->createQueryBuilder('u')
                ->where('u.email = :email')
                ->setParameter('email', $email)
                ->getOneOrNullResult();
        }
    }
    
    • Automatic Pagination: Use paginate() with KnpPaginatorBundle:
      $users = $this->paginate(User::class, $page, 10);
      

2. Form Handling

  • Dynamic Form Types Use BaseFormType for rapid form creation with built-in validation:
    use Backsystem\Base\Form\BaseFormType;
    
    class UserType extends BaseFormType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('name', TextType::class, [
                    'constraints' => [new NotBlank(), new Length(['max' => 100])],
                ])
                ->add('email', EmailType::class);
        }
    }
    
    • Auto-Validation: Integrates with Symfony’s validator component.
    • CSRF Protection: Enabled by default (via Symfony SecurityBundle).

3. Messenger Integration

  • Async Operations Dispatch messages for background processing:
    use Backsystem\Base\Message\SendEmail;
    
    $this->messageBus->dispatch(new SendEmail(
        'user@example.com',
        'Welcome!',
        'email_template.html.twig'
    ));
    
    • Handlers: Create custom handlers (e.g., SendEmailHandler) and tag them with @asynchronous.

4. Translation System

  • Locale-Aware Entities Use Translatable trait for multi-language support:
    class Product extends BaseEntity
    {
        use Translatable;
    
        #[ORM\Column]
        private string $name; // Base field
    
        #[ORM\Column(nullable: true)]
        private ?string $nameEn = null;
    
        #[ORM\Column(nullable: true)]
        private ?string $nameFr = null;
    }
    
    • Twig Integration: Access translations via {{ product.name(currentLocale) }}.

5. Twig Extensions

  • Utility Functions Add to templates:
    {{ dump(base_entity.getUuid()) }}
    {{ base_form.hasErrors(form) ? 'Error!' : '' }}
    {{ knp_pagination_render(paginator) }}
    

Gotchas and Tips

Pitfalls

  1. UUID vs. Auto-Increment

    • If use_uuid: true is set but your database lacks a uuid-ossp extension, fall back to auto-increment:
      backsystem_base:
          use_uuid: false # Override in production
      
  2. Soft Deletes in Queries

    • Forgetting to scope soft-deleted records:
      // ❌ Missing scope
      $user = $entityManager->getRepository(User::class)->find(1);
      
      // ✅ Correct (uses BaseRepository's soft-delete scope)
      $user = $entityManager->getRepository(User::class)->findOneBy(['id' => 1]);
      
  3. Translation Locale Mismatch

    • Ensure default_locale in config matches your app’s locale (e.g., en vs. en_US).
  4. Messenger Transport Configuration

    • If using async transports (e.g., Doctrine), configure in .env:
      MESSENGER_TRANSPORT_DSN=doctrine://default
      

Debugging Tips

  • Enable SQL Logging Add to config/packages/dev/doctrine.yaml:

    dbal:
        logging: true
        profiling: true
    
  • Check Entity Changes Use BaseEntity's getChangedFields() to debug updates:

    $user->setName('New Name');
    dump($user->getChangedFields()); // ['name' => ['old' => 'Old Name', 'new' => 'New Name']]
    

Extension Points

  1. Custom Traits Extend BaseEntity with your own traits (e.g., AuditLoggable):

    namespace App\Entity\Traits;
    
    use Doctrine\ORM\Mapping as ORM;
    
    trait AuditLoggable
    {
        #[ORM\Column(type: 'json')]
        private array $auditLog = [];
    
        public function logChange(string $action, string $field, $oldValue, $newValue): void
        {
            $this->auditLog[] = compact('action', 'field', 'oldValue', 'newValue');
        }
    }
    
  2. Override Form Types Customize BaseFormType behavior:

    class CustomUserType extends BaseFormType
    {
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults([
                'csrf_token_id' => 'custom_token', // Override CSRF token
            ]);
        }
    }
    
  3. Event Subscribers Listen to BaseEntity lifecycle events:

    use Backsystem\Base\Event\BaseEntityEvents;
    
    $dispatcher->addListener(BaseEntityEvents::PRE_PERSIST, function (BaseEntityEvent $event) {
        if ($event->getEntity() instanceof User) {
            $event->getEntity()->setEmail(strtolower($event->getEntity()->getEmail()));
        }
    });
    

Performance Considerations

  • Batch Operations Use BaseRepository::bulkUpdate() for large datasets:
    $this->bulkUpdate(
        User::class,
        ['status' => 'active'],
        ['id' => [1, 2, 3]]
    );
    
  • Query Optimization Avoid N+1 issues by eager-loading associations:
    $users = $this->findBy(['role' => 'admin'], ['posts' => 'id']);
    
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