Closed harikt closed 9 years ago
@harikt just try it
$container['Zend\Expressive\Application'] = new Container\ApplicationFactory;
// ... more code
$app = $container->get('Zend\Expressive\Application');
$app->run();
You'll see that it works :) Pimple and ServiceManager use factories to create services.
That means when invoking $container->get('Zend\Expressive\Application')
the first time the container uses the registered factory and invokes the factory with itself as argument. This way the factory can get further dependencies from the container, create the requested service and return it back to the container. The container caches the service (at least by default) and returns it to the caller of get
. That's it. No need for auto wiring but you need to register a factory for each service.
Thank you for explaining @codeliner .
Seems not a good idea when you are expecting the same object. But it works for people. So ok :-) .
Thanks.
@harikt hehe, no one said that Pimple's interface is clean and understandable ;) But it is widely used. So IMO it is a good idea of zend-expressive to support it.
In zend-servicemanager you explicitly map a service name to a factory: https://github.com/zendframework/zend-expressive/blob/master/doc/book/container/zend-servicemanager.md
That's my preferred IoC container because of the advanced features like abstract factories
and the possibility to configure it with a simple PHP array config.
@harikt It works because of these lines:
When retrieving the value by name, if the value is an object and implements __invoke
(which is also true of Closure
!), then the conditional in the first set of lines fails. This causes the next set of lines to trigger, which invokes the factory. This means that you can define invokable classes as factories, set pimple services to them, and they will be invoked in order to create the service. (This also means that you cannot directly assign invokable objects — such as middleware! — to Pimple unless they can act as factories!)
Thanks.
I have a few config stuffs that help to make use of Aura.Di. Don't know when I can send a PR / get time . In case if someone likes to write. Feel free to take this.
<?php
// PROJECT_PATH/config/Common.php
namespace Application\_Config;
use Aura\Di\Container;
use Aura\Di\ContainerConfig;
class Common extends ContainerConfig
{
public function define(Container $di)
{
$di->params['Aura\Router\RouteCollection'] = array(
'route_factory' => $di->lazyNew('Aura\Router\RouteFactory'),
);
$di->params['Aura\Router\Router'] = array(
'routes' => $di->lazyNew('Aura\Router\RouteCollection'),
'generator' => $di->lazyNew('Aura\Router\Generator'),
);
$di->params['Zend\Expressive\Router\Aura']['router'] = $di->lazyNew('Aura\Router\Router');
$di->set('Zend\Expressive\Router\RouterInterface', $di->lazyNew('Zend\Expressive\Router\Aura'));
$di->set('Zend\Expressive\Container\ApplicationFactory', $di->lazyNew('Zend\Expressive\Container\ApplicationFactory'));
$di->set('Zend\Expressive\Application', $di->lazyGetCall('Zend\Expressive\Container\ApplicationFactory', '__invoke', $di));
// Templating
// In most cases, you can instantiate the template renderer you want to use
// without using a factory:
$di->set('Zend\Expressive\Template\TemplateInterface', $di->lazyNew('Zend\Expressive\Template\Plates'));
// These next two can be added in any environment; they won't be used unless
// you add the WhoopsErrorHandler as the FinalHandler implementation:
$di->set('Zend\Expressive\Container\WhoopsFactory', $di->lazyNew('Zend\Expressive\Container\WhoopsFactory'));
$di->set('Zend\Expressive\Whoops', $di->lazyGetCall('Zend\Expressive\Container\WhoopsFactory', '__invoke', $di));
$di->set('Zend\Expressive\Container\WhoopsPageHandlerFactory', $di->lazyNew('Zend\Expressive\Container\WhoopsPageHandlerFactory'));
$di->set('Zend\Expressive\WhoopsPageHandler', $di->lazyGetCall('Zend\Expressive\Container\WhoopsPageHandlerFactory', '__invoke', $di));
// Error Handling
// If in development:
$di->set('Zend\Expressive\Container\WhoopsErrorHandlerFactory', $di->lazyNew('Zend\Expressive\Container\WhoopsErrorHandlerFactory'));
$di->set('Zend\Expressive\FinalHandler', $di->lazyGetCall('Zend\Expressive\Container\WhoopsErrorHandlerFactory', '__invoke', $di));
// If in production:
// $di->set('Zend\Expressive\FinalHandler', $di->lazyGetCall('Zend\Expressive\Container\TemplatedErrorHandlerFactory', '__invoke', $di));
}
public function modify(Container $di)
{
$router = $di->get('Zend\Expressive\Router\RouterInterface');
$router->addRoute(new \Zend\Expressive\Router\Route('/hello', function ($request, $response, $next) {
$response->write('Trying out');
return $response;
}, \Zend\Expressive\Router\Route::HTTP_METHOD_ANY, 'hello'));
}
}
and
// index.php
<?php
use Aura\Di\ContainerBuilder;
chdir(dirname(__DIR__));
require 'vendor/autoload.php';
$container_builder = new ContainerBuilder();
// use the builder to create and configure a container
// using an array of ContainerConfig classes
$di = $container_builder->newConfiguredInstance([
'Application\_Config\Common',
]);
$app = $di->get('Zend\Expressive\Application');
$app->get('/', function ($request, $response, $next) {
$response->write('Hello, world!');
return $response;
});
$app->run();
@harikt Thanks for the write-up above; I'm going to re-open and mark as "easy fix" so that somebody can take that information and write docs.
One question: in the above, you have calls like this:
$di->set('Zend\Expressive\FinalHandler', $di->lazyNew('Zend\Expressive\Container\WhoopsErrorHandlerFactory'));
Does that actually work? When I was researching adding Aura.Di docs, my understanding is that the above would return an instance of the WhoopsErrorHandlerFactory
, not invoke the factory; based on the fact that you defined Zend\Expressive\Application
to invoke the composed ApplicationFactory
service, I'm thinking that approach would need to be taken for all such factories?
Good catch @weierophinney . You are absolutely correct on the Factories. I missed to check those.
Thanks.
I have created a skelton repo https://github.com/harikt/expressive-aura-skelton if someone love to test quickly :) . I will try to find sometime myself to write.
Fixed with #112
Hi,
I was trying to make use of Aura.Di v3 which satisfies container-interop .
Going through the docs of pimple https://github.com/zendframework/zend-expressive/blob/master/doc/book/container/pimple.md and zend-service manager I guess there is something wrong.
Eg : In Pimple.
See getting the service
Zend\Expressive\Application
it will actually gives you an object ofZend\Expressive\Container\ApplicationFactory
, and inorder to get the object ofZend\Expressive\Application
you need to pass the container itself.Interested to hear whether it was a typo or I am understanding it wrongly.
Thank you.