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

Aop Bundle Laravel Package

demoniacdeath/aop-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation Add the package via Composer:

    composer require demoniacdeath/aop-bundle
    

    Enable the bundle in config/bundles.php:

    return [
        // ...
        DemoniacDeath\JMSAopBundle\JMSAopBundle::class => ['all' => true],
    ];
    
  2. Basic Configuration Configure the bundle in config/packages/jms_aop.yaml (create if missing):

    jms_aop:
        proxy_dir: "%kernel.cache_dir%/aop"
        proxy_namespace: "App\\Proxy"
        debug: "%kernel.debug%"
    
  3. First Use Case: Logging Method Calls Create a simple aspect to log method invocations:

    use JMS\Aop\Aspect;
    use JMS\Aop\Before;
    
    class LoggingAspect
    {
        /**
        * @Before("execution(public * *(..))")
        */
        public function logMethodCall(JoinPoint $joinPoint)
        {
            $method = $joinPoint->getMethod();
            $class = $joinPoint->getClass();
            \Log::info("Calling {$class}::{$method->getName()}");
        }
    }
    

    Register the aspect in services.yaml:

    services:
        App\Aspect\LoggingAspect:
            tags: ['jms.aop.aspect']
    
  4. Verify AOP is Working Inject a service annotated with @Aspect and observe logs when methods are called.


Implementation Patterns

Common Workflows

1. Cross-Cutting Concerns (Logging, Caching, Security)

  • Logging: Use @Before/@After to log method entry/exit.
    /**
     * @Before("execution(* App\Service\*(..))")
     */
    public function logServiceCalls(JoinPoint $joinPoint) { ... }
    
  • Caching: Cache method results with @Around.
    /**
     * @Around("execution(* App\Service\Cacheable*(..))")
     */
    public function cacheResult(JoinPoint $joinPoint) { ... }
    
  • Authorization: Validate permissions with @Before.
    /**
     * @Before("execution(* App\Service\Admin*(..)) && args(user, ..)")
     */
    public function checkAdmin(JoinPoint $joinPoint, User $user) { ... }
    

2. Performance Monitoring

Track method execution time:

/**
 * @Around("execution(* App\Service\*(..))")
 */
public function monitorPerformance(JoinPoint $joinPoint) {
    $start = microtime(true);
    $result = $joinPoint->proceed();
    $duration = microtime(true) - $start;
    \Log::debug("Method {$joinPoint->getMethod()->getName()} took {$duration}s");
    return $result;
}

3. Transaction Management

Wrap database operations in transactions:

/**
 * @Around("execution(* App\Service\Repository*(..))")
 */
public function manageTransaction(JoinPoint $joinPoint) {
    $entityManager = $this->getEntityManager();
    $entityManager->beginTransaction();
    try {
        $result = $joinPoint->proceed();
        $entityManager->commit();
        return $result;
    } catch (\Exception $e) {
        $entityManager->rollback();
        throw $e;
    }
}

4. Integration with Symfony Services

  • Dependency Injection: Inject aspects like any other service.
    services:
        App\Aspect\SecurityAspect:
            arguments: ['@security.token_storage']
            tags: ['jms.aop.aspect']
    
  • Event Dispatching: Trigger Symfony events from aspects.
    $event = new MethodCalledEvent($joinPoint);
    $this->eventDispatcher->dispatch($event, MethodCalledEvent::NAME);
    

5. Pointcut Expressions

Use expressive pointcuts to target methods:

  • By class: @Before("execution(* App\Service\UserService*(..))")
  • By annotation: @Before("@annotatedWith(App\Annotation\Cacheable)")
  • By method name: @Before("execution(* *->get*(..))")
  • Combining: @Before("execution(* App\Service\*(..)) && !execution(* App\Service\ReadOnly*(..))")

Integration Tips

