Question

So I've implemented a service structure that a stackoverflow user suggested to me in this post. I've got it mostly working but I'm running into the error:

Class 'App\Services\Mailer\Facades\Mailer' not found

My service folder structure looks like this:

app
|   App
|   |   Services
|   |   |   Mailer
|   |   |   |   Mailer.php
|   |   |   |   MailerFacade.php
|   |   |   |   MailerServiceProvider.php

Each of the files in the Mailer directory are namespaced as:

<?php namespace App\Services\Mailer;

Except for the Facade which is namespaced as the following per the example in this blog:

<?php namespace App\Services\Mailer\Facades; 

I put a test method in my Mailer.php file's Mailer class:

<?php namespace App\Services\Mailer;
//base service class

class Mailer {

  public function sayHi(){
    return "hello!";
  }      
}

I then created the facade:

<?php namespace App\Services\Mailer\Facades; 
// Facade for Mailer

use Illuminate\Support\Facades\Facade;

class Mailer extends Facade {

    protected static function getFacadeAccessor(){ return 'mailer'; }
}

Then I created the Service Provider to hook them all together:

<?php namespace App\Services\Mailer;
// Mailer's service provider

use Illuminate\Support\ServiceProvider;

class MailerServiceProvider extends ServiceProvider {
    public function register(){

        $this->app['mailer'] = $this->app->share( function ($app){
            return new App\Services\Mailer\Mailer;
        });

        $this->app->booting( function (){
            $loader = \Illuminate\Foundation\AliasLoader::getInstance();
            $loader->alias('Mailer', 'App\Services\Mailer\Facades\Mailer');
        });
    }
} 

THe loader for the facade is pointing to the correct namespace, 'App\Services\Mailer\Facades\Mailer', but when I try calling the method in one of my controllers like so:

public function showMe(){
    return Mailer::sayHi();
}

I get the message I noted at the top.

I tried putting the facade into a subfolder of the Mailer directory called Facade so that the namespace and folder structure matched exactly, but I got the same error.

I read and re-read the example, the original stackoverflow post, the composer documentation on psr-4 to make sure I wasn't referencing anything incorrectly, and I can't seem to figure it out.

Can anyone point me in the right direction?

EDIT:

So I took a step back and created a vanilla laravel project and tried to add in a service the same way I'm trying in my main project. It's running into a similar error.

Here's a screen shot of every file involved:

enter image description here

Process:

  • I created my new laravel project
  • I created my App/Services/Greetings directory structure
  • I added my psr-4 load path to my composer.json file
  • I created my underlying class Greetings
  • I Created a GreetingsFacade class that returns the string 'greetings' for the `getFacadeAccessor method
  • I created a Greetings Service Provider class GreetingsServiceProvider and added the register method with it's commands
  • I added my service provider to the app/config/app.php file in the providers array enter image description here
  • I added a route that returns a closure that uses my new Greetings service
  • I then ran composer dump-autoload and loaded my route

When I load my page I get the error "Class 'App\Services\Greetings\App\Services\Greetings\Greetings' not found" :(

Was it helpful?

Solution 2

According to your directory structure:

app
|   App
|   |   Services
|   |   |   Mailer
|   |   |   |   Mailer.php
|   |   |   |   MailerFacade.php
|   |   |   |   MailerServiceProvider.php

Your classes namespaces must be:

Service

<?php namespace App\Services\Mailer; 

class Mailer {}

Service Provider

<?php namespace App\Services\Mailer; 

class MailerServiceProvider {}

Facade

<?php namespace App\Services\Mailer; 

class MailerFacade {}

And you autoloader:

"autoload": {
    "psr-4": {
        "App\\": "app/App"
    },
},

For it to work the way you are trying to do, your directory structure would have to be

app
|   App
|   |   Services
|   |   |   Mailer
|   |   |   ├── Facades
|   |   |   |   └── Facade.php
|   |   |   |   Mailer.php
|   |   |   |   MailerServiceProvider.php

EDIT:

In your Greetings namespace, change from:

return new App\Services\Greetings\Greetings;

to

return new Greetings;

And it should work because they are in the same namespace. For an easy reading of the code, add

use App\Services\Greetings\Greetings;

In the top of your .php file.

OTHER TIPS

psr-4 expects your directory structure to reflect the namespace structure.

In order to autoload a class App\Services\Mailer\Facades\Mailer, it will look for the file App/Services/Mailer/Facades/Mailer.php.

Additionally, the facade accessor mailer (thus also the IoC-Container slug mailer) is already used by Illuminate\Support\Facades\Mail.

Try something different like my_mailer:

<?php namespace App\Services\Mailer\Facades; 
// Facade for Mailer

use Illuminate\Support\Facades\Facade;

class Mailer extends Facade {

    protected static function getFacadeAccessor(){ return 'my_mailer'; }
}

and

<?php namespace App\Services\Mailer;
// Mailer's service provider

use Illuminate\Support\ServiceProvider;
class MailerServiceProvider extends ServiceProvider {
    public function register(){

        $this->app['my_mailer'] = $this->app->share( function ($app){
            return new App\Services\Mailer\Mailer;
        });

        $this->app->booting( function (){
            $loader = \Illuminate\Foundation\AliasLoader::getInstance();
            $loader->alias('Mailer', 'App\Services\Mailer\Facades\Mailer');
        });
    }
} 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top