Laravel 5 系列入门教程(二)【最适合中国人的 Laravel 教程】

2015-3-8   /   阅读数:161690   /   分类: Laravel

本教程示例代码见:https://github.com/johnlui/Learn-Laravel-5  

大家在任何地方卡住,最快捷的解决方式就是去看我的示例代码。

我们将改变学习路线,不再像 Laravel 4 教程那样先构建登录系统。在本篇教程中,我们将一起构建 Pages 的管理功能,尝试 Laravel 的路由和 PHP 的命名空间

1. 路由

Laravel 中的路由,跟其他 PHP 框架一样,作用是把各种请求分流到各个控制器。

在 `learnlaravel5/app/Http/routes.php` 的末尾添加以下代码:

Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function()
{
  Route::get('/', 'AdminHomeController@index');
});

这表示创建了一个路由组。

1. `'prefix' => 'admin'` 表示这个路由组的 url 前缀是 /admin,也就是说中间那一行代码 `Route::get('/'` 对应的链接不是 http://fuck.io:88/ 而是 http://fuck.io:88/admin ,如果这段代码是 `Route::get('fuck'` 的话,那么 URL 就应该是 http://fuck.io:88/admin/fuck

2. `'namespace' => 'Admin'` 表示下面的 `AdminHomeController@index` 不是在 `\App\Http\Controllers\AdminHomeController@index` 而是在 `\App\Http\Controllers\Admin\AdminHomeController@index`,加上了一个命名空间的前缀。

如果你用过 Laravel 4,会发现 Laravel 5 的命名空间规划比较怪异,这其实是一个非常大的进步。Laravel 4 其实已经全面引入了命名空间这个强大的特性,但是为了“降低学习成本”,把 路由、控制器、模型 的默认命名空间全部设置成了顶级命名空间,这个举动反而让很多人比较轻易地“上手”了 Laravel,但是在用了一段时间以后,还需要翻越一堵高墙,那就是命名空间,而且有了前面的“容易上手”的印象作为铺垫,后期的学习会更加困难。Laravel 5 把命名空间全部隔开,控制器在 `\App\Http\Controllers`,模型在 `\App`,让我们在刚上手的时候就体验命名空间分离的感觉,总体上其实是会降低学习成本的。

2. 控制器

我们可以使用 Artisan 非常方便地构建控制器:

php artisan make:controller Admin/AdminHomeController

得到 `learnlaravel5/app/Http/Controllers/Admin/AdminHomeController.php` 文件。

在 `class AdminHomeController extends Controller {` 上面增加一行:

use App\Page;

修改 index() 的代码如下:

public function index()
{
  return view('AdminHome')->withPages(Page::all());
}

控制器中文文档:http://laravel-china.org/docs/5.0/controllers

控制器中涉及到了许多的命名空间知识,可以参考 PHP 命名空间 解惑

3. 视图

新建 `learnlaravel5/resources/views/AdminHome.blade.php`:

@extends('app')

@section('content')
<div class="container">
  <div class="row">
    <div class="col-md-10 col-md-offset-1">
      <div class="panel panel-default">
        <div class="panel-heading">后台首页</div>

        <div class="panel-body">

        <a href="{{ URL('admin/pages/create') }}" class="btn btn-lg btn-primary">新增</a>

          @foreach ($pages as $page)
            <hr>
            <div class="page">
              <h4>{{ $page->title }}</h4>
              <div class="content">
                <p>
                  {{ $page->body }}
                </p>
              </div>
            </div>
            <a href="{{ URL('admin/pages/'.$page->id.'/edit') }}" class="btn btn-success">编辑</a>

            <form action="{{ URL('admin/pages/'.$page->id) }}" method="POST" style="display: inline;">
              <input name="_method" type="hidden" value="DELETE">
              <input type="hidden" name="_token" value="{{ csrf_token() }}">
              <button type="submit" class="btn btn-danger">删除</button>
            </form>
          @endforeach

        </div>
      </div>
    </div>
  </div>
</div>
@endsection

视图的基本用法在此不再赘述,请阅读中文文档:http://laravel-china.org/docs/5.0/views

访问 http://fuck.io:88/admin 得到如下页面:

Image

至此,包含 路由 》 控制器 》 模型 》 视图 的整个流程都已经完成。

4. 完成 Pages 管理功能

接下来,我将记录下我实现 Pages 管理功能的过程,不再做过多的阐述。大家有问题可以直接在本文下面留言,我会及时回复。

4.1 修改路由 learnlaravel5/app/Http/routes.php

