Laravelを知る
概要系
ローカル開発環境
面倒くさそうなのでValetいれていく
valet link
-> valet open
valet unlink
uninstall
こっち?
教材
若干古そうだがこれ 2019 April
Laravel5.2あたりの言及が多いのでベースが古いっぽいものの基礎のお勉強なので大丈夫そう
たまに動かないコードがあったりはする
(追記)読み終わったものの良書だったと思う。6系の言及もあったりで、一応publishの時期で更新はされていそう。最新の話題は勿論ないものの、基礎を学ぶには十分だった
後で調べたい
- signedRoute
- Custom Route Model Binding
- view composer
- when/unless(eloquent)
Breezeは後々参考にできそうな初期セットが生成されていそう
Route/Controller
__invokeで単発function
// \App\Http\Controllers\UpdateUserAvatar.php
public function __invoke(User $user)
{
// Update the user's avatar image
}
productionでは php artisan route:cache
をするべし?
abort
Route::post('something-you-cant-do', function (Illuminate\Http\Request $request) {
abort(403, 'You cannot do that!');
abort_unless($request->has('magicToken'), 403);
abort_if($request->user()->isBanned, 403);
});
Commands
php artisan route:list
route一覧
php artisan make:controller XXXXController --api
CRUDのController雛形
php artisan make:controller XXXXController --resource
CRUDとviewの雛形
php artisan migrate
migrate
php artisan migrate:xx --seed
with any command with seeds
php artisan db:seed --class=VotesTableSeeder
add seeds and can run independently
migrate:reset
rollback every database migration
migrate:refresh
rollback every database migration and then run migrate
migrate:fresh
Drop all tabels and run migrate
migrate:status
Shows a table listing every migration
結構ここにまとまっている
Blade Template
echoのwrapが {{ }}
@がディレクティブ
if
@if (count($talks) === 1)
There is one talk at this time period.
@elseif (count($talks) === 0)
There are no talks at this time period.
@else
There are {{ count($talks) }} talks at this time period.
@endif
unless/endunless
@unless ($user->hasPaid())
You can complete your payment by switching to the payment tab.
@endunless
loop/@for
@for ($i = 0; $i < $talk->slotsCount(); $i++)
The number is {{ $i }}<br>
@endfor
loop/@foreach/@endforeach
@foreach ($talks as $talk)
• {{ $talk->title }} ({{ $talk->length }} minutes)<br>
@endforeach
loop/@while
@while ($item = array_pop($items))
{{ $item->orSomething() }}<br>
@endwhile
loop/@forelse
@forelse ($talks as $talk)
• {{ $talk->title }} ({{ $talk->length }} minutes)<br>
@empty
No talks this day.
@endforelse
Layouts/Partials
<!-- resources/views/layouts/master.blade.php -->
<html>
<head>
<title>My Site | @yield('title', 'Home Page')</title>
</head>
<body>
<div class="container">
@yield('content')
</div>
@section('footerScripts')
<script src="app.js"></script>
@show
</body>
</html>
<!-- resources/views/sign-up-button.blade.php -->
<a class="button button--callout" data-page-name="{{ $pageName }}">
<i class="exclamation-icon"></i> {{ $text }}
</a>
<!-- resources/views/dashboard.blade.php -->
@extends('layouts.master')
@section('title', 'Dashboard')
@section('content')
Welcome to your application dashboard!
@include('sign-up-button', ['text' => 'See just how great it is'])
@endsection
@section('footerScripts')
@parent
<script src="dashboard.js"></script>
@endsection
conditionally include
{{-- Include a view if it exists --}}
@includeIf('sidebars.admin', ['some' => 'data'])
{{-- Include a view if a passed variable is truth-y --}}
@includeWhen($user->isAdmin(), 'sidebars.admin', ['some' => 'data'])
{{-- Include the first view that exists from a given array of views --}}
@includeFirst(['customs.header', 'header'], ['some' => 'data'])
@each
<!-- resources/views/sidebar.blade.php -->
<div class="sidebar">
@each('partials.module', $modules, 'module', 'partials.empty-module')
</div>
<!-- resources/views/partials/module.blade.php -->
<div class="sidebar-module">
<h1>{{ $module->title }}</h1>
</div>
<!-- resources/views/partials/empty-module.blade.php -->
<div class="sidebar-module">
No modules :(
</div>
@stack/@push/@prepend
<!-- resources/views/layouts/app.blade.php -->
<html>
<head><!-- the head --></head>
<body>
<!-- the rest of the page -->
<script src="/css/global.css"></script>
<!-- the placeholder where stack content will be placed -->
@stack('scripts')
</body>
</html>
<!-- resources/views/jobs.blade.php -->
@extends('layouts.app')
@push('scripts')
<!-- push something to the bottom of the stack -->
<script src="/css/jobs.css"></script>
@endpush
<!-- resources/views/jobs/apply.blade.php -->
@extends('jobs')
@prepend('scripts')
<!-- push something to the top of the stack -->
<script src="/css/jobs--apply.css"></script>
@endprepend
$slot / @component / @slot
<!-- resources/views/partials/modal.blade.php -->
<div class="modal">
<div class="modal-header">{{ $title }}</div>
<div>{{ $slot }}</div>
<div class="close button etc">...</div>
</div>
<!-- in another template -->
@component('partials.modal')
@slot('title')
Password validation failure
@endslot
<p>The password you have provided is not valid.
Here are the rules for valid passwords: [...]</p>
<p><a href="#">...</a></p>
@endcomponent
Custom Blade Directive
// Binding
Blade::directive('newlinesToBr', function ($expression) {
return "<?php echo nl2br({$expression}); ?>";
});
// In use
<p>@newlinesToBr($message->body)</p>
Databases and Eloquent ( Migration / Seed / Factory )
create migration
artisan make:migration xxxx
artisan make:migration add_xxxx --table=xxxs
artisan make:migration create_xxxx --create=xxxs
Column Types
Index
// After columns are created...
$table->primary('primary_id'); // Primary key; unnecessary if used increments()
$table->primary(['first_name', 'last_name']); // Composite keys
$table->unique('email'); // Unique index
$table->unique('email', 'optional_custom_index_name'); // Unique index
$table->index('amount'); // Basic index
$table->index('amount', 'optional_custom_index_name'); // Basic index
Foreign Key
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
create seed
php artisan make:seeder ContactsTableSeeder
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
class ContactsTableSeeder extends Seeder
{
public function run()
{
DB::table('contacts')->insert([
'name' => 'Lupita Smith',
'email' => 'lupita@gmail.com',
]);
}
}
factory
php artisan make:factory ContactFactory
$factory->define(Contact::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
];
});
// Create one
$contact = factory(Contact::class)->create();
// Create many
factory(Contact::class, 20)->create();
in use
$post = factory(Post::class)->create([
'title' => 'My greatest post ever',
]);
factory(User::class, 20)->create()->each(function ($u) use ($post) {
$post->comments()->save(factory(Comment::class)->make([
'user_id' => $u->id,
]));
});
$factory->define(Contact::class, function (Faker\Generator $faker) {
return [
'name' => 'Lupita Smith',
'email' => 'lupita@gmail.com',
'company_id' => function () {
return factory(App\Company::class)->create()->id;
},
'company_size' => function ($contact) {
// Uses the "company_id" property generated above
return App\Company::find($contact['company_id'])->size;
},
];
});
multiple factory states
$factory->define(Contact::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'email' => $faker->email,
];
});
$factory->state(Contact::class, 'vip', [
'vip' => true,
]);
$factory->state(Contact::class, 'vip', function (Faker\Generator $faker) {
return [
'vip' => true,
'company' => $faker->company,
];
});
in use
$vip = factory(Contact::class)->state('vip')->create();
$vips = factory(Contact::class, 3)->state('vip')->create();
Databases and Eloquent ( Query Builder )
basics
// Basic statement
DB::statement('drop table users');
// Raw and parameter binding
DB::select(
'select * from users where type = ?',
[$type]
);
DB::select(
'select * from users where type = :type',
['type' => $userType]
);
DB::insert(
'insert into contacts (name, email) values (?, ?)',
['sally', 'sally@me.com']
);
DB::update(
'update contacts set status = ? where id = ?',
['donor', $id]
);
DB::delete(
'delete from contacts where archived = ?',
[true]
);
// Select using the fluent builder
$users = DB::table('users')->get();
// Joins and other complex calls
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.type', 'donor');
})
->get();
more complex
// where where
DB::table('contacts')
->where('vip', true)
->where('created_at', '>', now()->subDay());
// orWhere
DB::table('contacts')
->where('vip', true)
->orWhere(function ($query) {
$query->where('created_at', '>', now()->subDay())
->where('trial', false);
})
->get();
// whereBetween
DB::table('drinks')
->whereBetween('size', [6, 12])
->get();
// whereIn
DB::table('contacts')
->whereIn('state', ['FL', 'GA', 'AL'])
->get();
// whereNull / whereNotNull
DB::table('contacts')
-> whereNull('nullable')
-> get();
DB::table('contacts')
-> whereNotNull('nullable')
-> get();
// whereRaw, *beware of sql injection, queries passed to whereRaw will not be escaped
DB::table('contacts')->whereRaw('id = 12345')->get()
// whereExists
DB::table('users')
->whereExists(function ($query) {
$query->select('id')
->from('comments')
->whereRaw('comments.user_id = users.id');
})
->get();
// distinct
DB::table('contacts')->select('city')->distinct()->get();
modifying methods
// orderBy
DB::table('contacts')
->orderBy('last_name', 'asc')
->get();
// groupBy
DB::table('contacts')
->groupBy('city')
->havingRaw('count(contact_id) > 30')
->get();
// skip / take
DB::table('contacts')->skip(30)->take(10)->get();
// latest(colName = 'created_at') / oldest (colName = 'created_at')
DB::table('contacts')->latest()>get(); // order by descending created_at
DB::table('contacts')->oldest()>get(); // order by ascending created_at
// inRandomOrder
DB::table('contacts')->inRandomOrder()>get();
returning methods
xxx->get(); // all results
xxx->first(); // first result (LIMIT 1 added), first will fail if result is empty
xxx->firstOrFail() // throw exception if result is empty
xxx->find(5) // automatically get by ID. also can use findOrFail()
xxx->value('email') // get value from a single fields from the first row
xxx->count() // count of all of the matching results
xxx->min('col') // return min value of col
xxx->max('col') // return max value of col
xxx->dd() // dump the underlying SQL query
transaction
DB::transaction(function () use ($userId, $numVotes) {
// Possibly failing DB query
DB::table('users')
->where('id', $userId)
->update(['votes' => $numVotes]);
// Caching query that we don't want to run if the above query fails
DB::table('votes')
->where('user_id', $userId)
->delete();
});
manual transaction
DB::beginTransaction();
if ($badThingsHappened) {
DB::rollBack();
}
DB::commit();
Databases and Eloquent ( Eloquent )
the simplest model definition
php artisan make:model Contact
with migration php artisan make:model Contact --migration
(-m)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Contact extends Model
{
use HasFactory;
}
customization
// The default behavior is like `SecondaryContact` should be `secondary_contacts`
protected $table = 'contacts_secondary';
// primary key, default is `id`
protected $primaryKey = 'contact_id';
// if need to disable autoincrement
public $incrementing = false;
// if don't need to add `careted_at` and `updated_at`
public $timestamps = false;
// date format customization ( default is probablly Datetime: Y-m-d H:i:s)
protected $dateFormat = 'U'; // Unix Timestamp
Handling Data with Eloquent
$allContacts = Contact::all();
$vipContacts = Contact::where('vip', true)->get();
$newestContacts = Contact::orderBy('created_at', 'desc') // or latest?
->take(10)
->get();
Contact::findOrFail($contactId)
chunk responses ( for memory usage or locking issue )
Contact::chunk(100, function ($contacts) {
foreach ($contacts as $contact) {
// Do something with $contact
}
});
aggregates
$countVips = Contact::where('vip', true)->count();
$sumVotes = Contact::sum('votes');
$averageSkill = User::avg('skill_level');
insert
$contact = new Contact;
$contact->name = 'Ken Hirata';
$contact->email = 'ken@hirata.com';
$contact->save();
// or
$contact = Contact::make([
'name' => 'Ken Hirata',
'email' => 'ken@hirata.com',
]);
$contact->save();
// or (immidiately save to database)
$contact = Contact::make([
'name' => 'Ken Hirata',
'email' => 'ken@hirata.com',
]);
update
$contact = Contact::find(1);
$contact->email = 'natalie@parkfamily.com';
$contact->save();
definition of fillable or guarded variables
class Contact
{
protected $fillable = ['name', 'email'];
// or
protected $guarded = ['id', 'created_at', 'updated_at', 'owner_id'];
}
filtering variable from request
Contact::create($request->only('name', 'email'));
firstOrCreate
$contact = Contact::firstOrCreate(['email' => 'luis.ramos@myacme.com']);
Deletion
$contact = Contact::find(5);
$contact->delete();
or
Contact::destroy(1);
Contact::destroy([1, 5, 7]);
Contact::where('updated_at', '<', now()->subYear())->delete();
soft delete
// migration
Schema::table('contacts', function (Blueprint $table) {
$table->softDeletes();
});
// model
<?php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Contact extends Model
{
use SoftDeletes; // use the trait
protected $dates = ['deleted_at']; // mark this column as a date
}
// after that, delete() and destory() call will set the deleted_at
// retrieve not(?) soft deleted items
$allHistoricContacts = Contact::withTrashed()->get();
// retrieve soft deleted items
$deletedContacts = Contact::onlyTrashed()->get();
// to see whether instance has been soft-deleted or not
if ($contact->trashed()) {
// do something
}
// restore item from soft-deleted state
$contact->restore();
Contact::onlyTrashed()->where('vip', true)->restore();
// force delete ( actually delete items from database )
$contact->forceDelete();
Contact::onlyTrashed()->forceDelete();
Databases and Eloquent ( Scope )
Add a local scope
class Contact
{
public function scopeStatus($query, $status)
{
return $query->where('status', $status);
}
use in query
$friends = Contact::status('friend')->get();
Add a global scope to a Model
class Contact extends Model
{
protected static function boot()
{
parent::boot();
static::addGlobalScope('active', function (Builder $builder) {
$builder->where('active', true);
});
}
or create a global scope class
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class ActiveScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
return $builder->where('active', true);
}
}
use in Model
<?php
use App\Scopes\ActiveScope;
use Illuminate\Database\Eloquent\Model;
class Contact extends Model
{
protected static function boot()
{
parent::boot();
static::addGlobalScope(new ActiveScope);
}
}
remove global scopes in query
$allContacts = Contact::withoutGlobalScope('active')->get();
Contact::withoutGlobalScope(ActiveScope::class)->get();
Contact::withoutGlobalScopes()->get(); // disable all global scope
Databases and Eloquent ( Accessors / Mutators / Attribute Casting )
Accessors
The function name should be get{SampleName}Attribute
Handle empty attribute
// Model definition:
class Contact extends Model
{
public function getNameAttribute($value)
{
return $value ?: '(No name provided)';
}
}
// Accessor usage:
$name = $contact->name;
Define new a attribute which doesn't exist in the database
// Model definition:
class Contact extends Model
{
public function getFullNameAttribute()
{
return $this->first_name . ' ' . $this->last_name;
}
}
// Accessor usage:
$fullName = $contact->full_name;
Mutators
The mutator name should be set{SampleName}Attribute
// Defining the mutator
class Order extends Model
{
public function setAmountAttribute($value)
{
$this->attributes['amount'] = $value > 0 ? $value : 0;
}
}
// Using the mutator
$order->amount = '15';
proxy column, this is uncommon method because it can be confusing
// Defining the mutator
class Order extends Model
{
public function setWorkgroupNameAttribute($workgroupName)
{
$this->attributes['email'] = "{$workgroupName}@ourcompany.com";
}
}
// Using the mutator
$order->workgroup_name = 'jstott';
Attribute Casting
class Contact
{
protected $casts = [
'vip' => 'boolean',
'children_names' => 'array',
'birthday' => 'date',
];
}
Date Mutators
class Contact
{
protected $dates = [
'met_at',
// already added created_at and updated_at by default
];
}
Databases and Eloquent ( Eloquent Serialization )
two types of serializer
$contactArray = Contact::first()->toArray();
$contactJson = Contact::first()->toJson();
$contactsArray = Contact::all()->toArray();
$contactsJson = Contact::all()->toJson();
The result of converting Eqloquent instance or string to string is the same as toJson
And every routes try to return result as string, so we can easily return Json response like
// routes/web.php
Route::get('api/contacts', function () {
return Contact::all();
});
Route::get('api/contacts/{id}', function ($id) {
return Contact::findOrFail($id);
});
Hiding attributes from json
class Contact extends Model
{
public $hidden = ['password', 'remember_token'];
// or
public $visible = ['name', 'email', 'status'];
Mannually change visibility
$array = $user->makeVisible('remember_token')->toArray();
Databases and Eloquent ( Eloquent Relationship )
One to One
// class def
class Contact extends Model
{
public function phoneNumber()
{
return $this->hasOne(PhoneNumber::class);
return $this->hasOne(PhoneNumber::class, 'owner_id'); // if you want to use 'owner_id’, not 'contact_id'
}
// usage
$contact = Contact::first();
$contactPhone = $contact->phoneNumber;
// inverse
class PhoneNumber extends Model
{
public function contact()
{
return $this->belongsTo(Contact::class);
}
$contact = $phoneNumber->contact;
inserting related items
$contact = Contact::first();
$phoneNumber = new PhoneNumber;
$phoneNumber->number = 8008675309;
$contact->phoneNumbers()->save($phoneNumber);
// or
$contact->phoneNumbers()->saveMany([
PhoneNumber::find(1),
PhoneNumber::find(2),
]);
// or
$contact->phoneNumbers()->create([
'number' => '+13138675309',
]);
// or
$contact->phoneNumbers()->createMany([
['number' => '+13138675309'],
['number' => '+15556060842'],
]);
One to Many
class User extends Model
{
public function contacts()
{
return $this->hasMany(Contact::class);
}
// usage
$user = User::first();
$usersContacts = $user->contacts;
// filtering
$donors = $user->contacts->filter(function ($contact) {
return $contact->status == 'donor';
});
$lifetimeValue = $contact->orders->reduce(function ($carry, $order) {
return $carry + $order->amount;
}, 0);
// inverse
class Contact extends Model
{
public function user()
{
return $this->belongsTo(User::class);
}
$userName = $contact->user->name;
attach and detach related item
$contact = Contact::first();
$contact->user()->associate(User::first());
$contact->save();
$contact->user()->dissociate();
$contact->save()
Selecting only records that have a related item
$postsWithComments = Post::has('comments')->get();
$postsWithManyComments = Post::has('comments', '>=', 5)->get();
$usersWithPhoneBooks = User::has('contacts.phoneNumbers')->get();
// Gets all contacts with a phone number containing the string "867-5309"
$jennyIGotYourNumber = Contact::whereHas('phoneNumbers', function ($query) {
$query->where('number', 'like', '%867-5309%');
});
Has many through
class User extends Model
{
public function phoneNumbers()
{
return $this->hasManyThrough(PhoneNumber::class, Contact::class);
}
Has one through
class User extends Model
{
public function phoneNumber()
{
return $this->hasOneThrough(PhoneNumber::class, Company::class);
}
Many to Many
// pivot table should be contact_user
class User extends Model
{
public function contacts()
{
return $this->belongsToMany(Contact::class);
// or
return $this->belongsToMany(Contact::class)
->withTimestamps()
->withPivot('status', 'preferred_greeting');
}
}
class Contact extends Model
{
public function users()
{
return $this->belongsToMany(User::class);
}
}
Databases and Eloquent ( Eloquent Relationship - Polymorphic )
この章疲れたので今度 -> 5. Databases and Eloquent の polymorphic
Databases and Eloquent ( Eager Loading )
Eager Loading
$contacts = Contact::with('phoneNumbers')->get();
$contacts = Contact::with('phoneNumbers', 'addresses')->get(); // multiple
$authors = Author::with('posts.comments')->get(); // nested
$contacts = Contact::with(['addresses' => function ($query) {
$query->where('mailable', true);
}])->get(); // not all relations
Lazy eager loading
// lazy eager loading
$contacts = Contact::all();
if ($showPhoneNumbers) {
$contacts->load('phoneNumbers');
$contacts->loadMissing('phoneNumbers'); // recommend
}
Eager Loading only the count
// Adds a "posts_count" integer to each Author with a count of that
// author's related posts
$authors = Author::withCount('posts')->get();
Databases and Eloquent ( Eloquent Events )
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
$thirdPartyService = new SomeThirdPartyService;
Contact::creating(function ($contact) use ($thirdPartyService) {
try {
$thirdPartyService->addContact($contact);
} catch (Exception $e) {
Log::error('Failed adding contact to ThirdPartyService; canceled.');
return false; // Cancels Eloquent create()
}
});
}
available events
Collecting and Handling User Data
Route::post('form', function (Illuminate\Http\Request $request) {
// $request->etc()
});
except/only
Route::post('post-route', function (Request $request) {
var_dump($request->except('_token'));
});
Route::post('post-route', function (Request $request) {
var_dump($request->only(['firstName', 'utm']));
});
has
if ($request->has('utm')) {
// Do some analytics work
}
input
Route::post('post-route', function (Request $request) {
$userName = $request->input('name', 'Matt');
});
array input
Route::post('employees', function (Request $request) {
$employeeZeroFirstName = $request->input('employees.0.firstName');
$allLastNames = $request->input('employees.*.lastName');
$employeeOne = $request->input('employees.1');
var_dump($employeeZeroFirstname, $allLastNames, $employeeOne);
});
file data
Route::post('form', function (Request $request) {
if ($request->hasFile('profile_picture')) {
var_dump($request->file('profile_picture'));
}
});
Validation
Manual Validation
Route::post('recipes', function (Illuminate\Http\Request $request) {
$validator = Validator::make($request->all(), [
'title' => 'required|unique:recipes|max:125',
'body' => 'required'
]);
if ($validator->fails()) {
return redirect('recipes/create')
->withErrors($validator)
->withInput();
}
// Recipe is valid; proceed to save it
});
Custom Rule ( php artisan make:rule RuleName
)
class WhitelistedEmailDomain implements Rule
{
public function passes($attribute, $value)
{
return in_array(Str::after($value, '@'), ['tighten.co']);
}
public function message()
{
return 'The :attribute field is not from a whitelisted email provider.';
}
}
// in use
$request->validate([
'email' => new WhitelistedEmailDomain,
]);
Form Requests
php artisan make:request CreateCommentRequest
<?php
namespace App\Http\Requests;
use App\BlogPost;
use Illuminate\Foundation\Http\FormRequest;
class CreateCommentRequest extends FormRequest
{
public function authorize()
{
$blogPostId = $this->route('blogPost');
return auth()->check() && BlogPost::where('id', $blogPostId)
->where('user_id', auth()->id())->exists();
}
public function rules()
{
return [
'body' => 'required|max:1000',
];
}
}
// in use, specify the class
Route::post('comments', function (App\Http\Requests\CreateCommentRequest $request) {
// Store comment
});
Artisan and Tinker
Artisan
-
clear-compiled
: Remove Laravel's compiled class file -
down up
: Handle maintenance mode -
env
: Echo app()->environment() in-app -
migrate
: Runs all database migrations -
optimize
: Clears and refreshes the configuration and route files -
preset
: Changes out the frontend scaffolding for another -
serve
: Pins up a PHP server at localhost:8000 -
tinker
: Brings up the Tinker REPL. -
--env
Specify env (local, production, etc.)
grouped commands
-
auth
(auth:clear-resets
) -
cache
(cache:clear
cache:forget
cache:table
) -
config
(config:cache
config:clear
) -
db
(db:seed
) -
event
(event:list
event:cache
event:clear
) -
key
(key:generate
) make
-
migrate
(migrate:install
migrate:reset
migrate:refresh
migrate:fresh
migrate:status
) -
notifications
(notifications:table generates
) -
queue
(queue:listen
queue:table
) -
route
(route:list
route:cache
) -
schedule
(schedule:run
) -
session
(session:table
) -
storage
(storage:link
) -
vendor
(vendor:publish
) -
view
(view:clear
)
custom artisan command
php artisan make:command WelcomeNewUsers --command=email:newusers
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class WelcomeNewUsers extends Command
{
/**
* The name and signature of the console command
*
* @var string
*/
protected $signature = 'email:newusers';
/**
* The console command description
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command
*
* @return mixed
*/
public function handle()
{
//
}
}
Dump Server
php artisan dump-server
Route::get('/', function () {
dump('Dumped Value');
return 'Hello World';
});
Testing
./vendor/bin/phpunit
: target files are test/**/*Test.php