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

Rad Laravel Package

21torr/rad

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require 21torr/rad
    

    Ensure your config/bundles.php includes RadBundle.

  2. First Use Case:

    • API Responses: Replace manual JsonResponse with ApiResponse in controllers:
      use Rad\ApiResponse;
      
      public function show(): ApiResponse
      {
          return ApiResponse::ok(['data' => $this->getData()]);
      }
      
    • Entity Handling: Use EntityModel for CRUD operations:
      use Rad\EntityModel;
      
      $model = new EntityModel($entityManager, User::class);
      $model->persist($request->toArray());
      
  3. Key Entry Points:

    • Documentation (official)
    • src/Rad/ namespace (core classes)
    • config/packages/rad.yaml (optional bundle config)

Implementation Patterns

Core Workflows

1. API Layer

  • Response Normalization:

    // Controller
    public function create(Request $request): ApiResponse
    {
        $data = $this->handleRequest($request);
        return ApiResponse::created($data, ['Location' => $this->generateUrl('show', ['id' => $data['id']])]);
    }
    
    • Use ApiResponseNormalizer for custom serialization:
      $normalizer = $this->container->get(ApiResponseNormalizer::class);
      $response = $normalizer->createResponse($data, 200, ['X-Custom' => 'Header']);
      
  • Error Handling:

    try {
        $result = $this->service->execute();
    } catch (ValidationException $e) {
        return ApiResponse::validationError($e->getErrors());
    }
    

2. Entity Management

  • CRUD with EntityModel:

    $model = new EntityModel($entityManager, Post::class);
    $model->persist($request->validate()->all()); // Handles create/update
    $model->refresh(); // Force refresh from DB
    
    • Skip marking as modified:
      $model->update($data, skipModified: true);
      
  • Change Tracking:

    $changeChecker = new DoctrineChangeChecker($entityManager);
    $changes = $changeChecker->getEntityChanges($entity); // Returns array of changed fields
    

3. Data Import/Export

  • Import Data:
    use Rad\ImportData;
    
    $import = new ImportData($request->json());
    $import->normalizeEmptyStringsToNull(); // Auto-normalize
    $cleanData = $import->getData();
    

4. Authorization

  • Attribute-Based Voting:
    // In your entity
    #[Attribute('CAN_EDIT')]
    public function canEdit(): bool { return $this->isAdmin; }
    
    // In voter
    public function vote(AuthorizationContext $context): bool
    {
        return $context->getAttribute('CAN_EDIT', $entity);
    }
    

5. Utilities

  • Translation Helper:
    $translation = $this->translationHelper->translate('key', ['%name%' => $user->name]);
    
  • Argument Bag:
    $args = new ArgumentBag(['key' => 'value']);
    $args['nested']['key'] = 'value'; // ArrayAccess support
    

Integration Tips

  • BaseController: Extend Rad\BaseController for shared logic:
    class PostController extends BaseController
    {
        public function __construct(private EntityManagerInterface $em) {}
    
        protected function getEntityManager(): EntityManagerInterface
        {
            return $this->em;
        }
    }
    
  • Dependency Injection: Autowire TranslationHelper, ApiResponseNormalizer, etc., directly.
  • Symfony Forms: Use EntityModel with FormFactory for seamless integration:
    $form = $this->formFactory->create(PostType::class, $model->getEntity());
    

Gotchas and Tips

Pitfalls

  1. PHP Version:

    • Requires PHP 8.4+ (as of v3.4.0). Check composer.json for your project’s constraints.
    • Tip: Use php -v and update if needed.
  2. DoctrineChangeChecker:

    • Deprecated in v3.4.5: Use DoctrineChangeChecker::getEntityChanges() sparingly—it modifies the UnitOfWork.
    • Workaround: Clone the entity before checking:
      $clone = clone $entity;
      $changes = $changeChecker->getEntityChanges($clone);
      
  3. ApiResponse:

    • Explicit Status Codes: Constructor no longer accepts bool (deprecated in v3.1.0). Always pass HTTP codes:
      // ❌ Avoid
      ApiResponse::ok(true); // Deprecated
      
      // ✅ Use
      ApiResponse::ok(['data' => $data], 200);
      
    • Error Messages: User-friendly messages are auto-generated for NotNull violations.
  4. EntityModel:

    • Persist vs. Update: persist() handles both create/update. Use update() only for partial updates.
    • Refresh Behavior: refresh() detaches and re-attaches the entity. Use cautiously in transactions.
  5. ImportData:

    • Empty Strings: Normalized to null by default (v3.4.1). Disable with:
      $import = new ImportData($data, normalizeEmptyStrings: false);
      
  6. ArrayAccess in ArgumentBag:

    • Supports nested arrays but may throw UndefinedArrayKeyException if keys don’t exist. Initialize with defaults:
      $args = new ArgumentBag(['nested' => ['key' => null]]);
      

Debugging Tips

  1. JSON Request Logging:

    • If JSON parsing fails, check logs for raw JSON (added in v3.4.0). Enable debug mode:
      # config/packages/dev/rad.yaml
      rad:
        debug: true
      
  2. Change Tracking:

    • Log changes for debugging:
      $changes = $changeChecker->getEntityChanges($entity);
      $this->logger->debug('Entity changes', ['changes' => $changes]);
      
  3. Autocompletion:

    • Use @method annotations for IDE support (improved in v3.4.3). Example:
      /**
       * @method static self create(array $data)
       */
      class EntityModel {}
      

Extension Points

  1. Custom ApiResponse Normalizers:

    • Implement Rad\Normalizer\ApiResponseNormalizerInterface:
      class CustomNormalizer implements ApiResponseNormalizerInterface
      {
          public function normalize($data, int $statusCode, array $headers = []): ApiResponse
          {
              // Custom logic
              return ApiResponse::create($data, $statusCode, $headers);
          }
      }
      
    • Register as service:
      services:
          Rad\Normalizer\ApiResponseNormalizerInterface: '@App\Normalizer\CustomNormalizer'
      
  2. Translation Helpers:

    • Extend Rad\TranslationHelper for custom domains or fallbacks:
      class AppTranslationHelper extends TranslationHelper
      {
          protected function getDefaultDomain(): string
          {
              return 'app';
          }
      }
      
  3. EntityModel Events:

    • Listen to entity_model.persist or entity_model.update via Symfony events:
      // config/services.yaml
      Rad\EntityModel:
          tags: ['rad.entity_model']
      
  4. Doctrine Events:

    • Subscribe to onFlush for pre-persist logic:
      $eventManager->addEventListener(
          ORMEvents::ON_FLUSH,
          fn(OnFlushEventArgs $args) => $this->prePersistLogic($args)
      );
      

Configuration Quirks

  • Optional Dependencies:

    • symfony/translator is optional. If missing, TranslationHelper throws LogicException.
    • Fix: Install or mock translations:
      composer require symfony/translator
      
    • Or stub translations:
      $helper = new TranslationHelper(new NullTranslator());
      
  • Cache Invalidation:

    • InMemoryCache is not persistent. Clear manually or use Symfony’s cache system:
      $cache = new InMemoryCache();
      $cache->clear(); // Manual invalidation
      

Performance Notes

  • EntityModel: Avoid refresh() in loops—batch operations instead.
  • DoctrineChangeChecker: Clone entities before checking to prevent side effects:
    $clone = clone $
    
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.
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
ecotone/kafka
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata