Skip to content

Instantly share code, notes, and snippets.

@Gertiozuni
Forked from josephspurrier/AwsController.php
Created September 20, 2018 07:59
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save Gertiozuni/737c1d867fa9080a9546e9883d50f32c to your computer and use it in GitHub Desktop.
Laravel 5.2 Workflow with Service Providers

Laravel 5.2 Workflow with Service Providers and Facades

Primer on the Laravel workflow - using service providers to add your own classes to the Laravel service container so they are easier to use.

  • Let's say we created a class called S3 with a public method called listBuckets()
  • Natively in PHP, you would access the method like this:
$s3 = new S3;
$s3->listBuckets();
  • That is pretty easy, BUT it can get really complicated when you have to start passing in a lot of dependencies to a constructor everytime you want to use a class
  • In a nutshell, a service provider is how you show Laravel how to create an object of your class, which dependencies to pass, and then it will do it for you automatically
  • To register your class with the Laravel service container (App is the service container that is accessible by all classes), you have to create a service provider
  • The service provider has a simple register() method that binds the class
  • In config/app.php, there is a provider array and an alias array
  • The service provider gets added to the providers array
  • The alias gets added to the alias array
  • Aliases are optional and just allow you to use classes statically like this:
AwsHelper::listBuckets();
  • If you leave out the alias, you would have to use the class like this:
$s3 = App::make('awshelper');
$s3->listBuckets();
  • If you choose not to use a service provider, you would have to call the method like this:
$s3 = new S3;
$s3->listBuckets();

Facade Naming Convention

When you use the AwsHelper::listBuckets() in your controller, you must have the name specified in two places:

  • the namespace at the top of the file: use \AwsHelper;
  • the alias array at config/app.php: 'AwsHelper' => App\Library\Aws\AwsHelperFacade::class,

Once you have the pointer to the facade file, you can use the getFacadeAccessor() method to return the name of the binding from the service provider file. You could actually have one service provider file with many different bindings, but you will need a separate facade file for each one of those bindings.

Known Issue with Caching

If you make a change to a service provider, the change won't be applied until you run: php artisan clear-compiled. The command essentially deletes bootstrap/cache/services.php. This is a known issue: laravel/framework#2760 (comment)

<?php
// File Location: projectroot/config/app.php
/**
* Set the service providers and facades so the Laravel service container can use them.
*
* @return array
*/
return [
/// ... other settings removed for simplicity
/*
|--------------------------------------------------------------------------
| Autoloaded Service Providers
|--------------------------------------------------------------------------
|
| The service providers listed here will be automatically loaded on the
| request to your application. Feel free to add your own services to
| this array to grant expanded functionality to your applications.
|
*/
'providers' => [
/// ... other providers removed for simplicity
App\Library\AwsS3\AwsS3ServiceProvider::class,
],
/*
|--------------------------------------------------------------------------
| Class Aliases
|--------------------------------------------------------------------------
|
| This array of class aliases will be registered when this application
| is started. However, feel free to register as many as you wish as
| the aliases are "lazy" loaded so they don't hinder performance.
|
*/
'aliases' => [
/// ... other aliases removed for simplicity
'AwsS3' => App\Library\AwsS3\AwsS3Facade::class,
],
];
<?php
// File Location: projectroot/app/Http/Controllers/AwsController.php
namespace App\Http\Controllers;
use \App;
use \AwsS3;
class AwsController extends Controller
{
/**
* Get a list of all the buckets in S3 and send to the view.
*
* @return array
*/
public function index()
{
// Method 1: Access via facade
// Requires Laravel service provider and facade
$arr = AwsS3::listBuckets();
// Method 2: Access via service container
// Requires Laravel service provider
$s3 = App::make('awss3');
$arr = $s3->listBuckets();
// Method 3: Access via namespace
// Nothing required from Laravel, native PHP functionality
$s3 = new \App\Library\AwsS3\AwsS3;
$arr = $s3->listBuckets();
// Name of the view is index.blade.php and in folder called aws
// The variable, $arr, will be accessible in the view since we called
// it using the compact() function. Make sure to pass arr as a string
// and not as a variable.
return view('aws.index', compact('arr'));
}
}
<?php
// File Location: projectroot/app/Library/AwsS3/AwsS3.php
namespace App\Library\AwsS3;
use \AWS;
class AwsS3
{
/**
* Get a list of all the buckets in S3.
*
* @return array
*/
public function listBuckets() {
/* @var $s3 \Aws\S3\S3Client */
$s3 = AWS::createClient('s3');
// The call above is is calling a class in the AWS SDK to do the work. There is
// another service provider set up for it already: https://github.com/aws/aws-sdk-php-laravel
// The comment above the code (@var) allows IDEs to use type hinting so code completion
// will work even though the variable is created from a facade.
// No error handling is done on the line below for simplicity.
return $s3->listBuckets()->get('Buckets');
}
}
<?php
// File Location: projectroot/app/Library/AwsS3/AwsS3Facade.php
namespace App\Library\AwsS3;
use Illuminate\Support\Facades\Facade;
class AwsS3Facade extends Facade
{
/**
* Get the registered name of the component so it can be used as a facade.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'awss3';
}
}
<?php
// File Location: projectroot/app/Library/AwsS3/AwsS3ServiceProvider.php
namespace App\Library\AwsS3;
use Illuminate\Support\ServiceProvider;
class AwsS3ServiceProvider extends ServiceProvider
{
const VERSION = '1.0.0';
/**
* Indicates the service is only loaded when called to save resources.
*
* @var bool
*/
protected $defer = true;
/**
* Register the class so it can be accessed via App::make() by name: awss3
*
* @return void
*/
public function register()
{
$this->app->singleton('awss3', function () {
return new AwsS3();
});
}
/**
* Provides an array of strings that map to the services in the register() function.
* This function is only called when the provider is deferred so this is the only way
* Laravel knows which services are actually available without calling them.
*
* @return array
*/
public function provides()
{
return ['awss3'];
}
}
// File Location: projectroot/resources/views/aws/index.blade.php
// Template displays eac S3 bucket in the array
@extends('layouts.master')
@section('content')
<h1>S3 Buckets</h1>
@foreach ($arr as $item)
<div>{{ $item['Name'] }}</div>
@endforeach
@endsection
<?php
// File Location: projectroot/app/Http/routes.php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/
// If you navigate to http://localhost:8080/aws, you will see the list of AWS S3 buckets
Route::get('/aws', 'AwsController@index');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment