Skip to content
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

Session refactoring #59

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
65 changes: 61 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,60 @@ class MyConfiguration
}
```

## Session-aware Beans

Disco will not persists session-aware Beans on its own. You can choose freely how to accomplish that task.
Disco provides by default a bean store instance `\bitExpert\Disco\Store\SerializableBeanStore` which will
contain all created session-aware bean instances. The store can be serialized and unserialized. In case
you want to provide your own logic e.g. persisting session-aware Beans in Redis you can implement a custom
variant by implementing the `\bitExpert\Disco\Store\BeanStore` interface.

To be able to serialize Session-aware Beans create an `\bitExpert\Disco\BeanFactoryConfiguration` instance first
and pass it to the `\bitExpert\Disco\AnnotationBeanFactory`:

```php
$config = new \bitExpert\Disco\BeanFactoryConfiguration('/tmp/');
$beanFactory = new AnnotationBeanFactory(Config::class, [], $config);
BeanFactoryRegistry::register($beanFactory);
```

Grab the session bean store instance from the `\bitExpert\Disco\BeanFactoryConfiguration` and serialize it
and store the result:
```php
$sessionBeans = serialize($config->getSessionBeanStore());
```

Unserialization needs to be executed before the `\bitExpert\Disco\AnnotationBeanFactory` gets created:

```php
$sessionBeans = unserialize($sessionBeans);
$config = new \bitExpert\Disco\BeanFactoryConfiguration('/tmp/');
$config->setSessionBeanStore($sessionBeans);

$beanFactory = new AnnotationBeanFactory(Config::class, [], $config);
BeanFactoryRegistry::register($beanFactory);
```

In case your session beans make use of dependencies managed by Disco lazy proxy instances will be used.
That means you need to define a custom proxy autoloader to be able to load the classes before
unserializing the `\bitExpert\Disco\Store\SerializableBeanStore` instance otherwise PHP is not able to
find the class and will return an error.

```php
$config = new \bitExpert\Disco\BeanFactoryConfiguration('/tmp/');
$config->setProxyAutoloader(
new \ProxyManager\Autoloader\Autoloader(
new \ProxyManager\FileLocator\FileLocator('/tmp/'),
new \ProxyManager\Inflector\ClassNameInflector('Disco')
)
);
$beanFactory = new \bitExpert\Disco\AnnotationBeanFactory(Config::class, [], $config);
BeanFactoryRegistry::register($beanFactory);

$sessionBeans = unserialize($sessionBeans);
$config->setBeanStore($sessionBeans);
```

## Performance Tuning

Since a lot of parsing and reflection logic is involved during the conversion process of the configuration code
Expand All @@ -242,11 +296,14 @@ implementation pass an instance of it to `\bitExpert\Disco\BeanFactoryConfigurat

