Integration bridge for Go! AOP framework and Symfony
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
CacheWarmer
Command
DependencyInjection
Kernel
Resources
Tests
.gitignore
.scrutinizer.yml
.travis.yml
GoAopBundle.php Add Doctrine entities support, tests, commands, documentation, XSD sc… Jul 18, 2017
README.md
composer.json Fixes #25 Jul 8, 2018
composer.lock
phpunit.xml

README.md

GoAopBundle

Scrutinizer Code Quality Travis branch GitHub release Minimum PHP Version License

The GoAopBundle adds support for Aspect-Oriented Programming via Go! AOP Framework for Symfony2-Symfony4 applications.

Overview

Aspect-Oriented Paradigm allows to extend the standard Object-Oriented Paradigm with special instruments for effective solving of cross-cutting concerns in your application. This code is typically present everywhere in your application (for example, logging, caching, monitoring, etc) and there is no easy way to fix this without AOP.

AOP defines new instruments for developers, they are:

  • Joinpoint - place in your code that can be used for interception, for example, execution of single public method or accessing of single object property.
  • Pointcut is a list of joinpoints defined with a special regexp-like expression for your source code, for example, all public and protected methods in the concrete class or namespace.
  • Advice is an additional callback that will be called before, after or around concrete joinpoint. For PHP each advice is represented as a \Closure instance, wrapped into the interceptor object.
  • Aspect is a special class that combines pointcuts and advices together, each pointcut is defined as an annotation and each advice is a method inside this aspect.

You can read more about AOP in different sources, there are good articles for Java language and they can be applied for PHP too, because it's general paradigm.

Installation

GoAopBundle can be easily installed with composer. Just ask a composer to download the bundle with dependencies by running the command:

$ composer require goaop/goaop-symfony-bundle

Versions 1.x are for Symfony >=2.0,<2.7 Versions 2.x(master) are for Symfony >= 2.7 and 3.x

Then enable the bundle in the kernel:

// app/AppKernel.php

public function registerBundles()
{
    $bundles = array(
        new Go\Symfony\GoAopBundle\GoAopBundle(),
        // ...
    );
}

Make sure that bundle is the first item in this list. This is required for the AOP engine to work correctly.

Configuration

Configuration for bundle is required for additional tuning of AOP kernel and source code whitelistsing/blacklisting.

# app/config/config.yml
go_aop:
    # This setting enables or disables an automatic AOP cache warming in the application.
    # By default, cache_warmer is enabled (true), disable it only if you have serious issues with 
    # cache warming process.
    cache_warmer: true

    # This setting enables or disables workaround for weaving of Doctrine ORM entities. By default,
    # it is disabled. If you are using Doctrine ORM and you are using AOP to weave Doctrine entities,
    # enable this feature. For details about this known issue, see https://github.com/goaop/framework/issues/327
    doctrine_support: false

    # Additional settings for the Go! AOP kernel initialization
    options:
        # Debug mode for the AOP, enable it for debugging and switch off for production mode to have a
        # better runtime performance for your application
        debug: %kernel.debug%
        
        # Application root directory, AOP will be applied ONLY to the files in this directory, by default it's
        # src/ directory of your application.
        app_dir: "%kernel.root_dir%/../src"

        # AOP cache directory where all transformed files will be stored.
        cache_dir: %kernel.cache_dir%/aspect

        # Whitelist is array of directories where AOP should be enabled, leave it empty to process all files
        include_paths: []
        
        # Exclude list is array of directories where AOP should NOT be enabled, leave it empty to process all files
        exclude_paths: []
        
        # AOP container class name can be used for extending AOP engine or services adjustment
        container_class: ~
        
        # List of enabled features for AOP kernel, this allows to enable function interception, support for
        # read-only file systems, etc. Each item should be a name of constant from the `Go\Aop\Features` class.
        features: []
      

XML format is supported for configuration of this bundle as well, for XML format please use provided XML schema file.

Defining new aspects

Aspects are services in the Symfony2 apllications and loaded into the AOP container with the help of compiler pass that collects all services tagged with goaop.aspect tag. Here is an example how to implement a logging aspect that will log information about public method invocations in the src/ directory.

Definition of aspect class with pointuct and logging advice

<?php

namespace App\Aspect;

use Go\Aop\Aspect;
use Go\Aop\Intercept\MethodInvocation;
use Go\Lang\Annotation\Before;
use Psr\Log\LoggerInterface;

/**
 * Application logging aspect
 */
class LoggingAspect implements Aspect
{
    /**
     * @var LoggerInterface
     */
    private $logger;

    public function __construct(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    /**
     * Writes a log info before method execution
     *
     * @param MethodInvocation $invocation
     * @Before("execution(public **->*(*))")
     */
    public function beforeMethod(MethodInvocation $invocation)
    {
        $this->logger->info($invocation, $invocation->getArguments());
    }
}

Registration of aspect in the container:

services:
    logging.aspect:
        class: App\Aspect\LoggingAspect
        arguments: ["@logger"]
        tags:
            - { name: goaop.aspect }

If you're using Symfony 3.3+ with autowired and autoconfigured services, your aspects will be registered automatically.

Known issues and workarounds

  • By default, it is not possible to weave Doctrine ORM entities without additional configuration (see https://github.com/goaop/framework/issues/327). However, this bundle delivers workaround that can be easily enabled in configuration (see section about configuration in text above). Workaround is disabled by default in order to save some performances.
  • It is possible to get into circular reference issue when registering an aspect which has dependency on service that uses weaved class, or depends on service that has weaved class. Currently, detection of such scenario is not implemented, however, there are two workarounds:

License

This bundle is under the MIT license. See the complete license in the bundle:

Resources/meta/LICENSE