Skip to content

Service Provider Package Config, Views, Lang Issue #265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
bencorlett opened this issue Feb 6, 2013 · 20 comments
Closed

Service Provider Package Config, Views, Lang Issue #265

bencorlett opened this issue Feb 6, 2013 · 20 comments

Comments

@bencorlett
Copy link
Contributor

Hi,

Consider the following service provider:

<?php namespace Foo\Bar;

class FooBarServiceProvider extends ServiceProvider {

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->package('foo/bar', 'foo/bar');

        $this->app['qux'] = $this->app->share(function($app)
        {
            $dependency = $app['config']['foo/bar::baz.bat'];
            new Corge($dependnecy);
        });
    }

}

This works fine. However, as @taylorotwell has mentioned, all package() commands belong in boot. Let's try this:

<?php namespace Foo\Bar;

class FooBarServiceProvider extends ServiceProvider {

    /**
     * Boot the service provider.
     *
     * @return void
     */
    public function boot()
    {
        $this->package('foo/bar', 'foo/bar');
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->app['qux'] = $this->app->share(function($app)
        {
            $dependency = $app['config']['foo/bar::baz.bat'];
            new Corge($dependnecy);
        });
    }

}

This works fine. Sort of. If you try accessing $app['qux'] anywhere before a request has been dispatched (i.e. in app/routes.php), the config hasn't been loaded because boot() isn't called until a request is dispatched.

Bit of a chicken egg situation. I have run into this issue on a real life scenario where I am trying to override Laravel's router for a specific reason. When you call Route::get() (for example) in app/routes.php you run into the issue where the config hasn't been loaded from boot() yet.

Problem with not putting package() calls in boot() is that you can run into issues when service providers depend on other components from other service providers.

If anybody has a suggestion on how to get around this please let me know, but I feel that there is an underlying problem potentially.

@jasonlewis
Copy link
Contributor

Typically with this sort of thing you can register the configuration separately if you need to. So in the second example in your register() method you could do something like this.

$this->app['config']->package('foo/bar', __DIR__.'/../../config', 'foo/bar');

In this case you must provide the path to the config directory yourself and it's provided as the second parameter.


You shouldn't be able to run $this->package() inside the register() method at all if you have any language files because the translator is a deferred service. Deferred services are set AFTER all the eagerly loaded services have been registered.


On that above point I wonder if @taylorotwell could shed some light as to why the deferred services can't be set before registering the eagerly loaded services. That way you could use $this->package() inside the register() method. Thoughts Taylor?

If you were to move this line above the foreach it should technically work. Unless I'm missing something from the bigger picture here.

@bencorlett
Copy link
Contributor Author

Yep, that's right. Tried all of that lol. Spent all yesterday and today on it. Either way, up shit creek right now.

I will have to just work out a way of not overriding the router logic for my app?!

Sent from my iPhone
Please excuse my brevity

On 06/02/2013, at 6:37 PM, Jason Lewis notifications@github.com wrote:

Typically with this sort of thing you can register the configuration separately if you need to. So in the second example in your register() method you could do something like this.

$this->app['config']->package('foo/bar', DIR.'/../../config', 'foo/bar');
In this case you must provide the path to the config directory yourself and it's provided as the second parameter.

You shouldn't be able to run $this->package() inside the register() method at all if you have any language files because the translator is a deferred service. Deferred services are set AFTER all the eagerly loaded services have been registered.

On that above point I wonder if @taylorotwell could shed some light as to why the deferred services can't be set before registering the eagerly loaded services. That way you could use $this->package() inside the register() method. Thoughts Taylor?


Reply to this email directly or view it on GitHub.

@bencorlett
Copy link
Contributor Author

I'm going to have a play with the core see if I can make and test a fix for it to make it work.

Sent from my iPhone
Please excuse my brevity

On 06/02/2013, at 6:37 PM, Jason Lewis notifications@github.com wrote:

Typically with this sort of thing you can register the configuration separately if you need to. So in the second example in your register() method you could do something like this.

$this->app['config']->package('foo/bar', DIR.'/../../config', 'foo/bar');
In this case you must provide the path to the config directory yourself and it's provided as the second parameter.

You shouldn't be able to run $this->package() inside the register() method at all if you have any language files because the translator is a deferred service. Deferred services are set AFTER all the eagerly loaded services have been registered.

On that above point I wonder if @taylorotwell could shed some light as to why the deferred services can't be set before registering the eagerly loaded services. That way you could use $this->package() inside the register() method. Thoughts Taylor?


Reply to this email directly or view it on GitHub.

@jasonlewis
Copy link
Contributor

All you'd have to do Ben is move the line that sets the deferred services on the container above the line that registers the eager loaded services.

I don't see why you'd need to override the router logic?

@bencorlett
Copy link
Contributor Author

Oh, alternatively I can defer the service provider I am using and override the router. This creates another issue. Because of how PHP handles closures and how Router::createClosureCallback() works, means the old router instance is always referenced which means controller routes don't work. I'd be happy to provide anybody with a dumbed down version of the package I'm talking about as an example as what I'm saying probably isn't making much sence...

Sent from my iPhone
Please excuse my brevity

On 06/02/2013, at 6:37 PM, Jason Lewis notifications@github.com wrote:

Typically with this sort of thing you can register the configuration separately if you need to. So in the second example in your register() method you could do something like this.

$this->app['config']->package('foo/bar', DIR.'/../../config', 'foo/bar');
In this case you must provide the path to the config directory yourself and it's provided as the second parameter.

You shouldn't be able to run $this->package() inside the register() method at all if you have any language files because the translator is a deferred service. Deferred services are set AFTER all the eagerly loaded services have been registered.

On that above point I wonder if @taylorotwell could shed some light as to why the deferred services can't be set before registering the eagerly loaded services. That way you could use $this->package() inside the register() method. Thoughts Taylor?


Reply to this email directly or view it on GitHub.

@andymrussell
Copy link

This is the same issue if using the package from Artisan. The config doesn't get loaded unless you move $this->package() into register(). Which as pointed out is not good.

@jasonlewis
Copy link
Contributor

Taylor has mentioned that all providers are booted when using the CLI. I'm unable to track down where that occurs though.


All service providers are booted. The application is booted in the artisan file. I've tested and config does work from the command line.

bencorlett added a commit to bencorlett/framework that referenced this issue Feb 6, 2013
…er services are registered. Fixes laravel#265.

Signed-off-by: Ben Corlett <bencorlett@me.com>
@andymrussell
Copy link

Under Artisan it doesn't look like the boot() function doesn't get called for Workbench packages. So you have to put the $this->package() in the register() function..

Just incase you ask, the service provider was registered in app.php
Here is an example of a service provider with this issue: http://paste.laravel.com/gP5

@bencorlett
Copy link
Contributor Author

That could be right actually @andymrussell, I haven't tested that.

Looking at the service provider, I'd probably suggest changing 'commond.install' to something a little less generic, you may just find you run into issues with other packages who are doing the same thing :P

@andymrussell
Copy link

Yes, good point on installer name. :-)

@jasonlewis
Copy link
Contributor

I tested from a workbench package and it worked for me.
As long as the service provider is registered it shouldn't matter where the package is.

@andymrussell
Copy link

@jasonlewis Can you confirm you can access config params from inside the package (through Artisan)?

i.e.
$app['config']->get('vendor::filename')

@jasonlewis
Copy link
Contributor

Yeah mate can confirm that it all works through Artisan.

@andrewryno
Copy link
Contributor

I think I'm having the same issue as well, but I don't see anything in here that has helped. All I need to do is be able to access Config/Lang/etc. within my package. I can't seem to get it working at least to the point where I can get it working in tests. I just keep getting an error saying the method doesn't exist (get/has/etc).

I tried in the register() function to register the class passing $app['config'] but that doesn't really help me when I'm trying to use the config items a different class.

So was there ever a good example on how to just access the config items for a package inside that page?

@bencorlett
Copy link
Contributor Author

