Skip to content

ProxyManager Bridge #7890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 39 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
f829b7f
First implementation of lazy services via proxy manager
Ocramius Mar 29, 2013
1874dbf
Adding basic logic to generate proxy instantiation into a php dumped …
Ocramius Mar 30, 2013
37abd21
Compiling proxies into the generated DIC file
Ocramius Mar 30, 2013
7c1c5fd
Upgrading dependency to ProxyManager 0.3.*
Ocramius Mar 30, 2013
d0b4075
Suggesting ProxyManager in composer.json, removing useless calls
Ocramius Mar 31, 2013
d994434
Adding failing test to demonstrate that proxy initialization breaks s…
Ocramius Mar 31, 2013
2c6bf54
Fixing shared service instance
Ocramius Mar 31, 2013
ee0d51f
Sharing services in the container should only happen when proxying fa…
Ocramius Mar 31, 2013
f986dc7
Adding tests for proxy sharing within dumped containers
Ocramius Mar 31, 2013
cc56920
Fixing shared proxies into the container
Ocramius Mar 31, 2013
a6b031e
Bumping required version of ProxyManager
Ocramius Mar 31, 2013
d8acc5e
Docblock for ContainerBuilder#shareService
Ocramius Mar 31, 2013
e5f6bf2
Adding `ContainerBuilder#addClassResource`
Ocramius Mar 31, 2013
fa46c93
Adding test to check that class resources are registered for lazy ser…
Ocramius Apr 1, 2013
b90b359
Fixing tests, registering class resources for lazy services
Ocramius Apr 1, 2013
eb3d703
Reverting import of global namespace classes
Ocramius Apr 2, 2013
e364616
Lazier checks on the proxy structure (avoiding whitespace-based test …
Ocramius Apr 25, 2013
ba3a232
Getters for proxied services are public for 5.3.3 compatibility
Ocramius Apr 25, 2013
2dffad5
Enforcing soft dependency to ProxyManager
Ocramius Apr 25, 2013
2881fcc
Reverting documentation changes, adding exception types description i…
Ocramius Apr 25, 2013
1439e0b
Lazier checks on the proxy structure
Ocramius Apr 27, 2013
95db92a
Adding ProxyManager bridge structure
Ocramius Apr 30, 2013
5a4513c
Adding implementation of the proxy dumper and instantiator
Ocramius Apr 30, 2013
fa2445c
Using the proxy dumper in the php dumper
Ocramius Apr 30, 2013
eba1909
Re-configuring the container builder to get proxy generators injected…
Ocramius Apr 30, 2013
d34bdf4
Passing the proxy dumper to the PhpDumper via ContainerBuilder
Ocramius Apr 30, 2013
7bb0bdd
Adding tests for the runtime proxy instantiator
Ocramius Apr 30, 2013
57c1d76
Adding tests for the ProxyDumper
Ocramius Apr 30, 2013
57b270b
Moving lazy service instantiation features/tests to ProxyManager bridge
Ocramius Apr 30, 2013
eaf3585
Removing useless dependencies
Ocramius Apr 30, 2013
64b452c
CS fixes (EOF EOL)
Ocramius Apr 30, 2013
41237ee
Removing zendframework/zend-code from dev dependencies
Ocramius May 1, 2013
dcfc388
Adding vendor dir to ignored coverage directories
Ocramius May 1, 2013
0e52e96
Applying CS fixes as of @Stof's review
Ocramius May 1, 2013
48f0ac2
Moving proxy dumper instantiation from container builder to kernel
Ocramius May 5, 2013
194b9b5
Removing `@api` annotation
Ocramius May 5, 2013
73f79cc
Removing @api annotations, moving getters to private visibility
Ocramius May 5, 2013
d582131
Removing last `@api` occurrences in Definition
Ocramius May 5, 2013
f4d3e8a
EOL dots in docblock sentences
Ocramius May 5, 2013
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
"doctrine/orm": "~2.2,>=2.2.3",
"monolog/monolog": "~1.3",
"propel/propel1": "1.6.*",
"ircmaxell/password-compat": "1.0.*"
"ircmaxell/password-compat": "1.0.*",
"ocramius/proxy-manager": ">=0.3.1,<0.4-dev"
},
"autoload": {
"psr-0": { "Symfony\\": "src/" },
Expand Down
4 changes: 4 additions & 0 deletions src/Symfony/Bridge/ProxyManager/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
vendor/
composer.lock
phpunit.xml

7 changes: 7 additions & 0 deletions src/Symfony/Bridge/ProxyManager/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CHANGELOG
=========

2.3.0
-----

* First introduction of `Symfony\Bridge\ProxyManager`
19 changes: 19 additions & 0 deletions src/Symfony/Bridge/ProxyManager/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Copyright (c) 2004-2013 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\ProxyManager\LazyProxy\Instantiator;

use ProxyManager\Configuration;
use ProxyManager\Factory\LazyLoadingValueHolderFactory;
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
use ProxyManager\Proxy\LazyLoadingInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;

/**
* Runtime lazy loading proxy generator
*
* @author Marco Pivetta <ocramius@gmail.com>
*/
class RuntimeInstantiator implements InstantiatorInterface
{
/**
* @var \ProxyManager\Factory\LazyLoadingValueHolderFactory
*/
private $factory;

/**
* Constructor
*/
public function __construct()
{
$config = new Configuration();

$config->setGeneratorStrategy(new EvaluatingGeneratorStrategy());

$this->factory = new LazyLoadingValueHolderFactory($config);
}

/**
* {@inheritDoc}
*/
public function instantiateProxy(ContainerInterface $container, Definition $definition, $id, $realInstantiator)
{
return $this->factory->createProxy(
$definition->getClass(),
function (& $wrappedInstance, LazyLoadingInterface $proxy) use ($realInstantiator) {
$proxy->setProxyInitializer(null);

$wrappedInstance = call_user_func($realInstantiator);

return true;
}
);
}
}
116 changes: 116 additions & 0 deletions src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper;

use ProxyManager\Generator\ClassGenerator;
use ProxyManager\GeneratorStrategy\BaseGeneratorStrategy;
use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface;

/**
* Generates dumped php code of proxies via reflection
*
* @author Marco Pivetta <ocramius@gmail.com>
*/
class ProxyDumper implements DumperInterface
{
/**
* @var \ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator
*/
private $proxyGenerator;

/**
* @var \ProxyManager\GeneratorStrategy\BaseGeneratorStrategy
*/
private $classGenerator;

/**
* Constructor
*/
public function __construct()
{
$this->proxyGenerator = new LazyLoadingValueHolderGenerator();
$this->classGenerator = new BaseGeneratorStrategy();
}

/**
* {@inheritDoc}
*/
public function isProxyCandidate(Definition $definition)
{
return $definition->isLazy()
&& ($class = $definition->getClass())
&& class_exists($class);
}

/**
* {@inheritDoc}
*/
public function getProxyFactoryCode(Definition $definition, $id)
{
$instantiation = 'return';

if (ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) {
$instantiation .= " \$this->services['$id'] =";
} elseif (ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
$instantiation .= " \$this->services['$id'] = \$this->scopedServices['$scope']['$id'] =";
}

$methodName = 'get' . Container::camelize($id) . 'Service';
$proxyClass = $this->getProxyClassName($definition);

return <<<EOF
if (\$lazyLoad) {
\$container = \$this;

$instantiation new $proxyClass(
function (& \$wrappedInstance, \ProxyManager\Proxy\LazyLoadingInterface \$proxy) use (\$container) {
\$proxy->setProxyInitializer(null);

\$wrappedInstance = \$container->$methodName(false);

return true;
}
);
}


EOF;
}

/**
* {@inheritDoc}
*/
public function getProxyCode(Definition $definition)
{
$generatedClass = new ClassGenerator($this->getProxyClassName($definition));

$this->proxyGenerator->generate(new \ReflectionClass($definition->getClass()), $generatedClass);

return $this->classGenerator->generate($generatedClass);
}

/**
* Produces the proxy class name for the given definition
*
* @param Definition $definition
*
* @return string
*/
private function getProxyClassName(Definition $definition)
{
return str_replace('\\', '', $definition->getClass()) . '_' . spl_object_hash($definition);
}
}
13 changes: 13 additions & 0 deletions src/Symfony/Bridge/ProxyManager/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
ProxyManager Bridge
===================

Provides integration for [ProxyManager](https://github.com/Ocramius/ProxyManager) with various Symfony2 components.

Resources
---------

You can run the unit tests with the following command:

$ cd path/to/Symfony/Bridge/ProxyManager/
$ composer.phar install --dev
$ phpunit
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\ProxyManager\LazyProxy\Tests;

require_once __DIR__ . '/Fixtures/includes/foo.php';

use ProxyManager\Configuration;
use Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Integration tests for {@see \Symfony\Component\DependencyInjection\ContainerBuilder} combined
* with the ProxyManager bridge
*
* @author Marco Pivetta <ocramius@gmail.com>
*/
class ContainerBuilderTest extends \PHPUnit_Framework_TestCase
{
/**
* @covers Symfony\Component\DependencyInjection\ContainerBuilder::createService
*/
public function testCreateProxyServiceWithRuntimeInstantiator()
{
$builder = new ContainerBuilder();

$builder->setProxyInstantiator(new RuntimeInstantiator());

$builder->register('foo1', 'ProxyManagerBridgeFooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php');
$builder->getDefinition('foo1')->setLazy(true);

/* @var $foo1 \ProxyManager\Proxy\LazyLoadingInterface|\ProxyManager\Proxy\ValueHolderInterface */
$foo1 = $builder->get('foo1');

$this->assertSame($foo1, $builder->get('foo1'), 'The same proxy is retrieved on multiple subsequent calls');
$this->assertInstanceOf('\ProxyManagerBridgeFooClass', $foo1);
$this->assertInstanceOf('\ProxyManager\Proxy\LazyLoadingInterface', $foo1);
$this->assertFalse($foo1->isProxyInitialized());

$foo1->initializeProxy();

$this->assertSame($foo1, $builder->get('foo1'), 'The same proxy is retrieved after initialization');
$this->assertTrue($foo1->isProxyInitialized());
$this->assertInstanceOf('\ProxyManagerBridgeFooClass', $foo1->getWrappedValueHolderValue());
$this->assertNotInstanceOf('\ProxyManager\Proxy\LazyLoadingInterface', $foo1->getWrappedValueHolderValue());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\ProxyManager\LazyProxy\Tests\Dumper;

use ProxyManager\Configuration;
use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;

/**
* Integration tests for {@see \Symfony\Component\DependencyInjection\Dumper\PhpDumper} combined
* with the ProxyManager bridge
*
* @author Marco Pivetta <ocramius@gmail.com>
*/
class PhpDumperTest extends \PHPUnit_Framework_TestCase
{
public function testDumpContainerWithProxyService()
{
$container = new ContainerBuilder();

$container->register('foo', 'stdClass');
$container->getDefinition('foo')->setLazy(true);
$container->compile();

$dumper = new PhpDumper($container);

$dumper->setProxyDumper(new ProxyDumper());

$dumpedString = $dumper->dump();

$this->assertStringMatchesFormatFile(
__DIR__ . '/../Fixtures/php/lazy_service_structure.txt',
$dumpedString,
'->dump() does generate proxy lazy loading logic.'
);
}


/**
* Verifies that the generated container retrieves the same proxy instance on multiple subsequent requests
*/
public function testDumpContainerWithProxyServiceWillShareProxies()
{
require_once __DIR__ . '/../Fixtures/php/lazy_service.php';

$container = new \LazyServiceProjectServiceContainer();

/* @var $proxy \stdClass_c1d194250ee2e2b7d2eab8b8212368a8 */
$proxy = $container->get('foo');

$this->assertInstanceOf('stdClass_c1d194250ee2e2b7d2eab8b8212368a8', $proxy);
$this->assertSame($proxy, $container->get('foo'));

$this->assertFalse($proxy->isProxyInitialized());

$proxy->initializeProxy();

$this->assertTrue($proxy->isProxyInitialized());
$this->assertSame($proxy, $container->get('foo'));
}
}
Loading