在 Laravel 4 上使用非 laravel 包

Posted

技术标签:

【中文标题】在 Laravel 4 上使用非 laravel 包【英文标题】:Using a non-laravel package on Laravel 4 【发布时间】:2013-02-17 21:42:25 【问题描述】:

是否可以在框架中包含不是专门为 L4 设计的包? 如果是这样,它是如何完成的?我知道我需要将包添加到我的composer.json 中,这会将它添加到vendor 文件夹中,但是我可以在providers 数组中以某种方式注册它吗?还有其他必要的步骤吗?

我想使用最初为 Yii 设计的Google checkout package

【问题讨论】:

【参考方案1】:

在 Laravel 4 中使用第三方作曲家包

当开发者创建 composer 包时,他们应该使用 PSR-0 或 PSR-4 标准映射自动加载。如果不是这种情况,在你的 Laravel 应用程序中加载包可能会出现问题。 PSR-0 标准是:


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

还有 PSR-4 标准:


    "autoload": 
         "psr-4":  "Acme\\": "src/" 
    

基本上,以上是告诉作曲家在哪里寻找名称空间文件的标准。如果您不使用自己的命名空间,则无需配置任何其他内容。

场景 1

在 Laravel 中遵循 PSR-0 标准的包(带有自动加载类映射)

这是一个简单的,例如我将使用 facebook php sdk,可以找到:

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

第 1 步:

将包包含在您的 composer.json 文件中。

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

第 2 步:

run: composer update

第 3 步:

因为 facebook 包使用了一个开箱即用的类映射,您可以立即开始使用该包。 (下面的代码示例直接来自普通视图。请在生产应用程序的视图中保留您的逻辑。)

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

场景 2

对于这个例子,我将使用来自 instagram php api 的包装器。这里需要进行一些调整才能加载包。试一试吧! 包可以在这里找到:

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

第 1 步:

添加到作曲家.json

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

然后就可以正常更新了(composer update)

接下来尝试像使用 facebook 包一样使用该包。同样,这只是视图中的代码。

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

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

如果你尝试上面的例子,你会得到这个错误:

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

所以我们需要解决这个问题。为此,我们可以检查 instagram composer.json,它的自动加载与 facebook php sdk 不同。

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

与 facebook composer.json 相比:

"autoload": 
        "classmap": ["src"]
    

(Composer 处理不同类型的自动加载,从文件和类映射到 PSR。看看你的 vendor/composer/ 文件夹,看看它是如何完成的。)

现在我们必须手动加载类。很简单,只需添加这个(控制器、模型或视图的顶部):

use Instaphp\Instaphp;

composer dump-autoload,它可以工作了!

第 2 步(可选)

另一种方法是(如果您不想使用“use”语句,您可以简单地告诉作曲家直接从您的代码中查找文件。只需像这样更改实例:

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

但是我建议使用usestatement 让其他开发人员(以及您未来的自己)清楚地了解程序中使用了哪些(外部)类/包。

场景 3

这里我们使用 Laravel 内置的 IOC 容器来注册服务提供者。请注意,某些软件包可能不适合此方法。我将使用与场景 2 中相同的 Instagram 包。

又快又脏

如果您不关心设计模式和服务提供者,您可以像这样绑定一个类:

App::bind('Instaphp', function($app)

    return new Instaphp\Instaphp;
);

然后你就这样解决了。

App::make('Instaphp');

快速而肮脏的结局

如果您正在处理一个更大的项目,并且您使用接口,您可能应该进一步抽象绑定。

第 1 步:

在您的应用文件夹内创建一个文件夹,例如“providers”文件夹。

app/providers

确保 Laravel 自动加载该文件夹,您可以将一些附加信息传递给 composer.json,如下所示:

"autoload": 

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

,

现在在名为 Instagram.php 的新文件夹中创建一个文件并将其放入:

 <?php

    use Illuminate\Support\ServiceProvider;

    class InstagramServiceProvider extends ServiceProvider 

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

    


现在再次运行composer dump-autoload,就可以使用这个包了。请注意,instagram 包有一个final private function __construct(),这意味着您不能在不将构造方法更改为公共的情况下在原始类之外使用该包。我并不是说这是一个好习惯,我建议在使用 instagram 包的情况下使用场景 2。

无论如何,在这之后你可以像这样使用这个包:

$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!

【讨论】:

正是我想要的。谢谢! 这对我来说仍然没有点击。我正在尝试安装 FirePHP 包。将其添加到 composer.json 并运行 composer install 后,文件会显示在 vendor/firephp 中。我已经尝试创建提供程序文件夹并创建一个 FirePHPServiceProvider 文件,但我无法弄清楚正确注册它的热度。我也不明白与 vendor/firephp/firephp-core/lib/FirePHPCore/FirePHP.Class.php 文件的关系。我错过了什么?我应该开始一个新问题吗? 检查您的 composer.lock 文件,文件中的所有内容是否正确加载? firephp 使用 lib 所以路径应该是 "classmap": [ "lib/FirePHPCore/FirePHP.class.php", "lib/FirePHPCore/fb.php" ] 关系就是类所在的位置,通常它们保存在src 或 lib 文件夹。只需尝试安装然后转储实例,以检查 laravel 是否正在加载它。 好的,我让它工作了。在我的注册语句中,我只是简单地输入了 $this->app->bind('FirePHP', function() return new FirePHP; );虽然它正在工作,但我想了解 IoC 容器如何知道“FirePHP”与“lib/FirePHPCore/FirePHP.class.php”和“lib/FirePHPCore/fb.php”相关。它怎么知道我在问什么?我觉得如果我做了类似 $this->app->bind('FirePHP.class.php'... 或者如果我添加了 use "lib/FirePHPCore/FirePHP.class.php" 并使用“lib/FirePHPCore/fb.php”添加到我创建的用于向 IoC 注册的 FirePHP 文件的顶部。 我们能否通过给出步骤#1、#3(稍微多一点)#5 和#7 的示例代码来使答案变得更好?以及对 $this->app->bind 作用的简要说明。我理解#5 和#7。听起来很愚蠢,但我无法使用它。【参考方案2】:

"tvr/googlecheckout": "dev-master" 添加到您的composer.json

运行composer install,就可以使用IoC容器了。一些代码示例可以在 Laravel 4 的官方文档中找到:http://four.laravel.com/docs/ioc#basic-usage

【讨论】:

谢谢。我对 IoC 容器和 DI 进行了一些研究,但我仍然不明白如何加载不遵循 Laravel 服务提供商路线的类/库。如果我只是从我的付款控制器构造函数中调用它,我会收到一个找不到类的错误。我很感激一个例子

以上是关于在 Laravel 4 上使用非 laravel 包的主要内容,如果未能解决你的问题,请参考以下文章

将非框架 PHP 项目移植到 Laravel 4.x

试图在 laravel 5.4 上获取非对象错误的属性

试图在 Laravel 4 中获取非对象的属性

Laravel 在控制器中使用非 Laravel Composer 包

Laravel - 试图在集合上获取非对象的属性

试图在 laravel 5.4 中获取非对象的属性