Can you paste your service provider's contents on http://paste.laravel.com please?

On 14/02/2013, at 8:05 AM, Andrew Ryno notifications@github.com wrote:

I think I'm having the same issue as well, but I don't see anything in here that has helped. All I need to do is be able to access Config/Lang/etc. within my package. I can't seem to get it working at least to the point where I can get it working in tests. I just keep getting an error saying the method doesn't exist (get/has/etc).

I tried in the register() function to register the class passing $app['config'] but that doesn't really help me when I'm trying to use the config items a different class.

So was there ever a good example on how to just access the config items for a package inside that page?


Reply to this email directly or view it on GitHub.

@andrewryno
Copy link
Contributor

http://paste.laravel.com/htS

Changed my names, but it's consistent. My setup is weird, and likely wrong, but it's a difficult use case. I basically need several packages, but they all will share classes, so I'm trying to do this in one package, with several "sub packages".

This is what I'm trying to do:

  • /config/
    • Package1.php
    • Package2.php
  • /Appname/
    • /Appname/
      • AppnameServiceProvider.php
      • Shared1.php
      • Shared2.php
      • /Package1/
        • (More classes)
      • /Package2/
        • (More Classes)
  • /tests/

So within Shared1/Shared2, I want to be able to access the config array for either Package1 or Package2 by using an analog of Config::get('appname::Package1').

@bencorlett
Copy link
Contributor Author

From memory I don't think you can just access a whole file for package config, but I could be totally wrong!

Also, the provides() method is not required if deferred is false. It doesn't ever get called unless deferred is true. That's how deferred services are lazy loaded.

On 14/02/2013, at 8:35 AM, Andrew Ryno notifications@github.com wrote:

http://paste.laravel.com/htS

Changed my names, but it's consistent. My setup is weird, and likely wrong, but it's a difficult use case. I basically need several packages, but they all will share classes, so I'm trying to do this in one package, with several "sub packages".

This is what I'm trying to do:

/config/

Package1.php
Package2.php /Appname/
/Appname/
AppnameServiceProvider.php
Shared1.php
Shared2.php
/Package1/
(More classes)
/Package2/
(More Classes) /tests/
So within Shared1/Shared2, I want to be able to access the config array for either Package1 or Package2 by using an analog of Config::get('appname::Package1').


Reply to this email directly or view it on GitHub.

@andrewryno
Copy link
Contributor

I couldn't even access specific elements inside? I don't need to load the whole array if I can't do that, but I just need a way to read the config. I'm just rather lost while creating this package since the docs are somewhat vague on most things.

@bencorlett
Copy link
Contributor Author

Take a look at https://github.com/jasonlewis/basset - you may be able to get help from it's source :)

On 14/02/2013, at 8:42 AM, Andrew Ryno notifications@github.com wrote:

I couldn't even access specific elements inside? I don't need to load the whole array if I can't do that, but I just need a way to read the config. I'm just rather lost while creating this package since the docs are somewhat vague on most things.


Reply to this email directly or view it on GitHub.

@andrewryno
Copy link
Contributor

I looked at some other packages but didn't seem to help. Basset looks like it's structured how I need it so it should help. Just got some work to do. Thanks! :)

Olofguard pushed a commit to Indatus/laravel-PSRedis that referenced this issue May 7, 2015
Eliminated package configs in order to ditch the boot method all together.

The package configs would not load with the `$this->package()` method in
the boot method of our service provider. With our provider being defered
our config and package are not added to the application instance until
all other core services have been. With sessions particularly, this becomes
an issue, since we can't get the master information to set up our HAClient
via package configs until after the session manager and store are bound
to the application.

For a better understanding of the problem with package config files and service
providers checkout out this [issue on github](laravel/framework#265)
joelharkes pushed a commit to joelharkes/framework_old that referenced this issue Mar 7, 2019
gonzalom pushed a commit to Hydrane/tmp-laravel-framework that referenced this issue Oct 12, 2023
[5.2] Changed $e to $fe in render method.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants