在Laravel 5中创建一个新的ServiceProvider/Facade作为包

ste*_*esu 4 php package laravel composer-php laravel-5

介绍

我以前从未使用过框架(Zend,CakePHP等),最后决定坐下来学习一个.我从Laravel开始,因为代码看起来很漂亮,不像我试图安装的其他框架,"Hello,World!" 第一次尝试的例子.

目标

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

  1. 用户以下列形式提交请求: GET /dist/lat,lng

  2. 该应用程序使用远程IP地址和MaxMind来确定$latitude1$longitude1

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

  4. 使用这两个位置,我们计算它们之间的距离.要做到这一点,我正在使用Rafael Fragoso的WorldDistance PHP类

由于我计划在以后的项目中重用此函数,因此将所有代码都放入/app目录似乎并不正确.该应用程序的两个可重用部分是:

  1. 连接到MaxMind并返回经度和纬度的服务提供商
  2. 服务提供商,在地球上占两个点并返回距离

如果我正确地构建外观,那么routes.php我可以简单地写一下:而不是我的文件在闭包内是一堆乱码.

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

    return Distance::getDistance( GeoIP::getLocation(), $input );
});
Run Code Online (Sandbox Code Playgroud)

我试过的

初步尝试

对于第一家服务提供商,我找到了Daniel Stainback的Laravel 5 GeoIP服务提供商.它没有安装一样容易,因为它应该有(我不得不手动复制geoip.php/config目录中,更新/config/app.php的手,并运行composer updatephp artisan optimize),但是它的工作:要请求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'];
    }

}
Run Code Online (Sandbox Code Playgroud)

然后我把它添加到我的/config/app.php:

        'Stevendesu\WorldDistance\WorldDistanceServiceProvider',
Run Code Online (Sandbox Code Playgroud)

这失败了一个致命的错误:

FatalErrorException in ProviderRepository.php line 150:
Class 'Stevendesu\WorldDistance\WorldDistanceServiceProvider' not found
Run Code Online (Sandbox Code Playgroud)

使用WorkBench

由于这完全失败,我认为必须有一些其他文件依赖:可能没有composer.json或没有README它放弃.我不知道.所以我开始研究包的创建.几个谷歌搜索"创建包laravel 5"证明没有结果.或者:

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

要么

  1. 他们使用的是Laravel 5,在这种情况下,文档完全没用

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

您需要做的就是告诉Laravel给定命名空间的视图所在的位置.例如,如果您的包名为"courier",则可以将以下内容添加到服务提供者的引导方法中:

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

这假设你有一个服务提供者来引入一个引导方法

文档中没有任何内容说明如何以实际由Laravel加载的方式创建服务提供者.

我还发现了几个 不同的 资源,所有这些都假设你有一个存储库,你只想将它包含在你的应用程序中,或者假设你有"工作台".完全从头开始创建新包没什么.

PHP Artisan甚至没有"workbench"命令,并且没有"workbench.php"文件/config,因此我发现与工作台相关的任何内容都毫无价值.我开始对Workbench进行一些研究,并在StackOverflow上发现了几个 不同的 问题.

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

php artisan workbench Stevendesu/WorldDistance --resources
Run Code Online (Sandbox Code Playgroud)

这创建了一个目录:/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
Run Code Online (Sandbox Code Playgroud)

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

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

ste*_*esu 5

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

通过阅读作曲家源代码来查看它实际上如何加载文件,它构建了一个"类图" - 本质上是一个巨大的数组映射类到各自的文件.当您运行该文件是内置composer updatecomposer install-它会如果作曲家知道你的包的细节只有正确建立.也就是说 - 如果您的包包含在项目的composer.json文件中

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

至于:

它没有像它应该的那样容易安装

这里的秘诀是先将服务提供商添加到/config/app.php 第二次运行php artisan vendor:publish