结构预览
难点:
Laravel表机制:保证结构复杂的数据的一致性,如何规划数据结构,如何封装为易用且运行稳定的API
使用composer安装laravel
php composer.phar create-project laravel/laravel project disable-tls(前提把composer.phar放在安装目录)
报错:
The openssl extension is required for SSL/TLS protection but is not available. If you can not enable the openssl extensi
on, you can disable this error, at your own risk, by setting the 'disable-tls' option to true.
解决:php.ini中extension=php_openssl.dll打开
运行:
php artisan --version 查看版本
F:\phpStudy\WWW\Larvael>php -S localhost:8000 -t project/public
配置国内全量镜像Packagist:composer.json
"repositories": {
"packagist": {
"type": "composer",
"url": "https://packagist.phpcomposer.com"
}
}
小技巧(win):shift 点击鼠表邮件,cmd
Migration:数据库的版本控制
- . 解决团队合作下数据库结构不统一的问题
- SQL语句->PHP语句
create table users(
id int(10) unsigned not null auto_increment,
username varchar(12),
password varchar(255) not null,
primary key(id),
UNIQUE KEY users_username_unique(username)
) engine=innodb;
mysqldump -uroot -p *** > wangba.sql
创建Migration
up:
php artisan make:migration create_table_table1(生成在database)
artisan是laravel里面的一个命令行工具
class CreateTableTable1 extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
//
Schema::create('table',function(Blueprint $table){
$table->increments('id');
$table->string('name',12)->nullable()->unique();
$table->text('name')->nullable();
});
}
php artisan migrate
回滚(down):
public function down()
{
//
Schema::drop('table1');
}
php artisan migrate:rollback
参数:–pretend,预先查看
开发user表:
php artisan make:migration create_table_users --create=users
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('username')->unique();
$table->text('avatar_url')->nullable(); //默认代替
$table->string('email')->unique()->nullable();
$table->string('phone')->unique()->nullable(); // string or number 区号+,或者未来x
$table->string('password',255);
$table->text('intro')->nullable();
$table->timestamps();
});
}
php artisan migrate
php artisan migrate:rollback(保证都能正确执行)
php artisan migrate
注册API的实现
App->Http->routes.php(处理所有网络连接的设置)
如果是字符串,默认返回html/text
如果是数组,默认返回json
laravel 5.3之后就不存在route文件了。
而是改用routes文件夹中的web.php文件。routes->web.php
Route::any('api',function(){
return ['version' => '2.0'];
});
调用user模块
Route::any('api/user',function(){
$user = new App\User;
return $user->signup();
});
php artisan make:model User 创建一个模板
app->User.php
class User extends Model
{
//
public function signup(){
return 'signup';
}
}
注册API的实现
http://localhost:8000/public/index.php/api/user?username=%E7%8E%8B%E6%B7%B3%E9%BE%99&password=123
dd dorp and die 就是debug
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Request;
class User extends Model
{
//
public function signup(){
//
dd(Request::get('age'));
dd(Request::has('age'));
dd(Request::all());
// return 'signup';
}
}
加密密码:Hash::make( password)简易写bcrypt( password)
登陆API的实现
登陆接口:
function user_ins(){
return new App\User;
}
Route::any('api/login',function(){
return user_ins()->login();
});
登陆函数:
public function login(){
// 监测用户名和密码是否存在
// 接受Url参数
$has_username_and_password = $this->has_username_and_password();
if(!$has_username_and_password){
return ['status' => 0,'msg' => '用户名和密码皆不可为空'];
};
$username = $has_username_and_password[0];
$password = $has_username_and_password[1];
// 监测用户是否存在
$user = $this->where('username',$username)->first();
if(!$user){
return ['status' => 0,'msg' => '用户不存在 '];
}
// 监测密码是否正确
$hashed_possword =$user->password;
if(!Hash::check($password,$hashed_possword))
return ['status' => 0,'msg' => '密码有误 '];
return 1;
}
注意Laravel的php版本问题。For Laravel 5 you need:
The Laravel framework has a few system requirements:
PHP >= 5.4
Mcrypt PHP Extension
OpenSSL PHP Extension
Mbstring PHP
Extension Tokenizer PHP Extension
vendor/laravel/framework/src/Illuminate/Foundation/helpers.php on line 49(做其他项目时切换了下,没注意这个问题)
session:
session()->put('username',$user->username);
session()->set('person.name.wangchunlong.age','20');//支持多级嵌套
删除session:
$_username = session()->pull('username'); //拿出来,剪切
session()->forget('username');
session()->put('username',null);
session()->flush();
问题API的实现
Question Migration的建立(Up和Down)
php artisan make:migration create_table_questions --create=questions
突然写错了,发现删除后重新执行命令报错
[ErrorException]
include(F:\phpStudy\WWW\Larvael\project\vendor\composer/../../database/migrations/2017_05_25_062526_create_table_questions.php): failed to open stream: No such file or directory
解决方法:
php artisan cache:clear 删除缓存文件(bootstrap文件夹)
composer dump-autoload -o
composer update 重新加载再生成包含在项目中的列表文件
public function up()
{
Schema::create('questions', function (Blueprint $table) {
$table->increments('id');
$table->string('title',64);
$table->text('desc')->nullable()->comment('description'); //description
$table->unsignedInteger('user_id'); //无符号整形
$table->unsignedInteger('admin_id'); //防止误操作
$table->string('status')->default('ok'); //status,举报折叠问题
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
});
}
php artisan migrate
报错,说users表已经创建,原来这个表之前就没有创建成功。
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_username_unique`(`username`))
经过查询,是数据库版本过低的原因造成的。
Laravel 5.4更改了默认数据库字符集,现在utf8mb4它包括支持存储emojis。这只会影响新的应用程序,只要你运行MySQL v5.7.7或更高版本,你就不需要做任何事情。
添加代码,限制索引长度:
迁移指南:
编辑AppServiceProvider.php文件,并在boot方法中设置一个默认的字符串长度:
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
删表,重新执行,Good Job。
路由的建立和方法的建立
注意方法名不要和内置方法冲突
function question_ins(){
return new App\Question;
}
Route::any('api/question/add',function(){
return question_ins()->add();
});
php artisan make:model Question
问题添加:
class Question extends Model
{
//
public function add(){
if(!user_ins()->is_logged_in()){
return ['status' => 0,'msg' => 'login required'];
};
if(!rq('title')){
return ['status' => 0,'msg' => 'required title'];
}
if(rq('desc'))
$this->desc = rq('desc');
$this->title = rq('title');
$this->user_id = session('user_id');
return $this->save() ? ['status' => 1,'id' => $this->id] : ['status' => 0,'msg' => 'db insert failed'];
}
}
小贴士:使用laravel validation可以验证长度,数据类型
自己看
问题更新:
//更新问题
Route::any('api/question/refresh',function(){
return question_ins()->refresh();
});
//更新问题API
public function refresh(){
//检查用户是否登陆
if(!user_ins()->is_logged_in()){
return ['status' => 0,'msg' => 'login required'];
}
//检查传参中是否有ID
if(!rq('id'))
return ['status' => 0,'msg' => 'id is required'];
//获取指定ID的model
$question = $this->find(rq('id')); //返回主键对应的那一行
//用户不存在中断
if(!$question)
return ['status' => 0,'msg' => 'user not exisits'];
if($question->user_id != session('user_id')){
return ['status' => 0,'msg' => 'permission denied'];
}
//加判断的原因是有什么更新什么。
if(rq('title'))
$question->title = rq('title');
if(rq('desc'))
$question->desc = rq('desc');
return $question->save() ? ['status' => 1,] : ['status' => 0,'msg' => 'db refresh failed'];
}
查看问题,删除问题(略)……….
回答API的实现
Answers Migration的建立(Up和Down)
php artisan make:migration create_table_answers --create=answers
public function up()
{
Schema::create('answers', function (Blueprint $table) {
$table->increments('id');
$table->text('content');
$table->unsignedInteger('user_id');
$table->unsignedInteger('question_id');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
$table->foreign('question_id')->references('id')->on('questions');
});
}
php artisan migrate --pretend
php artisan migrate
php artisan make:model Answer
………
通用API的实现(跨表查询)
点赞和取消赞实现:
answer和user是多对多的关系
Answer模块和User模块下添加注册函数(指明两模块的关系):
public function users(){
return $this->belongsToMany('App\User');
}
public function answers(){
return $this->belongsToMany('App\Answer');
}
建立一个连接表,把answers表和users表通过一个轴表(中间表)连接起来
php artisan make:migration create_table_answer_user --create=answer_user(连接表例外,必须单数)
public function up()
{
Schema::create('answer_user', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('user_id'); //主键
$table->unsignedInteger('answer_id'); //主键
$table->unsignedSmallInteger('vote'); //赞同1,反对0
$table->timestamps();
$table->foreign('user_id')->references('users')->on('users');
$table->foreign('answer_id')->references('users')->on('answers');
});
}
user_id,answer_id,vote三者组合必须为1,所有需要限制一下(unique)。
$table->unique(['user_id','answer_id','vote']);
php artisan migrate
添加
php artisan migrate:rollback
php artisan migrate
添加接口,写vote方法
public function vote(){
if(!user_ins()->is_logged_in())
return ['status' => 0,'msg' => 'logined required'];
// answer_id是否存在,赞成还是反对
if(!rq('id') || !rq('vote'))
return ['status' => 0,'msg' => 'id or vote is required'];
//回答是否存在
$answer = $this->find(rq('id'));
if(!$answer) return ['status' => 0,'msg' => 'answer not exists'];
// 1赞同 2反对
$vote = rq('vote') <= 1 ? 1 : 2;
// 在中间表查找是否有该键,检查用户是否在相同问题下投过票(如果投过票,则delete)
$answer
->users()
->newPivotStatement() //进入user_answer连接表进行操作
->where('user_id',session('user_id'))
->where('answer_id',rq('id'))
->delete();
// 在连接表中添加数据
$answer->users()->attach(session('user_id'),['vote' => $vote]);
return ['status' => 1];
}
时间线API实现
php artisan make:controller CommonController位置在Http->Controllers->Comm.....
接口
//时间线 @相当于分隔符
Route::any('api/timeline','CommonController@timeline');
class CommonController extends Controller
{
public function timeline(){
list($limit,$skip) = paginate(rq('page'),rq('limit'));
$questions = question_ins()
->limit($limit)
->skip($skip)
->orderBy('created_at','desc')
->get();
$answers = answer_ins()
->limit($limit)
->skip($skip)
->orderBy('created_at','desc')
->get();
//合并两张表数据
$data = $questions->merge($answers);
// 按照时间线来排序,把每一条数据存为item
$data = $data->sortByDesc(function($item){
return $item->created_at;
});
// 只取值,不取键
$data = $data->values()->all();
return ['status' => 1, 'data' => $data];
}
}
API设计指南
- 命名清晰,准确(功能+思想=名称)
- 第三方API最好有版本号,V0.1.1
- RESTful.http://www.ruanyifeng.com/blog/2014/05/restful_api.html(切末生搬硬套。设计理论,不是规范)