Route::group(['prefix' => 'admin', 'namespace' => 'Admin'], function()
{
  Route::get('/', 'AdminHomeController@index');
  Route::resource('pages', 'PagesController');
});

此处增加了一条“资源控制器”,中文文档地址:http://laravel-china.org/docs/5.0/controllers#restful-resource-controllers

4.2 创建 learnlaravel5/app/Http/Controllers/Admin/PagesController.php

运行:

php artisan make:controller Admin/PagesController

4.3 修改 learnlaravel5/app/Http/Controllers/Admin/PagesController.php 为:

<?php namespace App\Http\Controllers\Admin;

use App\Http\Requests;
use App\Http\Controllers\Controller;

use Illuminate\Http\Request;

use App\Page;

use Redirect, Input, Auth;

class PagesController extends Controller {

	/**
	 * Show the form for creating a new resource.
	 *
	 * @return Response
	 */
	public function create()
	{
		return view('admin.pages.create');
	}

	/**
	 * Store a newly created resource in storage.
	 *
	 * @return Response
	 */
	public function store(Request $request)
	{
		$this->validate($request, [
			'title' => 'required|unique:pages|max:255',
			'body' => 'required',
		]);

		$page = new Page;
		$page->title = Input::get('title');
		$page->body = Input::get('body');
		$page->user_id = 1;//Auth::user()->id;

		if ($page->save()) {
			return Redirect::to('admin');
		} else {
			return Redirect::back()->withInput()->withErrors('保存失败!');
		}

	}

	/**
	 * Show the form for editing the specified resource.
	 *
	 * @param  int  $id
	 * @return Response
	 */
	public function edit($id)
	{
		return view('admin.pages.edit')->withPage(Page::find($id));
	}

	/**
	 * Update the specified resource in storage.
	 *
	 * @param  int  $id
	 * @return Response
	 */
	public function update(Request $request,$id)
	{
		$this->validate($request, [
			'title' => 'required|unique:pages,title,'.$id.'|max:255',
			'body' => 'required',
		]);

		$page = Page::find($id);
		$page->title = Input::get('title');
		$page->body = Input::get('body');
		$page->user_id = 1;//Auth::user()->id;

		if ($page->save()) {
			return Redirect::to('admin');
		} else {
			return Redirect::back()->withInput()->withErrors('保存失败!');
		}
	}

	/**
	 * Remove the specified resource from storage.
	 *
	 * @param  int  $id
	 * @return Response
	 */
	public function destroy($id)
	{
		$page = Page::find($id);
		$page->delete();

		return Redirect::to('admin');
	}

}

4.4 创建视图文件

首先在 learnlaravel5/resources/views 下创建 admin/pages 两级文件夹。

然后创建 learnlaravel5/resources/views/admin/pages/create.blade.php:

@extends('app')

@section('content')
<div class="container">
  <div class="row">
    <div class="col-md-10 col-md-offset-1">
      <div class="panel panel-default">
        <div class="panel-heading">新增 Page</div>

        <div class="panel-body">

          @if (count($errors) > 0)
            <div class="alert alert-danger">
              <strong>Whoops!</strong> There were some problems with your input.<br><br>
              <ul>
                @foreach ($errors->all() as $error)
                  <li>{{ $error }}</li>
                @endforeach
              </ul>
            </div>
          @endif

          <form action="{{ URL('admin/pages') }}" method="POST">
            <input type="hidden" name="_token" value="{{ csrf_token() }}">
            <input type="text" name="title" class="form-control" required="required">
            <br>
            <textarea name="body" rows="10" class="form-control" required="required"></textarea>
            <br>
            <button class="btn btn-lg btn-info">新增 Page</button>
          </form>

        </div>
      </div>
    </div>
  </div>
</div>
@endsection

之后创建 learnlaravel5/resources/views/admin/pages/edit.blade.php:

@extends('app')

@section('content')
<div class="container">
  <div class="row">
    <div class="col-md-10 col-md-offset-1">
      <div class="panel panel-default">
        <div class="panel-heading">编辑 Page</div>

        <div class="panel-body">

          @if (count($errors) > 0)
            <div class="alert alert-danger">
              <strong>Whoops!</strong> There were some problems with your input.<br><br>
              <ul>
                @foreach ($errors->all() as $error)
                  <li>{{ $error }}</li>
                @endforeach
              </ul>
            </div>
          @endif

          <form action="{{ URL('admin/pages/'.$page->id) }}" method="POST">
            <input name="_method" type="hidden" value="PUT">
            <input type="hidden" name="_token" value="{{ csrf_token() }}">
            <input type="text" name="title" class="form-control" required="required" value="{{ $page->title }}">
            <br>
            <textarea name="body" rows="10" class="form-control" required="required">{{ $page->body }}</textarea>
            <br>
            <button class="btn btn-lg btn-info">编辑 Page</button>
          </form>

        </div>
      </div>
    </div>
  </div>
