EzDevInfo.com

Pimple

A small PHP 5.3 dependency injection container Pimple - A simple PHP Dependency Injection Container pimple - a simple php dependency injection container

Silex service - $app parameter or "use ($app)" statement?

If I define a service in Silex application, I can either expect the main container (Application) to be passed as a parameter or can take it from the current scope using "use ($app)" statement.

The official documentation at http://silex.sensiolabs.org/doc/services.html has this snippet:

$app['some_service'] = function ($app) {
     return new Service($app['some_other_service'], $app['some_service.config']);
};

But it can be equally written as

$app['some_service'] = function () use ($app) {
     return new Service($app['some_other_service'], $app['some_service.config']);
};

and I've seen a lot of examples of such code. Is it just personal taste or one of them has benefits over another, such as in performance, memory usage or code isolation?


Edit: I've run perfromance comparison of "use" vs parameter vs simple function:

$func = function () use ($app) {...};
$func = function ($app) {...};
function test($app) {...}

The first one is the slowest, but overall difference is less than 25%. And as any micro-optimization, it's noticeable only if you have tens of thousands of these as the time difference between the fastest and slowest was about 1/10,000,000th of a second (0.05s for 1 million reps).

So performance difference should not be considered.


Source: (StackOverflow)

Configure boostrap file for PHPUnit in Yii

If I'm using this YiiPimple for dependency injection, then how to configure bootstrap file for phpunit? Below given bootstrap file content:

$yiit=dirname(__FILE__).'/../../../../../yii-assets/framework/yiit.php';
$config=dirname(__FILE__).'/../config/test.php';
require_once($yiit);
require_once(dirname(__FILE__).'/WebTestCase.php');
require_once(dirname(__FILE__).'/../../../components/WebApplication.php');
Yii::createApplication('WebApplication', $config)->run();

But when I run this phpunit following error occurs:

Fatal error: Uncaught exception 'CHttpException' with message 'Unable to resolve
 the request "site".' in D:\xampp\htdocs\yii-assets\framework\web\CWebApplicatio
n.php:286
Stack trace:
#0 D:\xampp\htdocs\yii-assets\framework\web\CWebApplication.php(141): CWebApplic
ation->runController('')
#1 D:\xampp\htdocs\yii-assets\framework\base\CApplication.php(180): CWebApplicat
ion->processRequest()
#2 D:\xampp\htdocs\AdlugeCore\protected\modules\lead\tests\bootstrap.php(11): CA
pplication->run()
#3 D:\xampp\php\pear\PHPUnit\Util\Fileloader.php(92): include_once('D:\xampp\htd
ocs...')
#4 D:\xampp\php\pear\PHPUnit\Util\Fileloader.php(76): PHPUnit_Util_Fileloader::l
oad('D:\xampp\htdocs...')
#5 D:\xampp\php\pear\PHPUnit\TextUI\Command.php(778): PHPUnit_Util_Fileloader::c
heckAndLoad('D:\xampp\htdocs...')
#6 D:\xampp\php\pear\PHPUnit\TextUI\Command.php(606): PHPUnit_TextUI_Command->ha
ndleBootstrap('D:\xampp\htdocs...')
#7 D:\xampp\php\pear\PHPUnit\TextUI\Command.php(138): PHPUnit_TextUI_Command->ha
ndleArguments(Array)
#8 D:\xampp\php\pear\PH in D:\xampp\htdocs\yii-assets\framework\web\CWebApplicat
ion.php on line 286

Source: (StackOverflow)

Advertisements

understanding pimple php source code

Pimple is a simple dependency injection container in php used in silex framework. I was going through the source code here. In the documentation the function offsetGet returns the same instance of the class that is attached to the dependency container. the relevant code for offsetGet is :

public function offsetGet($id)
{
    if (!isset($this->keys[$id])) {
        throw new InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
    }

    if (
        isset($this->raw[$id])
        || !is_object($this->values[$id])
        || isset($this->protected[$this->values[$id]])
        || !method_exists($this->values[$id], '__invoke')
    ) {
        return $this->values[$id];
    }

    if (isset($this->factories[$this->values[$id]])) {
        return $this->values[$id]($this);
    }

    $this->frozen[$id] = true;
    $this->raw[$id] = $this->values[$id];

    return $this->values[$id] = $this->values[$id]($this);
 }

Here, if the object is in the factories Object Store(SplObjectStorage type), it returns a new instance of the class with id $id. then in the last return again $this->values[$id] is set to a new instance of the object and that new instance is returned.

return $this->values[$id] = $this->values[$id]($this).

This is the line I fail to understand. How is this line supposed to return the same instance for different calls of offsetGet for the same $id. Won't it return a new instance every time? Please help me. I tried a lot but I don't get it.


Source: (StackOverflow)

Pimple and dynamic constructor injection

I have a question regarding Pimple and dynamic constructor injection.

Say I have an MVC framework and I want to do something like image uploading. The semi-DI way of doing it would be like this:

class ImageUploadController
{
    public function upload()
    {
         $targetImage = new Image(1920, 1080, 75, 'jpg', 'save/path');
         $imageSaver = new JPEGImageSaver($targetImage);
         $imageUploader = new ImageUploader($imageSaver);
         $imageUploader->upload('myUploadfield');
    }
}

Basically Image is a simple container for the properties of the image I want to create and save. JPEGImageSaver makes use of imagecreatefromjpeg(), imagecopyresized(), and imagejpeg() and the properties of the Image object as well as the properties from the uploaded temp image to save a new safe version of the uploaded image. ImageUploader interfaces with the JPEGImageSaver to safely store the uploaded image.

The problem is I have three tightly coupled classes with the controller, and the way I've attempted to avoid that is by using Pimple, and then passing Pimple into the controller.

class ImageUploadController
{
    public function upload()
    {
         $targetImage = $this->app['Image'];
         $targetImage->setWidth(1920);
         $targetImage->setHeight(1080);
         $targetImage->setQuality(75);
         $targetImage->setExtension('jpg');
         $targetImage->setSavePath('save/path');


         $imageSaver = $this->app['JPEGImageSaver'];
         $imageSaver->setTargetImage($targetImage);

         $imageUploader = $this->app['ImageUploader'];
         $imageUploader->setImageSaver($imageSaver);
         $imageUploader->upload('myUploadField');
    }
}

But as you can see, using Pimple to inject dependencies into my controller has made using them MORE complicated than before. The main issue is that I don't see a way in Pimple to set constructor values for objects during request, thus needing a bunch of setters for the Image object.

Is there a common solution to this problem? I've thought about wrapping Pimple in a resolving container that lets me pass in constructor arguments, but the problem with that is my IDE won't indicate how the various objects should be constructed through intellisensing. I'm also a bit dubious about how much more testable $this->app['something'] has even made my controller.

Do controllers even need to be testable? If so, can I consider the Image object to be a value object?

Any thoughts?


Source: (StackOverflow)

Best practice for sharing 3rd party dependency in Silex application?

I am just starting a new Silex project. I am using the Cartalyst Sentry Authentication package and I wish to inject into my controller Service Controllers. Here is my attempt at using Silex's built in dependency container which extends Pimple. I would just like some feedback on whether I am going about things the right way and what I can improve.

$app['sentry'] = $app->share(function() use ($app) {
    $hasher = new Cartalyst\Sentry\Hashing\NativeHasher;
    $userProvider = new Cartalyst\Sentry\Users\Eloquent\Provider($hasher);
    $groupProvider = new Cartalyst\Sentry\Groups\Eloquent\Provider;
    $throttleProvider = new Cartalyst\Sentry\Throttling\Eloquent\Provider($userProvider);
    $session = new Cartalyst\Sentry\Sessions\NativeSession;
    $cookie = new Cartalyst\Sentry\Cookies\NativeCookie(array());

    $sentry = new Cartalyst\Sentry\Sentry(
        $userProvider,
        $groupProvider,
        $throttleProvider,
        $session,
        $cookie
    );

    Cartalyst\Sentry\Facades\Native\Sentry::setupDatabaseResolver(new PDO(
        $app['db.dsn'], 
        $app['db.options']['user'], 
        $app['db.options']['password']
    ));

    return $sentry;
});

Defining my controller:

// General Service Provder for Controllers
$app->register(new Silex\Provider\ServiceControllerServiceProvider());

$app['user.controller'] = $app->share(function() use ($app) {
    return new MyNS\UserController($app);
});

$app->get('/user', "user.controller:indexAction");

Here is my controller, note that app['sentry'] is available to my controller by injecting it into the constructor.

