【问题标题】:Creating a new ServiceProvider / Facade as a package in Laravel 5在 Laravel 5 中创建一个新的 ServiceProvider / Facade 作为一个包
【发布时间】:2015-04-24 02:53:04
【问题描述】:

简介

我以前从未使用过框架(Zend、CakePHP 等),最后决定坐下来学习一个。我从 Laravel 开始,因为代码看起来很漂亮,并且与我尝试安装的其他一些框架不同,“Hello, World!”示例在第一次尝试时有效。

目标

目前,我希望我的应用做一些非常简单的事情:

  1. 用户提交请求格式为:GET /dist/lat,lng

  2. 应用使用远程IP地址和MaxMind来判断$latitude1$longitude1

  3. 此请求路径被解析为$latitude2$longitude2

  4. 使用这两个位置,我们计算它们之间的距离。为此,我使用Rafael Fragoso's WorldDistance PHP class

由于我打算在以后的项目中重复使用这个函数,所以将所有代码都扔到/app 目录中似乎不太合适。该应用程序的两个可重用部分是:

  1. 连接 MaxMind 并返回纬度和经度的服务提供者
  2. 获取地球上两个点并返回距离的服务提供者

如果我正确构建了外观,那么我的 routes.php 文件不会是闭包中的一堆闭包,我可以简单地写:

Route::get('dist/{input}', function($input){
    $input = explode( "," , $input );

    return Distance::getDistance( GeoIP::getLocation(), $input );
});

我尝试过的

初步尝试

对于第一个服务提供商,我找到了Daniel Stainback's Laravel 5 GeoIP service provider。它没有像应有的那样轻松安装(我必须手动将geoip.php 复制到/config 目录,手动更新/config/app.php,然后运行composer updatephp artisan optimize)但是它起作用了:A request到GET /test返回了我所有的信息。

对于第二个服务提供商,我首先尝试模仿 GeoIP 服务提供商的目录结构和文件命名约定。我想如果我有相同的命名约定,自动加载器将能够找到我的类。于是我创建了/vendor/stevendesu/worlddistance/src/Stevendesu/WorldDistance\WorldDistanceServiceProvider.php

<?php namespace Stevendesu\WorldDistance;

use Illuminate\Support\ServiceProvider;

class WorldDistanceServiceProvider extends ServiceProvider {

    protected $defer = false;

    public function register()
    {
        // Register providers.
        $this->app['distance'] = $this->app->share(function($app)
        {
            return new WorldDistance();
        });
    }

    public function provides()
    {
        return ['distance'];
    }

}

然后我将此添加到我的/config/app.php

        'Stevendesu\WorldDistance\WorldDistanceServiceProvider',

此操作失败并出现致命错误:

FatalErrorException in ProviderRepository.php line 150:
Class 'Stevendesu\WorldDistance\WorldDistanceServiceProvider' not found

使用工作台

由于这完全失败了,我认为必须有其他一些文件依赖项:可能没有 composer.json 或没有 README 它放弃了。我不知道。所以我开始研究包的创建。几次谷歌搜索“create package laravel 5”被证明是徒劳的。要么:

  1. 他们使用的是 Laravel 4.2,在这种情况下,建议是“运行 php artisan workbench vendor/package --resources”

或者

  1. 他们使用的是 Laravel 5,在这种情况下 the docs were completely useless

官方 Laravel 5 文档为您提供了大量示例代码,例如:

你需要做的就是告诉 Laravel 给定命名空间的视图所在的位置。例如,如果您的包裹名为“courier”,您可以在服务提供商的引导方法中添加以下内容:

public function boot()
{
    $this->loadViewsFrom(__DIR__.'/path/to/views', 'courier');
}

这假设您有一个服务提供商可以在其中放置引导方法

文档中没有任何内容说明如何创建服务提供者以使其实际由 Laravel 加载。

我还发现 several different resources 所有这些都假设您有一个存储库并且您只想将它​​包含在您的应用程序中,或者假设您有“工作台”。完全从头开始创建一个新包没什么。

PHP Artisan 甚至没有“workbench”命令,/config 中也没有“workbench.php”文件,所以我发现的任何与 workbench 相关的东西都是毫无价值的。我开始对 Workbench 进行一些研究,并在 StackOverflow 上找到了 several different questions

经过很长时间和一些实验,我设法将laravel/workbench 放入了我的composer.json,composer update,composer install,手动构建了一个workbench.php 配置文件,最后使用PHP Artisan Workbench 命令制作了一个新包:

php artisan workbench Stevendesu/WorldDistance --resources

这创建了一个目录:/workbench/stevendesu/world-distance,其中包含许多子目录和一个文件:/workbench/stevendesu/world-distance/src/Stevendesu/WorldDistance/WorldDistanceServiceProvider.php

这个服务提供者类与我之前创建的文件基本相同,只是它位于/workbench 目录而不是/vendor 目录中。我尝试重新加载页面,但仍然出现致命错误:

FatalErrorException in ProviderRepository.php line 150:
Class 'Stevendesu\WorldDistance\WorldDistanceServiceProvider' not found

我也试过php artisan vendor:publish。我真的不知道这个命令是做什么的,并且描述没有帮助,所以也许它会有所帮助?没有。

问题

我如何创建一个新的服务提供者作为一个包,以便在未来的项目中我可以简单地包含这个包并拥有所有相同的功能?或者更确切地说,我做错了什么导致我创建的包不起作用?

【问题讨论】:

    标签: php laravel package composer-php laravel-5


    【解决方案1】:

    在玩了两天之后,我设法找到了解决方案。我曾假设目录结构直接映射到它检查的自动加载器的路径(例如,尝试访问一个类 Stevendesu\WorldDistance\WorldDistanceServiceProvider 会在 vendor/stevendesu/world-distance/WorldDistanceServiceProvider 中查找)...事实并非如此。

    通读 composer 源代码以查看它是如何实际加载文件的,它会构建一个“类映射”——本质上是一个巨大的数组,将类映射到它们各自的文件。这个文件是在你运行composer updatecomposer install 时构建的——只有当composer 知道你的包的细节时它才会正确构建。也就是说 - 如果您的包包含在项目的 composer.json 文件中

    我在我的应用程序之外创建了一个本地 git 存储库,然后将我的包添加到我的应用程序的 composer.json 文件中,然后运行 ​​composer update -- 突然一切正常。

    至于:

    它没有像应有的那样轻松安装

    这里的秘诀是首先将服务提供者添加到/config/app.php 然后,第二个运行php artisan vendor:publish

    【讨论】:

    • 您可以使用composer dumpautoload 来更新classmap。 composer update 做的远不止这些。对于 Laravel,有时也需要运行 php artisan clear-compiled 来清除 Laravel 自己优化的映射元数据。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 2017-08-30
    • 1970-01-01
    • 1970-01-01
    • 2016-06-26
    • 2016-08-07
    相关资源
    最近更新 更多