1. Proxy Generation

  • Clear the cache when adding new aspects:
    php bin/console cache:clear
    
  • Customize proxy namespace/class in jms_aop.yaml to avoid conflicts.

2. Testing Aspects

  • Mock JoinPoint in unit tests:
    $joinPoint = $this->createMock(JoinPointInterface::class);
    $joinPoint->method('getMethod')->willReturn(new ReflectionMethod($class, 'methodName'));
    $aspect->yourMethod($joinPoint);
    
  • Use JMS\Aop\Test\AspectTestCase for integration tests.

3. Debugging

  • Enable debug mode in jms_aop.yaml to log proxy generation.
  • Check generated proxies in var/cache/dev/aop/ for issues.

4. Performance

  • Avoid complex logic in aspects (keep them lightweight).
  • Use @Around sparingly, as it can impact performance due to proxy overhead.

Gotchas and Tips

Pitfalls

1. Proxy Generation Issues

  • Symptom: Aspects not applied, methods not intercepted.
  • Cause: Cache not cleared after adding new aspects.
  • Fix: Run php bin/console cache:clear and check proxy_dir in config.

2. Circular Dependencies

  • Symptom: Proxy generation fails with "Class not found" errors.
  • Cause: Aspects referencing each other or services not properly autowired.
  • Fix: Use setter injection or constructor injection carefully. Avoid cyclic dependencies in aspects.

3. Pointcut Misconfiguration

  • Symptom: Aspect not triggered when expected.
  • Cause: Incorrect pointcut expression (e.g., wrong method signature).
  • Fix: Test pointcuts incrementally:
    // Start broad, then narrow down
    @Before("execution(* *(..))") // All methods
    @Before("execution(* App\*(..))") // All App namespace
    @Before("execution(* App\Service\*(..))") // Specific service
    

4. JoinPoint Limitations

  • Symptom: Cannot access expected arguments or method details.
  • Cause: JoinPoint is a proxy and may not expose all expected data.
  • Fix: Use getArgs(), getMethod(), and getThis() carefully. For complex cases, pass dependencies via constructor.

5. Debugging Proxies

  • Symptom: Unclear why an aspect isn’t working.
  • Fix: Dump the generated proxy class:
    $proxyClass = $joinPoint->getProxy();
    var_dump(get_class($proxyClass));
    
  • Check var/cache/dev/aop/ for generated proxy files.

Tips

1. Aspect Naming and Organization

  • Group aspects by concern (e.g., LoggingAspect, CacheAspect, SecurityAspect).
  • Use namespaces to avoid collisions:
    namespace App\Aspect\Logging;
    namespace App\Aspect\Security;
    

2. Reusable Aspects

  • Extract common logic into base aspects:
    abstract class BaseAspect {
        protected function log(JoinPoint $joinPoint, string $message) {
            \Log::info("[AOP] {$message}: {$joinPoint->getMethod()->getName()}");
        }
    }
    

3. Dynamic Pointcuts

  • Use @Around to dynamically decide whether to proceed:
    public function dynamicProceed(JoinPoint $joinPoint) {
        if ($this->shouldSkip($joinPoint)) {
            return null; // Skip execution
        }
        return $joinPoint->proceed();
    }
    

4. Aspect Configuration

  • Externalize aspect behavior via config:
    # config/packages/aop.yaml
    app_aop:
        logging:
            enabled: true
            log_level: debug
    
    // In aspect
    public function __construct(array $config) {
        $this->enabled = $config['enabled'];
    }
    

5. Aspect Testing

  • Test aspects in isolation:
    public function testLoggingAspect() {
        $joinPoint = $this->createMock(JoinPointInterface::class);
        $joinPoint->method('getMethod')->willReturn(new ReflectionMethod('App\Service\UserService', 'getUser'));
    
        $aspect = new LoggingAspect();
        $aspect->logMethodCall($joinPoint);
    
        $this->assertLogContains("Calling App\Service\UserService
    
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.
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
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver