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

Calculator Bundle Laravel Package

dk/calculator-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation Run:

    composer require dk/calculator-bundle:dev-master
    

    Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 3-):

    DK\CalculatorBundle\DKCalculatorBundle::class => ['all' => true],
    
  2. Define a Calculated Property Annotate a Doctrine entity property with @DK\CalculatorBundle\Annotation\Calculator:

    use DK\CalculatorBundle\Annotation\Calculator;
    
    /**
     * @Entity
     */
    class User
    {
        /**
         * @var float
         * @Calculator(query="SELECT SUM(t.amount) FROM App\Entity\Transaction t WHERE t.user = user")
         */
        private $balance;
    }
    
  3. First Use Case Fetch a User entity via Doctrine (e.g., UserRepository::find(1)). The balance property will be populated automatically on hydration.


Implementation Patterns

Usage Patterns

  1. Dynamic Calculations Use DQL expressions to compute properties dynamically:

    /**
     * @Calculator(query="SELECT AVG(r.rating) FROM App\Entity\Review r WHERE r.product = product")
     */
    private $averageRating;
    
  2. Conditional Logic Filter calculations with WHERE clauses:

    /**
     * @Calculator(query="SELECT COUNT(t) FROM App\Entity\Transaction t WHERE t.user = user AND t.status = 'completed'")
     */
    private $completedTransactions;
    
  3. Aggregations Support for SUM, AVG, COUNT, etc.:

    /**
     * @Calculator(query="SELECT COUNT(DISTINCT t.category) FROM App\Entity\Transaction t WHERE t.user = user")
     */
    private $transactionCategoriesCount;
    
  4. Joins and Subqueries Complex relationships via joins:

    /**
     * @Calculator(query="SELECT SUM(o.total) FROM App\Entity\Order o JOIN o.items i WHERE i.product = product")
     */
    private $totalSales;
    

Workflows

  • Entity Hydration: Properties are calculated once during entity hydration (lazy-loading not supported).
  • Caching: Use Symfony’s cache system to optimize repeated queries (configure via dk_calculator.cache in config/packages/dk_calculator.yaml).
  • Testing: Mock calculations in unit tests by overriding the Calculator annotation or using a custom CalculatorListener.

Integration Tips

  • Symfony Forms: Bind calculated properties to forms (though they won’t be writable).
  • API Platform: Expose calculated fields in serializers:
    # config/serializer/Entity.User.yaml
    App\Entity\User:
        attributes:
            balance:
                groups: ['api']
    
  • Event Subscribers: Trigger recalculations post-save:
    use DK\CalculatorBundle\Event\CalculatorEvent;
    
    public function onFlush(CalculatorEvent $event) {
        $entity = $event->getEntity();
        if ($entity instanceof User) {
            $event->markDirty('balance'); // Force recalculation
        }
    }
    

Gotchas and Tips

Pitfalls

  1. N+1 Queries

    • Calculated properties trigger additional queries per entity. Mitigate with:
      • DQL JOIN FETCH or batch loading.
      • Caching (see below).
  2. Circular Dependencies

    • Avoid calculations that reference other calculated properties (e.g., balance depending on totalIncome which depends on balance).
  3. Write Operations

    • Calculated properties are read-only. Attempting to set them via Doctrine will throw an exception.
    • Workaround: Use setter methods that trigger recalculations manually.
  4. Database-Specific DQL

    • Some DQL features (e.g., window functions) may not work across databases. Test thoroughly.
  5. Annotation Parsing

    • Ensure annotations are parsed by Symfony’s annotation reader. For Symfony 4+, add this to config/packages/framework.yaml:
      framework:
          annotations:
              cache: true
      

Debugging

  • Query Logging Enable Doctrine debug mode to inspect generated queries:
    // config/packages/dev/doctrine.yaml
    doctrine:
        dbal:
            logging: true
            profiling: true
    
  • Listener Debugging Override the CalculatorListener in tests to log queries:
    $listener = new CalculatorListener($entityManager);
    $listener->setDebug(true); // Hypothetical method
    

Config Quirks

  • Cache Configuration Enable caching in config/packages/dk_calculator.yaml:

    dk_calculator:
        cache: true
        cache_lifetime: 3600 # Cache for 1 hour
    
    • Cache keys are based on entity ID + property name. Clear cache manually if data changes unexpectedly.
  • Performance Tuning

    • Use INDEX hints in DQL for large datasets:
      /**
       * @Calculator(query="SELECT /*+ INDEX(t user_idx) */ SUM(t.amount) FROM App\Entity\Transaction t WHERE t.user = user")
       */
      private $balance;
      

Extension Points

  1. Custom Calculators Extend the bundle by creating a custom Calculator type:

    use DK\CalculatorBundle\Calculator\CalculatorInterface;
    
    class CustomCalculator implements CalculatorInterface {
        public function calculate(EntityManagerInterface $em, object $entity, string $property) {
            // Custom logic
        }
    }
    

    Register via dependency injection.

  2. Event-Driven Recalculations Listen to prePersist, preUpdate, or preRemove to invalidate cache:

    $entityManager->getEventManager()->addEventListener(
        [PrePersist::class, PreUpdate::class],
        function (LifecycleEventArgs $args) {
            $entity = $args->getObject();
            if ($entity instanceof User) {
                $entityManager->getCache()->delete('dk_calculator.User.balance.' . $entity->getId());
            }
        }
    );
    
  3. Bulk Calculations For performance-critical bulk operations, bypass the listener and use raw DQL:

    $query = $em->createQuery('UPDATE App\Entity\User u SET u.balance = (
        SELECT SUM(t.amount) FROM App\Entity\Transaction t WHERE t.user = u
    )');
    $query->execute();
    
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