Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
195 views
in Technique[技术] by (71.8m points)

php - Using a non-laravel package on Laravel 4

Is it possible to include a package that was not specifically designed for L4 in the framework? If so, how is it done? I know I need to add the package to my composer.json which adds it to the vendor folder, but can I register it somehow in the providers array? are there any other steps necessary?

I would like to use the Google checkout package originally designed for Yii

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Using third party composer packages with Laravel 4

When developers create composer packages, they should map the auto-loading using PSR-0 or PSR-4 standards. If this is not the case there can be issues loading the package in your Laravel application. The PSR-0 standard is:

{
    "autoload": {
        "psr-0": { "Acme": "src/" }
    }
}

And the PSR-4 standard:

{
    "autoload": {
         "psr-4": { "Acme": "src/" }
    }
}

Basically the above is a standard for telling composer where to look for name-spaced files. If you are not using your own namespaces you dont have to configure anything else.

SCENARIO 1

PSR-0 standard following packages (with autoload classmap) in Laravel

This is a simple one, and for example i will use the facebook php sdk, that can be found:

https://packagist.org/packages/facebook/php-sdk

Step 1:

Include the package in your composer.json file.

"require": {
    "laravel/framework": "4.0.*",
    "facebook/php-sdk": "dev-master"
}

Step 2:

run: composer update

Step 3:

Because the facebook package uses a class map its working out of the box, you can start using the package instantly. (The code example below comes straight from a normal view. Please keep your logic out from views in your production app.)

$facebook = new Facebook(array(
    'appId'  => 'secret',
    'secret' => 'secret'
));
var_dump($facebook); // It works!

SCENARIO 2

For this example i will use a wrapper from the instagram php api. Here there need to be made some tweaks to get the package loaded. Lets give it a try! The package can be found here:

https://packagist.org/packages/fishmarket/instaphp

Step 1:

Add to composer .json

"require": {
    "laravel/framework": "4.0.*",
    "fishmarket/instaphp": "dev-master"
}

Then you can update normally (composer update)

Next try to use the package like you did with the facebook package. Again, this is just code in a view.

$instagramconfig = array(
    'client_id' => 'secret',
    'client_secret'=> 'secret',
    'access_token' => 'secret'
);

$api = Instaphp::Instance(null, $instagramconfig);                
var_dump($api); // Epic fail!

If you try the above example you will get this error:

FatalErrorException: Error: Class 'Instaphp' not found in ...

So we need to fix this issue. To do this we can examine the instagram composer.json, that has its autoload diffrent than the facebook php sdk had.

"autoload": {
         "psr-0": { "Instaphp": "." }
    }

Compared to the facebook composer.json:

"autoload": {
        "classmap": ["src"]
    }

(Composer handles different kinds of autoloading, from files and class-maps to PSR. Take a look at your vendor/composer/ folder to see how its done.)

Now we will have to load the class, manually. Its easy, just add this (top of your controller, model or view):

use InstaphpInstaphp;

composer dump-autoload, and it works!

step2 (optional)

Another method is (if you dont want to use the "use" statement, you can simply tell composer to look for the files straight from your code. Just change the Instance like so:

// reference the name-spaced class straight in the code
$api = InstaphpInstaphp::Instance(null, $instagramconfig); 
var_dump($api); // It works

However I suggest using the usestatement to make it clear to other developers (and your future self) what (external) classes/packages are used in the program.

SCENARIO 3

Here we use the Laravels built in IOC container to register service providers. Please note that some packages might not be suitable for this method. I will use the same Instagram package as in scenario 2.

Quick and dirty

If you don't care about design patterns and service providers you can bind a class like this:

App::bind('Instaphp', function($app)
{
    return new InstaphpInstaphp;
});

And you resolve it like this.

App::make('Instaphp');

Quick and dirty end

If you're working on a bigger project, and you make use of interfaces you should probably abstract the bindings further.

Step 1:

Create a folder inside your app folder, for example a 'providers' folder.

app/providers

Make sure Laravel auto-loads that folder, you can pass in some additional info to composer.json, like this:

"autoload": {

    "classmap": [
        "app/commands",
        "app/controllers",
        "app/models",
        "app/database/migrations",
        "app/database/seeds",
        "app/tests/TestCase.php",
        "app/providers" // this was added
    ]

},

Now create a File inside the new folder called Instagram.php and place this inside:

 <?php

    use IlluminateSupportServiceProvider;

    class InstagramServiceProvider extends ServiceProvider {

    public function register()
    {
        $this->app->bind('Instaphp', function()
        {
            return new InstaphpInstaphp;
        });

    }

}

Now run composer dump-autoload again, and you can use the package. Note that the instagram package has a final private function __construct(), this means you cannot use that package outside the original class without changing the construct method to public. I'm not saying this is a good practice, and i suggest to use the scenario 2, in the case of the instagram package.

Anyway, after this you can use the package like this:

$instagramInstance = App::make('Instaphp');

$instagramconfig = array(
    'client_id' => 'secret',
    'client_secret'=> 'secret',
    'access_token' => 'secret'
 );

$instagram = new $instagramInstance();
$userfeed = $instagram->Users->feed($instagramconfig);

var_dump($userfeed); // It works!

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...