</div>
@endsection

4.5 查看结果

后台首页 http://fuck.io:88/admin

Image

新增 Page http://fuck.io:88/admin/pages/create

Image

编辑 Page http://fuck.io:88/admin/pages/1/edit

Image

页面上的新增、编辑、删除的功能均已经完成,并且加入了表单验证,Pages 管理功能完成!



教程(二)代码快照:https://github.com/johnlui/Learn-Laravel-5/archive/tutorial_2.zip


下一步:Laravel 5 系列入门教程(三)【最适合中国人的 Laravel 教程】

WRITTEN BY

avatar

评论:

小菜鸟
2015-06-11 18:20
你好    我想知道你既然use App\Page   然后还调用了Page::all()  我想知道这个Page在什么位置    我找不到all方法啊
JohnLui
2015-06-11 21:01
@小菜鸟:Page 在 app/Page.php 文件。all() 由 Eloquent 类提供。
sly
2015-06-08 11:43
为什么打开输入admin网页一片空白
Qi
2015-06-06 15:57
钻了牛角尖,有点疑惑
Controller类中直接使用的view()函数怎么引入的? 在哪儿定义的?
use Redirect, Input, Auth; 这几个类具体的定义在哪儿?
求解
JohnLui
2015-06-06 16:38
@Qi:view() 就是全局函数呀

下面类的定义在 config/app.php 中可以找到,使用了别名。
MrA
2015-06-06 10:14
这种用法是个什么鬼,没见过
PagesController的store方法中:
$page = new Page;  为嘛能省略后面的括号?
MrA
2015-06-06 09:56
您好,请教个问题
<a href="{{ URL('admin/pages/'.$page->id.'/edit') }}" class="btn btn-success">编辑</a> 实现编辑功能,编辑id号为$page->id的page
路由到PagesController的edit($id)方法,将$page->id作为参数传入,
貌似过程是这样的
比较疑惑,既然要将$page->id作为参数传递给PagesController的edit($id)方法,
为何参数存在 URL('admin/pages/'.$page->id.'/edit') 这么奇怪的表示? 如何将这个$page->id解析给edit($id)方法的?
JohnLui
2015-06-06 11:05
@MrA:资源控制器会自动解析
redsword
2015-06-05 19:17
请问laravel如何在控件函数中实现多表格查询传入视图?用where函数吗?求例子
自撰一例,假设Article表中有个Atitle值且unique,我想找到Page表的title和Article表中Atitle相等的数据,然后传入视图edit处理:
use App\Page;
use App\Article;
..
public function edit($id)
    {
        return view('admin.pages.edit')->withPage(Page::find($id))->withArticle(Article::where($title,'=',Page::find($id)->title));
    }
这条语句肯定不能执行,正确的查找方式应该是怎样的呢?请博主教我。
JohnLui
2015-06-05 19:25
@redsword:这条语句可以执行呀,只是后面一条写的有问题。。。。

不过应该减少查询次数:

$page = Page::find($id);
$article = Article::where('title', $page->title)->first();

