全局安裝
composer global require "laravel/installer"
安装后执行
export PATH=PATH:HOME/.composer/vendor/bin
将laravel 加入全局路径
新建project
laravel new common-system
composer create-project --prefer-dist laravel/laravel common-system
添加 auth support
php artisan make:auth
添加 model 并生成数据迁移文件
php artisan make:model Models/PasswordHistory -m
执行迁移
php artisan migrate
针对某个表执行,--table 和 --create 选项可用来指定数据表的名称,或是该迁移被执行时会创建的新数据表。这些选项需在预生成迁移文件时填入指定的数据表:
php artisan make:migration create_users_table
php artisan make:migration create_users_table --create=users
migrate:refresh命令首先回滚所有的数据据迁移, 然后运行migrate 命令, 这个命令有效地重建了整个数据库。
php artisan migrate:refresh
// 刷新数据库结构并执行数据填充
php artisan migrate:refresh --seed
修改字段需要安装第三方库
composer require doctrine/dbal
如果装了这个库之后,手动修改了db 结构,会报错~~,将它删除掉重新安装就可以了
创建 seeder 类
php artisan make:seeder UsersTableSeeder
运行seed
php artisan db:seed
php artisan db:seed --class=UsersTableSeeder
路由不区分大小写
在入口 index.php
中添加:
// uri 全部转成小写
$GLOBALS['_SERVER']['REQUEST_URI'] = strtolower($GLOBALS['_SERVER']['REQUEST_URI']);
参考:https://laracasts.com/discuss/channels/laravel/how-do-i-make-routes-case-insensitive?page=1
自定义事件
生成自定义事件
php artisan make:event UpdateUserStatusEvent
创建自定义事件监听器
php artisan make:listener UpdateUserStatusListener --event UpdateUserStatusEvent
在 ./app/Providers/EventServiceProvider.php
中添加监听器和事件的关联
'App\Events\UpdateUserStatusEvent' => [
'App\Listeners\UpdateUserStatusListener',
],
fire 事件
event(new UpdateUserStatusEvent($event->user, "lock"));
auth 的 failed 事件是怎么触发的?
在 SessionGuard.php
的 attempt
/**
* Attempt to authenticate a user using the given credentials.
*
* @param array $credentials
* @param bool $remember
* @return bool
*/
public function attempt(array $credentials = [], $remember = false)
{
$this->fireAttemptEvent($credentials, $remember);
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
// If an implementation of UserInterface was returned, we'll ask the provider
// to validate the user against the given credentials, and if they are in
// fact valid we'll log the users into the application and return true.
if ($this->hasValidCredentials($user, $credentials)) {
$this->login($user, $remember);
return true;
}
// If the authentication attempt fails we will fire an event so that the user
// may be notified of any suspicious attempts to access their account from
// an unrecognized user. A developer may listen to this event as needed.
$this->fireFailedEvent($user, $credentials);
return false;
}
登入失败触发 fireFailedEvent
事件。如果我们要监听 failed
事件,可以添加 listener
,并在 EventServiceProvider
绑定 lister
和 event
的关系
protected $listen = [
'App\Events\SomeEvent' => [
'App\Listeners\EventListener',
],
'App\Events\UpdateUserStatusEvent' => [
'App\Listeners\UpdateUserStatusListener',
],
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LoginListener',
],
'Illuminate\Auth\Events\Failed' => [
'App\Listeners\LoginFailedListener',
],
];
listener:
<?php
namespace App\Listeners;
use Illuminate\Auth\Events\Failed;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;
use App\Repositories\LoginLogRepository;
use App\Models\LoginLog;
use App\Libs\nmg\account\AccountFactory;
use App\Events\UpdateUserStatusEvent;
class LoginFailedListener
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param AuthLoginEvent $event
* @return void
*/
public function handle(Failed $event)
{
if (!$event->user) return false;
$userID = $event->user->id;
$log = new LoginLogRepository();
$log->addLoginLog($userID, false, 'login failed');
$count = $log->getLoginFailedTime($userID);
// 如果密码错误超过次数,发送email提醒
$accountFactory = new AccountFactory();
$maxTimes = $accountFactory->getPolicyByName("incorrectTimes");
if ($count >= $maxTimes) {
event(new UpdateUserStatusEvent($event->user, "lock"));
}
return false;
}
}
添加 login 事件
login 后将登入状态记录到 DB 。新建 2 个 Event Listener, 并在 EventServiceProvider 中添加
protected $listen = [
'App\Events\SomeEvent' => [
'App\Listeners\EventListener',
],
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LoginListener',
],
'Illuminate\Auth\Events\Failed' => [
'App\Listeners\LoginFailedListener',
],
];
Auth 默认带了 login 和 failed 事件,在
vendor\laravel\framework\src\Illuminate\Auth\Events
在 Listener 的 handle 中添加事件处理
public function handle(Login $event)
{
//
Log::info("email:" . $event->user->email);
return false; // 停止事件传播
}
自定义验证规则
https://github.com/golaravel/laravel4.1docs/blob/master/cn/validation.md#custom-validation-rules
获取最近一次执行的sql
DB::enableQueryLog();
$users = $this->user->search("david");
var_dump($users->toArray());
$queries = DB::getQueryLog();
var_dump($queries);
$last_query = end($queries);
var_dump($last_query);
echo $last_query['query'];
array (size=3)
'query' => string 'select * from `users` where `user_id` like ? order by `user_id` desc' (length=68)
'bindings' =>
array (size=1)
0 => string '%david%' (length=7)
'time' => float 13
使用DebugBar
install:
composer require barryvdh/laravel-debugbar
https://github.com/barryvdh/laravel-debugbar
但是,如果是ajax请求,debugbar不会输出ajax的sql
use Barryvdh\Debugbar\Facade as Debugbar;
Debugbar::error('my test!', 'my_label');
发送邮件
基于 API 的驱动,例如 Mailgun 和 SparkPost 通常比 SMTP 服务器更简单快速。如果可能,你应该尽可能使用这些驱动。所有的 API 驱动都需要 Guzzle HTTP 函数库,你可以使用 Composer 包管理器安装它:
composer require guzzlehttp/guzzle
生成 mailables#
在 Laravel 中,每种类型的邮件都代表一个「mailables」对象。这些对象存储在 app/Mail
目录中。如果在你的应用中没有看见这个目录,别担心,在首次使用 make:mail
命令创建 mailables 类时这个目录会被创建,例如:
php artisan make:mail LockAccount
修改Build
public function build()
{
return $this->view('view.lock_account');
}
修改email 模板文件
如何禁用csrf token?
laravel 默认是开启 csrf token 的,但是有时我们会通过第三方工具测试 url ,例如发送post 请求,如果开启 csrf token 会导致请求失败。
我们可以在全局关闭csrf token。
打开文件:app\Http\Kernel.php
把这行注释掉:
'App\Http\Middleware\VerifyCsrfToken'
如果只想关闭某个url 页面的csrf token 。可以在.\app\Http\Middleware\VerifyCsrfToken.php
添加例外路由规则
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array
*/
protected $except = [
//
'admin/*',
];
API 授权
composer require laravel/passport
在./config/app.php 添加 providers
Laravel\Passport\PassportServiceProvider::class,
Model添加访问器
laravel可以为 model 默认属性添加访问器,使数据按照自定义的格式输出。也可以生成一个不存在的属性,但是在 对象或 toArray 输出时不会显示,但是直接访问该属性名是可以输出的。
public function getDisplayNameAttribute()
{
return $this->last_name . ',' . $this->first_name . ($this->nick_name ? " ($this->nick_name)" : '');
}
artisan 命令参考
显示 debug 信息,可以在命令行最后加上 -vvv
生成带资源控制器
php artisan make:controller PhotoController --resource
php artisan make:controller PhotoController --resource --model=Photo
Route::resource('photos', 'PhotoController');
生成新的app key
php artisan key:generate
查看路由
php artisan route:list
生成model 和migrate
php artisan make:model User -m
执行数据库迁移,请注意:不能针对某个表执行迁移
php artisan migrate
php artisan list
php artisan help migrate
php artisan migrate refresh # 重置数据库,rollback后再执行migrate,会删除所有表和数据
生成 data seed
php artisan make:seeder GroupsTableSeeder
可以针对某个seeder 执行,但是不能rollback。
php artisan db:seed
php artisan db:seed --class=UsersTableSeeder
如何在 seed 中批量插入数据?
若使用以下方式, 不会自动加入 create_at,update_at 等默认值。
DB::table('users')->insert([
'name' => str_random(10),
'email' => str_random(10).'@gmail.com',
'password' => bcrypt('secret'),
]);
改成UserModel::insert($users);
也一样。不会加入自动的 timestamp
字段,要手动加上这2个字段
参考下:
http://stackoverflow.com/questions/12702812/bulk-insertion-in-laravel-using-eloquent-orm/26569967#26569967
因为 timestamp
是eloquent 才有的。可以改成用 create
生成 timestamp
public function run()
{
$websites = [
[
'title' => '1',
'atom_link' => 'http://www.xx.com/feed/',
],
[
'title' => '新22',
'atom_link' => 'http://www.xxxx.hk/feed/',
]
];
foreach($websites as $website){
Website::create($website);
}
}
清除缓存等
php artisan config:clear
php artisan view:clear // 清除 storage\framework\views 下的cache 文件
php artisan route:clear
php artisan clear-compiled
cache 设置和获取
Cache::put('test', true, 30);
dump(Cache::getDefaultDriver());
$this->assertTrue(Cache::get('test'));
使用 put
设置 cache
要注意的是,不能省略第三个参数minutes。否则默认是null,实际上不会存储cache。在phpunit
中若不设置第三个参数,则assertTrue
是false。
另外,如果是在laravel中设置的cache,在phpunit中是获取不到的,因为两者的驱动方式不一样,phpunit
的phpunit.xml
中设置了cache
的存储驱动,laravel
默认是 file
驱动
<php>
<env name="APP_ENV" value="testing"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="QUEUE_DRIVER" value="sync"/>
</php>
日志记录
Log::emergency($message);
Log::alert($message);
Log::critical($message);
Log::error($message);
Log::warning($message);
Log::notice($message);
Log::info($message);
Log::debug($message);
Log::info('User failed to login.', ['id' => $user->id]);
查看最近 一條sql
DB::enableQueryLog();// 全局使用可以放入AppServiceProvider的 boot 中
DB::getQueryLog()
将每次sql操作都写入log文件。在AppServiceProvider.php
的boot中添加
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
DB::enableQueryLog();
DB::listen(function ($query) {
Log::debug("SQL: ", [
$query->sql,
$query->bindings,
$query->time
]);
});
}
Eloquent 添加自定义访问器 (Defining An Accessor)
可以在model中添加自定义属性访问器,获取后可以直接像访问原生字段一样访问。但是如果返回成json或array,这些自定义属性是不会添加上去的。
因为默认laravel是不会加上去的,要在model上添加需要append的自定义属性,参考
https://laravel.io/forum/02-26-2014-model-attribute-accessor-not-working-with-object-get-helper-function
protected $appends = array('displayName');
phpunit
执行所有测试用例
phpunit
只执行指定test function
phpunit --filter 'testMembers'
参考
https://phpunit.de/manual/current/zh_cn/textui.html#textui.clioptions
https://phpunit.de/
如果phpunit执行以下错误
PHP Fatal error: Uncaught Error: Call to undefined method PHPUnit_Util_Configuration::getTestdoxGroupConfiguration() in /home/laravel5/common-system/vendor/phpunit/phpunit/src/TextUI/TestRunner.php:1066
Stack trace:
#0 /home/laravel5/common-system/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(163): PHPUnit_TextUI_TestRunner->handleConfiguration(Array)
#1 /usr/share/php/PHPUnit/TextUI/Command.php(155): PHPUnit_TextUI_TestRunner->doRun(Object(PHPUnit_Framework_TestSuite), Array)
#2 /usr/share/php/PHPUnit/TextUI/Command.php(106): PHPUnit_TextUI_Command->run(Array, true)
#3 /usr/bin/phpunit(29): PHPUnit_TextUI_Command::main()
#4 {main}
thrown in /home/laravel5/common-system/vendor/phpunit/phpunit/src/TextUI/TestRunner.php on line 1066
root@linuxtest:/home/laravel5/common-system# phpunit --version
PHPUnit 5.1.3 by Sebastian Bergmann and contributors.
表示phpunit的版本太低,在 composer.json 中要求 "phpunit/phpunit": "~5.7"。请升级phpunit 至最低要求版本!
$ wget https://phar.phpunit.de/phpunit-6.1.phar
$ chmod +x phpunit-6.1.phar
$ sudo mv phpunit-6.1.phar /usr/local/bin/phpunit
$ phpunit --version
测试controllers
有个方法调用了route的action。由于在phpunit中无法获取到route,因此会测试失败。这种情况,可以测试controller的方法,通过
public function testRemoveGroups()
{
$response = $this->call('POST', 'Admin\GroupController@removeGroups', ['ids'=>'7,8']);
}
请注意,laravel5.1用的是$this->action();
laravel 5.4 没有action这个方法了。
获取 表的所有字段
模板
模板渲染时报错
ErrorException
in helpers.php line 532:htmlspecialchars() expects parameter 1 to be string, array given (View: /home/laravel5/common-system/resources/views/cms/user/privileges.blade.php)
如果赋值的数据是数据类型,不应该用var members = {{ $members }};
而应该用var members = {!! $members !!};
自定义辅助函数
-- 1. 在 app 目录下新建一个文件 helpers.php**
-- 2. 在 composer.json 文件的 autoload 字典中添加 "files":["app/helpers.php"][图片上传失败...(image-ed170d-1532662234986)]
-- 3. 执行命令:composer dumpautoload OK搞定
-- 4. 这其实是与composer中的自动加载有关 -> **链接
为数组或 collect 添加分页
注意 array_slice
最后一个参数如果改成 true 会导致重新排序。默认 false
$data 是数组
use Illuminate\Pagination\LengthAwarePaginator;
/**
* 根据热度,时间等因素排序
* @param int $perPage
* @param array $pagesize
* @return mixed
*/
public function smart_paginate($page=1, $page_size = 10)
{
$data = $this->getAllFeeds();
// Start displaying items from this number;
$offSet = ($page * $page_size) - $page_size;
return new LengthAwarePaginator(array_slice($data, $offSet, $page_size),
count($data),
$page_size,
$page,
['path' => request()->url(),
'query' => request()->query()]);
}
为数据库查询添加 cache
Laravel4 的 ->remember(60)
的写法已经被抛弃了。
use Illuminate\Support\Facades\Cache;
$value = Cache::remember('users', $minutes, function () {
return DB::table('users')->get();
});
cronjob 日志权限变成root 导致 website 无法打开
设置了cronjob 来执行console command,用的是root
用户执行的,且日志是按日期生成的,导致生成的日期文件都是root
用户创建的,而website使用的是www-data,因此没有权限写入这些root
创建的日志文件。
解决办法:将cronjob 放入www-data
的crontab 中执行。
model 查询重置查询
同一个model执行多次查询,会使用上一次查询的条件。为了重置查询,需要加上 newQuery()
或
newQueryWithoutScopes
或
newQueryWithoutScope
API 文檔:
https://laravel.com/api/5.5/Illuminate/Database/Eloquent/Model.html#method_newQuery
$model->newQuery()->where($data)->get();
Session 后直接执行exist();不会保存session
例如
public function testSession()
{
session(['key' => 'abc']);
exit();
}
// 无输出
public function getSession()
{
echo session('key');
}
不要exit(),就有输出
public function testSession()
{
session(['key' => 'abc']);
}
// 有输出
public function getSession()
{
echo session('key');
}
换成
$request->session()->put('key', 'abcd');
也是一样的结果。别人有提出过这个问题:
https://github.com/laravel/framework/issues/3267
https://stackoverflow.com/questions/46403996/sessionput-not-working-when-i-put-die-or-exit-after-declaration-in-laravel
https://stackoverflow.com/questions/26206021/laravel-session-storage-is-empty-on-refresh
标准答案:
Laravel's session data is written as part of the response shutdown process. This is for efficiency reasons - if you're making dozens of Session::put
calls in a request, it's better to make them all at once in bulk.
As a result, if you don't cause a response with something like View::make
or Response::json
or what have you and instead exit
or die
, session data won't be written as you've short circuited the response lifecycle.
request 如何区分有无input这个field以及这个field的内容为空的区别?
如果form中无某个input和有input但是内容为空,通过$request获取到的都是null。如何区别这两者情况呢?
<input type="text" name="password" value="">
有input且value=‘’的情况
$input = $request->all();
var_dump($input);
var_dump($request->has('password'));// 有input 返回true,无则返回false
var_dump($request->input('password'));//有input且value='' 也返回null
var_dump($request->password);//有input且value='' 也返回null
var_dump($_POST['password']);//有input且value='' 也返回“”
exit();
无input,就都返回null。这个是一样的。
因此,可以通过$request->has()方法区别input是否存在和输入值为空的情况
5.5 取消了整数类型字段的第二个参数
$table->unsignedTinyInteger('width', 4)->default(1);
会报错
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default val
ue for 'width' (SQL: create table `sys_grid_files` (`id` int unsigned not n
ull auto_increment primary key, `file_name` varchar(255) not null, `origina
l_name` varchar(255) null, `file_path` varchar(255) not null, `file_size` i
nt unsigned not null default '0', `file_type` varchar(50) not null, `width`
tinyint unsigned not null default '0' auto_increment primary key, `height`
tinyint unsigned not null default '0' auto_increment primary key, `storage
_engine` varchar(50) not null comment 'local or s3', `upload_user` varchar(
50) null, `status` tinyint unsigned not null default '1' auto_increment pri
mary key, `created_at` timestamp null, `updated_at` timestamp null) default
character set utf8mb4 collate utf8mb4_unicode_ci engine = InnoDB)
[Doctrine\DBAL\Driver\PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default val
ue for 'width'
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1067 Invalid default val
ue for 'width'
要改成
$table->unsignedTinyInteger('width')->default(1);
laravel migration 找不到db的问题
执行php artisan migrate
出现
[Illuminate\Database\QueryException]
SQLSTATE[HY000] [1049] Unknown database 'instagram_auto_post_cms' (SQL: sel
ect * from information_schema.tables where table_schema = instagram_auto_po
st_cms and table_name = migrations)
的错误,这个sql
在phpmyadmin
中执行,确实是没有记录的。
select * from information_schema.tables where table_schema = instagram_auto_post_cms and table_name = migrations
这个db
是手动通过phpmyadmin
添加的,删除掉,再用create database instagram_auto_post_cms
创建,就可以在information_schema.tables
表中见到这个db了。再次执行php artisan migrate
,正确执行。
leftJoin 多条件查询
使用闭包函数,传$join
参数进行处理。如果是查询不要用on
,改用where
。因为用on
会将1转换成string
,导致查询类型错误。
$now = datetime();
$posts = $this->model->select('ig_post.id', 'ig_post.message', 'ig_post.publish_time',
'ig_post.post_type', 'ig_post.page_id',
'sys_grid_files.file_path', 'sys_grid_files.file_name')
->leftJoin('sys_grid_files_mapping', function ($join) {
$join->on('sys_grid_files_mapping.pk_value', '=', 'ig_post.id');
$join->on('sys_grid_files_mapping.field_name', '=', 'ig_post.post_type');
$join->where('sys_grid_files_mapping.status', '=', 1);
})
->leftJoin('sys_grid_files', 'sys_grid_files.id', '=', 'sys_grid_files_mapping.file_id')
->where('page_id', $page_id)
->where('sync_status', 0)
->where('publish_time', '<', $now)
->get();
.env 的配置内容包含空格必须用引号包含起来,否则会报错
执行代码报以下错误
Fatal error: Uncaught ReflectionException: Class config does not exist in /home/laravel5/ig_cms/vendor/laravel/framework/src/Illuminate/Container/Container.php:752 Stack trace: #0 /home/laravel5/ig_cms/vendor/laravel/framework/src/Illuminate/Container/Container.php(752): ReflectionClass->__construct('config') #1 /home/laravel5/ig_cms/vendor/laravel/framework/src/Illuminate/Container/Container.php(631): Illuminate\Container\Container->build('config') #2 /home/laravel5/ig_cms/vendor/laravel/framework/src/Illuminate/Container/Container.php(586): Illuminate\Container\Container->resolve('config', Array) #3 /home/laravel5/ig_cms/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(732): Illuminate\Container\Container->make('config', Array) #4 /home/laravel5/ig_cms/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php(110): Illuminate\Foundation\Application->make('config', Array) #5 /home/laravel5/ig_cms/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php(272): app('config') #6 /home/laravel5/ig in /home/laravel5/ig_cms/vendor/laravel/framework/src/Illuminate/Container/Container.php on line 752
执行composer dump-autload
报错:
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover
[Dotenv\Exception\InvalidFileException]
Dotenv values containing spaces must be surrounded by quotes.
Script @php artisan package:discover handling the post-autoload-dump event returned with error code 1
env 配置文件
如果使用了config:cache 则只有config文件才能读取到env('xxx')。其它地方都读取不到。必须建议env 变量对应的config文件'env.php'通过config('env.xxx')来读取。参考:https://icewing.cc/post/laravel-5-env.html
参考资料
laravel5.4 中文文档
laravel up and running
laravel5.1 LTS 速查表
laravel5.4 API
PIPE 模式
PIPE
php artisan list
网友评论