Let'sTalk Laravel
1
AboutLaravel
» Developer Happiness
» Expressive syntax
» Readability of code
» Rapid application development
» Sane Defaults and Usable Drivers
» Built on Symfony components
2
Community
» Active Slack and IRC communities
» Laracasts
» Twitter
» !
3
Service Containerand Service Providers
4
LaravelService Container
» Manages class dependencies and dependency
injection
» Uses reflection for classes that weren't bound to
container
5
LaravelService Container
Binding
// Simple binding
$this->app->bind('HelpSpotAPI', function ($app) {
return new HelpSpotAPI($app->make('HttpClient'));
});
// Bind a singleton
$this->app->singleton('HelpSpotAPI', function ($app) {
return new HelpSpotAPI($app->make('HttpClient'));
});
6
LaravelService Container
ContextualBinding
// Working with local filesystem
$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('local');
});
// Working with s3
$this->app->when(VideoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('s3');
});
7
LaravelService Container
Resolving from Container
$api = $this->app->make('HelpSpotAPI');
8
LaravelService Container
Automatic Injection
use AppUsersRepository as UserRepository;
class UserController extends Controller
{
/**
* The user repository instance.
*/
protected $users;
/**
* Create a new controller instance.
*
* @param UserRepository $users
* @return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
9
LaravelService Container
Binding InterfacesTo Implementations
$this->app->bind(
'AppContractsEventPusher',
'AppServicesRedisEventPusher'
);
10
LaravelService Container
Binding InterfacesTo Implementations
use AppContractsEventPusher;
/**
* Create a new class instance.
*
* @param EventPusher $pusher
* @return void
*/
public function __construct(EventPusher $pusher)
{
$this->pusher = $pusher;
}
11
Service Providers
» Provide the bootstrapping of the application
» Registration and configuration
» Many are deferred and don't load unless needed
12
Service Providers
Register method
<?php
namespace AppProviders;
use CouchConnection;
use IlluminateSupportServiceProvider;
class CouchServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
$this->app->singleton(Connection::class, function ($app) {
return new Connection(config('couch'));
});
}
}
13
Service Providers
Bootmethod
<?php
namespace AppProviders;
use IlluminateSupportServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
view()->composer('view', function () {
//
});
}
}
14
Facadesand Contracts
15
Facades...
“Laravel facades serve as "static proxies" to
underlying classes in the service container,
providing the benefit of a terse, expressive syntax
while maintaining more testability and flexibility
than traditional static methods.”
16
Facades...
<?php
namespace AppHttpControllers;
use AppHttpControllersController;
use IlluminateSupportFacadesCache;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* @param int $id
* @return Response
*/
public function showProfile($id)
{
$user = Cache::get('user:'.$id);
return view('profile', ['user' => $user]);
}
}
17
Facades...
// in IlluminateSupportFacadesFacade
// ...
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}
18
Contracts
» Set of interfaces that define core services
provided by Laravel
» Base for creating your own service implementations
» Can be swapped dynamically
19
Artisan
20
Artisan
» Command-line interface
» Tons of commands available
» Create your own!
21
Artisan
php artisan tinker
22
Artisan
make
make:auth Scaffold basic login and registration views and routes
make:command Create a new Artisan command
make:controller Create a new controller class
make:event Create a new event class
make:job Create a new job class
make:listener Create a new event listener class
make:mail Create a new email class
make:middleware Create a new middleware class
make:migration Create a new migration file
make:model Create a new Eloquent model class
make:notification Create a new notification class
make:policy Create a new policy class
make:provider Create a new service provider class
make:request Create a new form request class
make:seeder Create a new seeder class
make:test Create a new test class
23
Routing, Controllers, Requests, Responses...
24
Routingand Controllers
Simple Routing
// handle callback
Route::get('/test',function(){
return 'it works!!';
});
// dispatch to controller
Route::get('/users', 'UserController@index');
// pass in parameters...
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
//
});
25
Routingand Controllers
Route ModelBinding
// in routes file
Route::get('users/{user}', 'UserController@show');
// in UserController
public function show(AppUser $user){
// user is instance of eloquent model...
return $user->name;
}
26
Routingand Controllers
Request
<?php
namespace AppHttpControllers;
use IlluminateHttpRequest;
class UserController extends Controller
{
/**
* Store a new user.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->name;
//
}
}
27
Responses
FullHTTPResponse
/* from route or controller */
// string
return 'Hi';
// array
return ['a', 'b', 'c'];
// collection
return User::all();
28
Responses
Response Object
return response('Hello World', 200)
->header('Content-Type', 'text/plain')
->cookie('my_cookie', 'my_value', $minutes);
29
Responses
EasyResponses
// json
return response()->json(['name' => 'Marcus']);
// view
return view('home-page', ['data' => 'here']);
// file in browser
return response()->file('path/to/file');
// file download
return response()->download('path/to/file');
30
Validation
31
Validation
Inthe Controller
/**
* Store a new blog post.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$this->validate($request, [
'title' => 'required|unique:posts|max:255',
'body' => 'required',
]);
// The blog post is valid, store in database...
}
32
Validation
Form RequestValidation
class FightPredictionRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*/
public function rules()
{
return [
'fight' => 'required|exists:fights,uuid',
'fighter' => 'required|exists:fighters,uuid',
];
}
/**
* Get the validation messages.
*/
public function messages()
{
return [
'fight.required' => 'Fight is required...',
'fighter.required' => 'Fighter is required...',
];
}
}
33
Queues,Jobs, Mailables
34
Queues
EasyDispatching ofJobs
// User places an order...
dispatch(new ProcessOrder($user, $order));
35
Queues
Job ClassesandabitofMail...
/**
* Create a new job instance.
*/
public function __construct(User $user, Order $order)
{
$this->user = $user;
$this->order = $order;
}
/**
* Execute the job.
*/
public function handle()
{
// process order...
Mail::to($this->user->email)->send(new OrderProcessed($order));
}
36
Mail
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->from('orders@example.com')
->view('emails.orders.processed');
}
37
Events, Listenersand Broadcasts
38
Events
Dispatching Events
$order = Order::create([
// use request details
]);
event(new OrderPlaced($order));
39
Events
EventClass
namespace AppEvents;
use AppOrder;
use IlluminateQueueSerializesModels;
class OrderPlaced
{
use SerializesModels;
public $order;
/**
* Create a new event instance.
*
* @param Order $order
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
}
40
Events
Listeners
namespace AppListeners;
use AppEventsOrderPlaced;
use IlluminateContractsQueueShouldQueue;
class NotifyUser implements ShouldQueue
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param OrderPlaced $event
* @return void
*/
public function handle(OrderPlaced $event)
{
Mail::to($event->order->email)->send(new OrderPlacedEmail($event->order));
}
}
41
Broadcasts
EventClass
namespace AppEvents;
use AppOrder;
use IlluminateQueueSerializesModels;
class OrderPlaced implements ShouldBroadcast
{
use SerializesModels;
public $order;
/**
* Create a new event instance.
*
* @param Order $order
* @return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
/**
* Get the channels the event should broadcast on.
*
* @return Channel|array
*/
public function broadcastOn()
{
return new PrivateChannel('orders');
}
}
42
Broadcasting
Receivingwith LaravelEcho
Echo.channel('orders')
.listen('OrderPlaced', (e) => {
console.log(e.order.name);
});
43
Database, Migrations Factoriesand Eloquent
44
Database: Migrations
php artisan make:migration create_flight_table --create=flights
# or
php artisan make:model Flight -m
45
Database: Migrations
use IlluminateSupportFacadesSchema;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateDatabaseMigrationsMigration;
class CreateFlightsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('flights', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('airline');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('flights');
}
}
46
Database: Migrations
# run all migrations
php artisan migrate
# rollback and re-run migrations
php artisan migrate:refresh
47
Database: Seeding
<?php
use IlluminateDatabaseSeeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
DB::table('users')->insert([
'name' => str_random(10),
'email' => str_random(10).'@gmail.com',
'password' => bcrypt('secret'),
]);
}
}
48
Database: ModelFactories
$factory->define(AppModelsUser::class, function (FakerGenerator $faker) {
static $password;
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
];
});
49
Database: ModelFactories
public function run()
{
// create 50 users and for each of them create a post
factory(AppUser::class, 50)->create()->each(function ($user) {
$post = factory(AppPost::class)->make();
$user->posts()->save($post);
});
}
50
Eloquent
» Active Record ORM
» (Most) tables have a corresponding Eloquent Model
51
Eloquent
Retrieving
// Collection of Users models...
$users = AppUser::all();
// Single User model...
$user = AppUser::first();
// or
$user = AppUser::find(10);
52
Eloquent
Retrieving
// Find the first user with the first name Doug
$doug = AppUser::where('first_name', 'Doug')->first();
// Get all Dougs
$allDougs = AppUser::where('first_name', 'Doug')->get();
53
Eloquent
Inserting
$user = new User;
$user->first-name = 'Marcus';
$user->save();
// or
User::create(['first_name' => 'Marcus']);
54
Eloquent
Updating
$user = AppUser::find(10);
$user->first_name = 'Marcus';
$user->save();
// or
$user = AppUser::find(10);
$user->update(['first_name' => 'Marcus']);
55
Eloquent- Relationships
Oneto One
class User extends Model
{
/**
* Get the phone record associated with the user.
*/
public function phone()
{
return $this->hasOne('AppPhone');
}
}
class Phone extends Model
{
/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('AppUser');
}
}
// access user's number...
$user->phone()->number;
56
Eloquent- Relationships
Oneto Many
class User extends Model
{
/**
* Get the phone records associated with the user.
*/
public function phones()
{
return $this->hasMany('AppPhone');
}
}
class Phone extends Model
{
/**
* Get the user that owns the phone.
*/
public function user()
{
return $this->belongsTo('AppUser');
}
}
// access user's first number...
$user->phones()->first()->number;
57
Eloquent- Relationships
Saving Related Models
$phone = new Phone;
$phone->number = '555-555-5555';
$user->phones()->save($phone);
58
Eloquent- Relationships
AdditionalTypes
» Many to Many
» Has Many Through
» Polymorphic
» Many to Many Polymorphic
59
Testing
60
Testing
HTTPTests
<?php
use AppUser;
class HomePageTest extends TestCase
{
public function testHomePage()
{
$user = factory(User::class)->create(['first_name' => 'John']);
$this->actingAs($user)
->get('/')
->assertStatus(200)
->assertViewHas('user', $user);
}
}
61
Testing
JSONTests
<?php
class ExampleTest extends TestCase
{
/**
* A basic functional test example.
*
* @return void
*/
public function testBasicExample()
{
$response = $this->json('POST', '/user', ['name' => 'Sally']);
$response
->assertStatus(200)
->assertJson([
'created' => true,
]);
}
}
62
Testing
Database
<?php
use AppUser;
use IlluminateFoundationTestingDatabaseMigrations;
class HomePageTest extends TestCase
{
use DatabaseMigrations;
public function testHomePage()
{
$user = factory(User::class)->create(['first_name' => 'John']);
$this->actingAs($user)
->get('/')
->assertStatus(200)
->assertViewHas('user', $user);
}
}
63
Testing
Mocking Facades
<?php
namespace TestsFeature;
use TestsTestCase;
use IlluminateSupportFacadesCache;
use IlluminateFoundationTestingWithoutMiddleware;
use IlluminateFoundationTestingDatabaseMigrations;
use IlluminateFoundationTestingDatabaseTransactions;
class UserControllerTest extends TestCase
{
public function testGetIndex()
{
Cache::shouldReceive('get')
->once()
->with('key')
->andReturn('value');
$response = $this->get('/users');
// ...
}
}
64
Testing
Faking
Event::fake();
// Do stuff...
Event::assertDispatched(OrderShipped::class, function ($e) use ($order) {
return $e->order->id === $order->id;
});
65
Middleware, AuthenticationandAuthorization, Collections, FileSystems, Notifications...
66
Questions?
67

SDPHP Lightning Talk - Let's Talk Laravel