class UserController
{
    private $app;

    public function __construct(Application $app)
    {
        $this->app = $app;
    }

    public function indexAction()
    {
            // just testing various things here....
        $user = $this->app['sentry']->getUserProvider()->findById(1);
        $sql = "SELECT * FROM genes";
        $gene = $this->app['db']->fetchAssoc($sql);
        $this->app['monolog']->addDebug(print_r($gene,true));
        return new JsonResponse($user);
    }

}

Source: (StackOverflow)

Pass parameters to Pimple->container->factory

So I basically want to do this:

$this->container['Menu_builder'] = $this->container->factory(function ($c) {
    return new Menu_builder($parameter_1, $parameter_2);
});

Where $parameter_1 and $parameter_2 are passed in from the call, like this:

$menu_builder = $this->container['Menu_builder']('account', 'reset_password');

I know the above syntax is incorrect, but I want to pass these strings into the call to $this->container->factory.

Is this possible?

For example, if I wanted to instantiate the Menu_builder from various controller functions with different parameters for each controller function.


Source: (StackOverflow)

PHP Lazy loading with Pimple Dependency Injection Container?

Recently I have started using Pimple (together with Silex). Depending on how Pimple is used it can either be a Service Locator or a Dependency Injection Container. I am aware of the reasons why a Service Locator pattern should be avoided. Nevertheless one thing which seems to be haunting me is the moment when the dependency instance is created.

In case of a Dependency Injection, instances of the required classes are created and passed to the constructor:

class Foo{
    public $depend1;
    public $depend2;

    public function __construct($depend1, $depend2) {
        $this->depend1=$depend1;
        $this->depend2=$depend2;
    }

    public function task1() {
        return $this->depend1->run();
    }

    public function task2() {
        return $this->depend2->run();
    }
}

In case we pass the container itself to the class constructor, the dependency instances do not need to be created until they are needed.

class Foo{
    public $app;

    public function __construct(\Silex\Application $app) {
        $this->app=$app;
    }

    public function task1() {
        return $app['depend1']->run();
    }

    public function task2() {
        return $app['depend2']->run();
    }
}

As a result, even if we are only going to call one of the two methods on the Foo class, in the first example still both dependency instances will be created. This code is a very simple example, but I expect the problem will grow in case of more complex classes with more dependency structures. I do notice some other Dependency Injection Containers use proxy classes, but was not able to find anything for this library. Is there any better alternative to lazy load the dependencies with Pimple?


Source: (StackOverflow)

How to use Pimple C Extension

I have the Pimple C extension installed and in my phpinfo() i can see that the Pimple extension is active.

I also have pimple/pimple in my composer.json and the php package is loaded.

As far as i see they dont collide as i dont get any errors, but how do i know that the extension is in use?

When i have the Pimple C extension installed, do i still need the php Pimple package?
Will the C extension silently override the php class?

Is it common behaviour that php will first check if a class is present in php itself and then fallback to a php implementation?


Source: (StackOverflow)

PHP pimple cross dependency

I have two classes which depending on each other:

class A
{
    public function __construct(B $b)
    {
        $this->b = $b;
    }
}
class B
{
    public function __construct(A $a)
    {
        $this->a = $a;
    }
}

And I need to wrap them through Pimple like this:

$c = new \Pimple();
$c['aService'] = function($c){
    return new A($c['bService']);
}
$c['bService'] = function($c){
    return new B($c['aService']);
}

But unfortunately I get cycling:

Fatal error: Maximum function nesting level of '100' reached, aborting!

Is there any way to reach this cross-dependency without cycling? Or I can use only unidirectional dependencies?


Source: (StackOverflow)

Define dependencies for framework controllers with Pimple

So I have a controller which I have added its dependencies with Pimple like this:

$this->container['Account'] = $this->container->factory(function ($c) {
    return new Account(
        $c['Menu_builder']
    );
});

And when I go to the URL of any action in this controller it just says:

Message: Argument 1 passed to Account::__construct() must be an instance of Menu_builder, none given, called in website/system/core/CodeIgniter.php on line 482 and defined Filename: controllers/Account.php Line Number: 13

To load any class with dependencies I usually say:

$account = $this->container['Account'];

But Im not sure where to put this call in the case of a framework controller.

The controller looks like this:

class Account extends MY_Controller
{
    private $menu_builder;

    public function __construct(Menu_builder $menu_builder){
        $this->menu_builder = $menu_builder;
    }
    // ...
}

QUESTION: What am I doing wrong here? The above works fine for returning any classes except for controllers.


Source: (StackOverflow)

Laravel IoC outside Laravel

I am using this repo as the basis for a new CLI PHP project using Eloquent as the ORM.

When you create the new Eloquent capsule you have the option to setAsGlobal which makes the DB capsule accessible from anywhere in the code.

Does that mean there's a Laravel Container being used? Or is this just affecting the DB object?

I'd been using pimple as a container, but if Laravel already has a container I can bind to via Eloquent, that would be a lot simpler-- I want to bind a log writer, the Eloquent capsule, and probably a settings object to the global container so I can access it from anywhere.


Source: (StackOverflow)

Update used pimple version in Silex application

I'm currently creating an application using silex 1.3.

I want to use the dflydev doctrine orm service provider.

For this service provider pimple >=2.1 is needed - but my silex version comes with pimple 1.x.

I've tried to install a newer version via composer, but this results in an error:

Your requirements could not be resolved to an installable set of packages.

Problem 1 - silex/silex v1.3.0 requires pimple/pimple ~1.0 -> no matching package foun d. - silex/silex v1.3.0 requires pimple/pimple ~1.0 -> no matching package foun d. - silex/silex v1.3.0 requires pimple/pimple ~1.0 -> no matching package foun d. - Installation request for silex/silex v1.3.0 -> satisfiable by silex/silex[ v1.3.0].

So my question is: how Can I update this pimple version?

EDIT: I've just seen that there's an older release of the dflydev-doctrine-orm-service-provider, which uses pimple 1.x, so I guess I have to use this version. Nevertheless, I would be intereseted if an update is (theoretical) possible.


Source: (StackOverflow)

PHPStorm Auto-complete Array Keys (dynamically inserted)

I'm using Pimple dependency injector, and every time I use a dependency from the container, I can't help but to double check the spelling of the key used to get the dependency:

$ioc = new Pimple();

// 1. Define some object
$ioc["some-key"] = $ioc->share(function($c){ /* ... */});

// 2. Use it
$ioc["som... // Open config file and check spelling...

Does PHPStorm have some way of looking up those properties and providing auto-completion? I have considered defining all those keys using something like

define('SOME_KEY', 'some-key');

// ...

$ioc[SOME_KEY] = $ioc->share(/* ... */);

but I wonder if there's a better way.

Edit

Here's some sample code:

// project_root/library/App/Injector/Ioc.php
require_once "Pimple.php";

/** @var array|Pimple $ioc */
$ioc = new Pimple();

$ioc["version"] = "1.0.1650.63";

$ioc["location-service"] = $ioc->share(function ($c) {
     return new Application_Service_Location();
   }
);

It turns out that string auto-completion works fine whether or not I include /** @var array|Pimple $ioc */ before the $ioc declaration in the same file as $ioc is declared. However, since I'm using Zend Framework, I'm usually using $ioc thusly:

// project_root/Application/Bootstrap.php
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap {
   protected function _initInjector() {
     $ioc = null;
     require_once LIBRARY_PATH . "/MFM/Injector/ioc.php";
     Zend_Registry::set("ioc", $ioc);
   }
}

// project_root/Application/Controllers/SomeController.php
class Application_Controller_SomeController extends Zend_Controller_Action {
   public function IndexAction() {
      /** @var Pimple $ioc */
      $ioc = Zend_Registry::get("ioc");

      // No IDE assistance for the string "location-service"
      $service = $ioc["location-service"];
   }
}

Source: (StackOverflow)

Silex Pimple service implementation

Inside my Silex app I need a function which basically does a file_get_contents() my idea was to use something like

$app['funky_service'] = function () {
$content = file_get_contents();
return $content;
}

this is working fine, but how can I pass parameters to this function? I can call it like this

$fs = $app['funky_service'];

but passing arguments to it is still puzzling my


Source: (StackOverflow)

Pimple dependency injection static or object

Pimple help re-use the same object across application, and manage dependecy.

but how to manage Pimple itself?

Should I create a global object? Or make it static class? Or use a function?

I would like to access on Pimple methods from anywhere, controllers, models, plugins, etc...

Thanks!!


Source: (StackOverflow)