return view('admin.pages.edit')->withPage($page)->withArticle($article);
redsword
2015-06-05 19:33
@JohnLui:回复好快!
多谢释疑。where也能够连用吗?如果我要同时满足两个查询条件,比如要求title和body都相等,该怎么写?
$article = Article::where('title', $page->title)->where('body',$page->body)-->first();
JohnLui
2015-06-05 20:16
@redsword:just try it
redsword
2015-06-05 22:09
@JohnLui:不能用::,要用->
$page = Page::find($id);
$article = Article::where('title', $page->title)->where('body', $page->body)->first();
return view('admin.pages.edit')->withPage($page)->withArticle($article);
redsword
2015-06-05 11:32
create.blade.php 中 <form action="{{ URL('admin/pages') }}" method="POST"> 表示向'admin/pages'发送表单数据,
在相应的PagesController.php 的store函数中,
if ($page->save()) {
            return Redirect::to('admin');
表示如果存储成功则回到~/admin页面下。
但是我的程序在点击页面上的“新增 Page”按钮后,却跳到了“~/admin/pages/"这个地址,这是怎么回事?
PagesController和create view里的转向和表头我都是照着教程来的啊。
JohnLui
2015-06-05 11:53
@redsword:<a href="{{ URL('admin/pages/create') }}" class="btn btn-lg btn-primary">新增</a>

检查一下这句
redsword
2015-06-05 14:48
@JohnLui:多谢回复,一个类似的问题:
在AdminHome.blade.php中
<a href="{{ URL('admin/pages/'.$page->id.'/edit') }}" class="btn btn-success">编辑</a>
定义了”编辑“按钮的转向地址是带id的。
对应的PagesController.php的edit函数只简单定义了视图:
return view('admin.pages.edit')->withPage(Page::find($id));
没有”pages/“和”/edit“之间的”$page->id“。
那么当点击编辑按钮,编辑 Page的页面 http://fuck.io:88/admin/pages/1/edit 是如何知道要转向
admin.pages.edit  而不是 admin.pages.1.edit 的?

这中间的转换过程我没搞明白,试着在别的项目上实现类似功能时,得到提示 admin.pages.1.edit not found.
请问如何解决?
JohnLui
2015-06-05 18:36
@redsword: 这是个很简单的逻辑,你需要仔细观察一下。。。
小白
2015-07-27 18:33
@redsword:想通之后望指教。
fiona
2015-06-01 09:59
非常感谢您的教程
有一个问题就是,当我在使用嵌套资源控制器的时候,show($id) 这个函数传入的$id依然是第一个资源控制器的$id而不是嵌套之后的。
比如链接是 localhost/people/bob/photo/0001  people是一个资源控制器,photo是嵌套的资源控制器,在photoController里面,show($id)的$id依然是bob, 但是我想要的是0001,这个有办法解决么,谷歌没有谷歌出来。
谢谢啦
JohnLui
2015-06-01 23:13
@fiona:"photo是嵌套的资源控制器" 资源控制器不能嵌套,统一前缀可以用路由组。
初来乍到
2015-05-30 12:00
大神我们交朋友吧!我的qq号:1291492301
MisterChen
2015-05-25 20:57
我想请问这个:URL('admin/pages/'.$page->id)
这个是什么意思,有这个文件吗?
JohnLui
2015-05-25 21:19
@MisterChen:这是生成一个链接的意思,网页链接,不是下载
Kompyuter.Biz
2015-05-22 17:12
好不容易配置,终于配好了,教程一  里的所有测试都通过了,然后按教程步骤走,走到 "3. 视图" 把视图文件创建好了以后,浏览器输入http://localhost:8000/admin 页面就提示了:Page not found: /admin,然后我在输入了教程一 中的 http://localhost:8000/home 一样提示 Page not found: /home;
找来找去、不知道那出了问题?
JohnLui
2015-05-22 19:48
@Kompyuter.Biz:伪静态问题,试试 http://localhost:8000/index.php/home
Mary
2015-05-21 09:09
博主你好,我来求救
Route::controllers([                              
    'auth' => 'Auth\AuthController',
    'password' => 'Auth\PasswordController',
]);
1、这个路由怎么表示的?
2、请求:auth/login 是登入首页,那是通过这个路由控制的( 'auth' => 'Auth\AuthController',)?
3、我看了位于 Auth 下的控制器 AuthController.php, 开面并没有 渲染登入页面啊。
4、(1)控制器 AuthController.php 中引用了 “use AuthenticatesAndRegistersUsers ”,我把这句话注释了,页面出错
       (2)可是我找到对应的 “Illuminate\Foundation\Auth” 下的 “AuthenticatesAndRegistersUsers.php” ,把 “trait AuthenticatesAndRegistersUsers   ”注释了或者把整个页面注释了,为什么页面不会出错。
JohnLui
2015-05-21 15:40
@Mary:这是控制器路由:http://laravel-china.org/docs/5.0/controllers#implicit-controllers
然后你需要去了解一下 PHP 的 trait
瞌睡o0
2015-05-19 11:38
博主你好,为什么搭建laravel5成功后,进不了phpMydamin
JohnLui
2015-05-19 11:41
@瞌睡o0:
瞌睡o0
2015-05-19 11:43
@JohnLui:报错提示   NotFoundHttpException in compiled.php line 7793:
新手求指导
JohnLui
2015-05-19 11:48
@瞌睡o0:哥,给 Laravel 分配一个独立端口吧,对于你现在的水平来讲最省时间
kingopq
2015-05-17 20:02
博主你好,为什么我的页面显示的样式不是bootstrap的
JohnLui
2015-05-19 11:48
@kingopq:我也不知道呀~
xuxuxumayi
2015-05-25 18:56
@JohnLui:我要是层主,分分钟打爆楼主 - -
新手  继续学习中
Pierre
2015-05-13 00:10
@JohnLui,
edit.blade.php 照copy你的代码,点击“edit”按钮出现错误,链接指向了:
http://localhost/admin/pages12/edit
而改成http://localhost/admin/pages/12/edit则可以。

代码没有改动:
          <form action="{{ URL('admin/pages/'.$page->id) }}" method="POST">
......
请帮忙解疑。
JohnLui
2015-05-13 10:53
@Pierre:代码没有问题
Pierre
2015-05-13 11:36
@JohnLui:是的,我也觉得代码没有问题。
但在点击“编辑”的时候发现链接指向变成这个http://localhost/admin/pages12/edit(这里有疑问)。
手动将URL改成http://localhost/admin/pages/12/edit,则可以打开。
看上去像是把<form action="{{ URL('admin/pages/'.$page->id) }}" method="POST">
这里的pages后面的“/”自动给清除掉了。
不知道是我环境设置上有问题还是其他原因?
JohnLui
2015-05-13 12:21
@Pierre:我觉得更大的可能性是搞错了文件
qkl
2015-05-27 19:43
@Pierre:我也出现同样的问题
http://172.16.4.203/admin/pages/5/edit     这个就可以访问

http://172.16.4.203/admin/pages5/edit 这个直接报:
Sorry, the page you are looking for could not be found.

不知道楼主这个问题  如何解决的?


sorry,我发现了这个错误是代码抄写错误导致!
AdminHome.blade.php这个文件中:
action="{{ URL('admin/pages/'.$page->id) }}"
楼主应该少了个斜杠,在pages后
flyfish
2015-06-19 17:08
@qkl:楼主的代码没有问题。。。
戈乾
2015-05-12 22:50
大神,1,SQLSTATE[42000]: Syntax error or access violation: 1103 Incorrect table name 'pages '
            2.SQLSTATE[42000]: Syntax error or access violation: 1103 Incorrect table name 'pages ' (SQL: select count(*) as aggregate from `pages ` where `title` = 33)
这两个错误意思是表不能用么
JohnLui
2015-05-13 10:53
@戈乾:'pages ' 多了个空格。目测你在 Model 里面指定表名,多打了个空格。
luis
2015-05-07 14:47
为什么新增文章的时候:<form action="{{ URL('admin/pages') }}" method="POST">,没有指定是admin/pages下面的store方法,它就提交到这个方法了呢,是根据 public function store(Request $request)这个参数吗?是的话那我重写一个方法参数也是这样的会有问题吗?
JohnLui
2015-05-07 14:52
@luis: 看这里:http://laravel-china.org/docs/5.0/controllers#restful-resource-controllers
ZRJ
2015-05-07 09:32
$page = Page::find($id);

这一行,在 update 和 delete 方法中,不检查返回值是否为空吗?
JohnLui
2015-05-07 11:05
@ZRJ:不用检查,因为链接是之前生成的,系统里面会有数据。如果现实中出现多人同时对同一个资源进行编辑,那说明业务流程有问题
ZRJ
2015-05-07 11:06
@JohnLui:如果是手工构造的请求呢
JohnLui
2015-05-07 11:53
@ZRJ: 直接 Whoops
nickwang
2015-04-27 18:17
FatalErrorException in BooksController.php line 44: Class 'App\Http\Controllers\Admin\Input' not found
新增之后,报错了
JohnLui
2015-04-27 18:29
@nickwang:头部没有 use Input;
nickwang
2015-04-27 18:58
@JohnLui:哦哦,太粗心了,程序员大忌
蒙大拿小子
2015-04-27 10:24
报错app\Page 找不到
FatalErrorException in AdminHomeController.php line 20:
Class 'App\Page' not found
<?php
namespace App\Http\Controllers\Admin;

use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Page;

use Illuminate\Http\Request;

class AdminHomeController extends Controller {

    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {
        //
        return view('AdminHome')->withPages(Page::all());
    }
JohnLui
2015-04-27 12:24
@蒙大拿小子:说明在教程一中你创建 Page 模型没有成功
蒙大拿小子
2015-04-27 12:36
@JohnLui:啊哈~真的是哇,感谢哈~太粗心了
redsword
2015-06-05 09:24
@JohnLui:请问怎么在laravel里判断和存储单选按钮组的值?例如:
<form action="{{ URL(admin/answer) }}" method="POST">
<input type="radio" name="Q1"  value="" />1
<input type="radio" name="Q1" value=""  />2
<input type="radio" name="Q1" value=""  />3
</form>

我怎么在控制器的store函数里得到用户的选择值并储存呢?
JohnLui
2015-06-05 11:11
@redsword:Input::get('Q1')

会得到用户选中的那个选项的 value 值。

发表评论:

© 2011-2019 岁寒  |  Powered by Emlog