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

Entity Rating Bundle Laravel Package

cymo/entity-rating-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require cymo/entity-rating-bundle
    

    Add the bundle to config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3):

    Cymo\Bundle\EntityRatingBundle\CymoEntityRatingBundle::class => ['all' => true],
    
  2. Import Routes: Add to config/routes.yaml:

    cymo_entity_rating:
        resource: "@CymoEntityRatingBundle/Resources/config/routing.yml"
        prefix: /rating
    
  3. First Use Case: Extend BaseEntityRate for your rating entity (e.g., ProductRate, ArticleRate):

    use Cymo\Bundle\EntityRatingBundle\Entity\EntityRate as BaseEntityRate;
    
    #[ORM\Entity(repositoryClass: CymoEntityRatingBundleRepository::class)]
    class ProductRate extends BaseEntityRate
    {
        #[ORM\Id, ORM\GeneratedValue, ORM\Column]
        private ?int $id = null;
    }
    
  4. Annotate Your Entity: Add the #[Rateable] annotation to any entity you want to rate (e.g., Product):

    use Cymo\Bundle\EntityRatingBundle\Annotation\Rateable;
    
    #[Rateable]
    #[ORM\Entity]
    class Product { ... }
    
  5. Run Migrations:

    php bin/console doctrine:migrations:diff
    php bin/console doctrine:migrations:migrate
    

Implementation Patterns

Core Workflow

  1. Rating Submission: Use the RatingService to submit ratings via the API or form:

    $ratingService = $this->container->get('cymo_entity_rating.rating_service');
    $rating = $ratingService->rateEntity(
        $product,  // Your rated entity (must be #[Rateable])
        $user,     // User submitting the rating
        4,         // Rating value (e.g., 1-5)
        'Great product!' // Optional comment
    );
    $entityManager->persist($rating);
    $entityManager->flush();
    
  2. Displaying Ratings: Fetch ratings for an entity via its repository:

    $ratings = $product->getRatings(); // Assumes $product is #[Rateable]
    $average = $ratingService->getAverageRating($product);
    
  3. Frontend Integration: Use the Twig extension to render ratings in templates:

    {% for rating in product.getRatings() %}
        {{ rating.value }}/5 - {{ rating.comment }}
    {% endfor %}
    {{ cymo_entity_rating.getAverageRating(product) }} ({{ product.getRatings().count() }} votes)
    

Advanced Patterns

  1. Custom Rating Logic: Extend RatingService to add business rules (e.g., prevent duplicate ratings):

    class CustomRatingService extends RatingService
    {
        public function rateEntity($entity, User $user, $value, $comment = null)
        {
            if ($this->hasRatedAlready($entity, $user)) {
                throw new \RuntimeException('User already rated this entity.');
            }
            return parent::rateEntity($entity, $user, $value, $comment);
        }
    
        private function hasRatedAlready($entity, User $user): bool
        {
            return $this->entityManager
                ->getRepository(EntityRate::class)
                ->countBy(['entity' => $entity, 'user' => $user]) > 0;
        }
    }
    

    Register the service in services.yaml:

    services:
        App\Service\CustomRatingService: ~
        Cymo\Bundle\EntityRatingBundle\CymoEntityRatingBundle:
            arguments:
                $ratingService: '@App\Service\CustomRatingService'
    
  2. Event-Driven Extensions: Listen to rating events to trigger actions (e.g., notifications):

    // src/EventListener/RatingListener.php
    class RatingListener
    {
        public function onRatingAdded(RatingEvent $event)
        {
            $rating = $event->getRating();
            // Send email, update analytics, etc.
        }
    }
    

    Register the listener in services.yaml:

    services:
        App\EventListener\RatingListener:
            tags:
                - { name: kernel.event_listener, event: cymo_entity_rating.rating_added, method: onRatingAdded }
    
  3. API Endpoints: Use Symfony’s AbstractController to expose rating endpoints:

    #[Route('/api/products/{id}/rate', name: 'api_rate_product', methods: ['POST'])]
    public function rateProduct(Product $product, Request $request, RatingService $ratingService): JsonResponse
    {
        $data = json_decode($request->getContent(), true);
        $rating = $ratingService->rateEntity($product, $this->getUser(), $data['value'], $data['comment'] ?? null);
        return $this->json(['success' => true, 'rating' => $rating]);
    }
    
  4. Bulk Rating Updates: Use Doctrine batch operations for performance:

    $conn = $entityManager->getConnection();
    $conn->executeStatement(
        'UPDATE entity_rate SET value = :value WHERE entity_id = :entityId AND user_id = :userId',
        ['value' => 5, 'entityId' => $product->getId(), 'userId' => $user->getId()]
    );
    

Gotchas and Tips

Pitfalls

  1. Annotation Misconfiguration:

    • Forgetting to add #[Rateable] to your entity will cause getRatings() to return null.
    • Fix: Verify annotations are loaded by checking composer dump-autoload and clearing cache (php bin/console cache:clear).
  2. Circular Dependencies:

    • If your EntityRate extends BaseEntityRate but doesn’t properly map the entity and user fields, ratings won’t persist.
    • Fix: Ensure BaseEntityRate fields are correctly mapped in your child class:
      #[ORM\ManyToOne(targetEntity: Product::class, inversedBy: "ratings")]
      private ?Product $entity = null;
      
      #[ORM\ManyToOne(targetEntity: User::class)]
      private ?User $user = null;
      
  3. Permission Issues:

    • The bundle assumes the logged-in user is the rater. If using anonymous ratings, override RatingService to handle this:
      public function rateEntity($entity, $user = null, $value, $comment = null)
      {
          $user = $user ?: $this->getAnonymousUser(); // Custom logic
          // ...
      }
      
  4. Performance with Large Datasets:

    • Fetching all ratings for an entity with getRatings() can be slow. Use pagination:
      $ratings = $product->getRatings()->setMaxResults(10)->getQuery()->getResult();
      
  5. Doctrine Proxy Conflicts:

    • If EntityRate is not properly initialized, you may encounter proxy errors.
    • Fix: Ensure your EntityRate class is fully hydrated before use:
      $rating = $entityManager->find(EntityRate::class, $id);
      if (!$rating) {
          throw new \RuntimeException('Rating not found.');
      }
      

Debugging Tips

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

    doctrine:
        dbal:
            logging: true
            profiling: true
    

    Check logs for SQL queries to verify rating persistence.

  2. Check Event Dispatching: Add a debug listener to verify events are fired:

    public function onKernelRequest(GetResponseEvent $event)
    {
        if ($event->isMasterRequest()) {
            $this->container->get('debug.stopwatch')->lap('rating_events');
        }
    }
    
  3. Validate Entity State: Use Symfony’s validator to ensure entities are valid before rating:

    $errors = $validator->validate($product);
    if (count($errors) > 0) {
        throw new \RuntimeException('Entity must be valid to rate.');
    }
    

Extension Points

  1. Custom Rating Values: Override the getAllowedValues() method in RatingService to support non-numeric ratings (e.g., stars, thumbs):

    public function getAllowedValues(): array
    {
        return ['⭐', '⭐⭐', '⭐⭐⭐', '⭐⭐⭐⭐', '⭐⭐⭐⭐⭐'];
    }
    
  2. Multi-Entity Support: Extend the bundle to support rating multiple fields of an entity (e.g., Product has quality and delivery ratings):

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.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle