如果通过另一个包注册,则包的功能不可用

时间:2014-08-03 21:17:37

标签: laravel laravel-4 composer-php php-packages

我有一个基础包,我想用它来管理我的所有包依赖项。在构建这个包时,我的目标是安装并注册所有依赖包。

我已经成功注册了每个软件包的服务提供商(当dd($ app)时,它们显示为已加载;)。

不幸的是,我无法访问任何子包中的任何功能。

我得到的错误如下:

Method <ServiceProviderMethod> does not exist.

以下是主程序包的服务提供者:

use Illuminate\Support\ServiceProvider;

class BonesServiceProvider extends ServiceProvider {
    protected $defer = false;

    public function boot()
    {
        $this->package('genealabs/bones');
    }

    public function register()
    {
        $this->app->register('GeneaLabs\BonesMacros\BonesMacrosServiceProvider');
        $this->app->register('GeneaLabs\BonesFlash\BonesFlashServiceProvider');
    }

    public function provides()
    {
        return array();
    }
}

如果我在app.php配置文件中独立注册两个子包,它们的工作方式与预期一致,所以我认为没有任何错误。我的猜测是我没有通过主程序包暴露某些东西,但我不知道我错过了什么。

有关可能导致此问题的任何想法?

更新 为了进行调试,我在一个新的Laravel应用程序中在工作台中创建了主程序包,以将命名空间“污染”降至最低。我能够安装它,但是现在它在$ this-&gt;注册行中抛出错误,它找不到列出的命名空间,即使这些包是在这些命名空间下开发的。

我更新了主程序包服务提供程序中的register方法,如下所示:

public function register()
{
    $bonesMacroServiceProvider = new BonesMacrosServiceProvider($this->app);
    $bonesFlashServiceProvider = new BonesFlashServiceProvider($this->app);
    $this->app->register($bonesMacroServiceProvider);
    $this->app->register($bonesFlashServiceProvider);
}

但这也没有用,仍然收到相同的错误,它无法找到子包中的方法。

更新2

在寄存器方法中使用instanciation撤消最后一位后,我做了一些调查。现在dd()'$ app变量显示我的包都没有实际注册,事件是我手动包含在app.php中的主包。到目前为止似乎:

  • 主程序包无法注册,因为它在作曲家更新时出错。
  • Composer update抱怨它无法看到依赖包的命名空间来注册它们。
  • 依赖包的命名空间不可用于注册,因为composer尚未安装它们。

这似乎是一个恶毒的捕获22。反正有没有避免这个?我可以检查命名空间,只在命名空间存在时才尝试注册包吗?

更新3

通过修改主程序包服务提供程序中的register()方法,我能够让composer立即成功运行:

public function register()
{
    if (class_exists('GeneaLabs\BonesMacros\BonesMacrosServiceProvider')) {
        $this->app->register('GeneaLabs\BonesMacros\BonesMacrosServiceProvider');
    }
    if (class_exists('GeneaLabs\BonesFlash\BonesFlashServiceProvider')) {
        $this->app->register( 'GeneaLabs\BonesFlash\BonesFlashServiceProvider' );
    }
}

但是,最初的问题仍然是我无法访问子包中的任何功能。

1 个答案:

答案 0 :(得分:0)

这篇文章有几个月了,但我认为这在这里很有用。我是这样做的(laravel 4.2):

在我的服务提供商中:

// for adding package alias
use Illuminate\Foundation\AliasLoader;

public function boot() {

    // ...laravel stuff

    // register the service provider for the child package
    $this->app->register('Vendor\Package\PackageServiceProvider');
}


public function register() {

    // loader for config namespaces
    $loader = $this->app['config']->getLoader();

    // get the config environment name
    $env = $this->app['config']->getEnvironment();

    // add the folder to the package config files to the config loader namespace
    $loader->addNamespace('package',__DIR__.'/../../../../../../app/config/packages/vendor/package');

    // perform the "override" (load config data)
    $configs = $loader->load($env,'config','package');

    // override config data in global config array
    $this->app['config']->set('package::config',$configs);

    // add the alias for the child package
    AliasLoader::getInstance()->alias('Former', 'Depends\On\Package');
}

通过这种方式,您可以保持子包不变,因为您可以覆盖配置文件laravelish样式。

所有内容包括别名,服务提供商和配置文件(可选择覆盖)