[ProxyManager](https://github.com/Ocramius/ProxyManager) also needs to be configured for faster performance. Read about the details [here](https://ocramius.github.io/ProxyManager/docs/tuning-for-production.html).

For production mode you need to configure the `\ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy`
by passing an instance of it as second parameter to `\bitExpert\Disco\BeanFactoryConfiguration::construct()`.
For production mode you need to enable the custom autoloader by setting an instance of `\ProxyManager\Autoloader\Autoloader`
via `\bitExpert\Disco\BeanFactoryConfiguration::setProxyAutoloader()`. This will significantly increase the overall
performance of Disco.

In addition to that enable the custom autoloader by passing an instance of `\ProxyManager\Autoloader\Autoloader` as fourth parameter of `\bitExpert\Disco\BeanFactoryConfiguration::construct()`. This will significantly increase
the overall performance of Disco.
By default Disco is configured to use the `\ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy` which will dump
the generated config classes as well as the lazy proxy classes on disk. When no proxy autoloader is defined the classes
get overwritten for every request which can be rather slow. Thus you might also want to use a proxy autoloader in your
development environment.

When enabling the caching methods, make sure you regularly clean your cache storage directory after
changing your configuration code!
Expand Down
30 changes: 13 additions & 17 deletions Upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,16 @@ and we do no longer need to "guess" which type might be the correct one.
## BC BREAK: BeanFactoryConfiguration

The `\bitExpert\Disco\BeanFactoryConfiguration::__construct()` method
changed. The 4th parameter is no longer a bool but an instance of
`\ProxyManager\Autoloader\AutoloaderInterface`

To make your life easier make use of the factory method
`\bitExpert\Disco\BeanFactoryConfiguration::getDefault()` to quickly
set up a configuration instance.

## BC BREAK: EvalStrategy (ProxyManager)

When not using the BeanFactoryConfiguration to configure the BeanFactory
internals, ProxyManager in version 2.x will make use of the
`\ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy` instead of
`\ProxyManager\GeneratorStrategy\FileWriterGeneratorStrategy`. Depending
on the complexitity of your configuration class and depending on how many
traits you might use this can lead to a poor performance.

Follow the advice in the README.md file on performance tuning.
signature changed. The constructor accepts just one parameter which
defines the directory where the proxy classes and the annotation metadata
are stored. To configure a proxy autoloader instance or a proxy genrator
instance use the respective setter methods of the object.

## BC BREAK: Serialization of AnnotationBeanFactory

To make use of the session-aware beans it is no longer possible to serialize
the `\bitExpert\Disco\AnnotationBeanFactory` instance. Instead grab the
`\bitExpert\Disco\Store\BeanStore` instance by calling
`\bitExpert\Disco\BeanFactoryConfiguration::getSessionBeanStore()` and serialize
it. Pass the unserialized object to the `\bitExpert\Disco\BeanFactoryConfiguration`
before creating the `\bitExpert\Disco\AnnotationBeanFactory` instance.
3 changes: 1 addition & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
"phpdocumentor/phpdocumentor": "v2.9.0",
"monolog/monolog": "^1.21.0",
"phing/phing": "^2.14.0",
"bitexpert/phing-securitychecker": "^0.2.1",
"mikey179/vfsStream": "^1.6"
"bitexpert/phing-securitychecker": "^0.2.1"
},
"autoload": {
"psr-4": {
Expand Down
84 changes: 19 additions & 65 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 11 additions & 28 deletions src/bitExpert/Disco/AnnotationBeanFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,10 @@
*/
class AnnotationBeanFactory implements BeanFactory
{
/**
* @var string
*/
protected $configClassName;
/**
* @var string[]
*/
protected $parameters;
/**
* @var AliasContainerInterface
*/
protected $beanStore;
protected $beanConfig;

/**
* Creates a new {@link \bitExpert\Disco\BeanFactory}.
Expand All @@ -44,11 +36,12 @@ class AnnotationBeanFactory implements BeanFactory
*/
public function __construct($configClassName, array $parameters = [], BeanFactoryConfiguration $config = null)
{
$this->configClassName = $configClassName;
$this->parameters = $parameters;
if ($config === null) {
$config = new BeanFactoryConfiguration(sys_get_temp_dir());
}

$configFactory = new ConfigurationFactory($config);
$this->beanStore = $configFactory->createInstance($configClassName, $parameters);
$this->beanConfig = $configFactory->createInstance($config, $configClassName, $parameters);
}

/**
Expand All @@ -61,12 +54,10 @@ public function get($id)
$instance = null;

try {
if (is_callable([$this->beanStore, $id])) {
$instance = $this->beanStore->$id();
}

if ($this->beanStore->hasAlias($id)) {
$instance = $this->beanStore->getAlias($id);
if (is_callable([$this->beanConfig, $id])) {
$instance = $this->beanConfig->$id();
} elseif ($this->beanConfig->hasAlias($id)) {
$instance = $this->beanConfig->getAlias($id);
}
} catch (\Throwable $e) {
$message = sprintf(
Expand All @@ -75,7 +66,7 @@ public function get($id)
$e->getMessage()
);

throw new BeanException($message, 0, $e);
throw new BeanException($message, $e->getCode(), $e);
}

if (null === $instance) {
Expand All @@ -90,14 +81,6 @@ public function get($id)
*/
public function has($id)
{
return is_callable([$this->beanStore, $id]) || $this->beanStore->hasAlias($id);
}

/**
* {@inheritDoc}
*/
public function __sleep()
{
return ['configClassName', 'parameters', 'beanStore'];
return is_callable([$this->beanConfig, $id]) || $this->beanConfig->hasAlias($id);
}
}
Loading