Laravel 學習筆記(10) - 第一個小專案:微型部落格

Laravel Example

綜合前面說到的內容,就可以來練習第一個小專案:微型部格格。

先來描述一下要完成的功能:
  • 首頁顯示文章的清單,只顯示標題
  • [標題]連結,開啟文章內容
  • [新增]連結,開啟表單頁面新增內容
  • [編輯]連結,緊接著標題,開啟表單頁面編輯內容
  • [刪除]連結,在編輯頁面中,可刪除文章

顯示文章清單

1.app/routes.php

Route::get('post', 'HomeController@index');
對應網址:http://localhost/blog/public/post

2.app/controllers/HomeController.php

public function index()
{
    $posts = Post::all();

    return View::make('home')
        ->with('title', 'My Blog')
        ->with('posts', $posts);
}
Post 是我們的 model ,對應到資料表 posts,使用 all() 方法來取出全部的資料。
等效SQL:
select * from `posts`;
回傳值會是一個陣列,所以我們的變數名稱以複數表示 $posts。最後傳送給 view 去顯示。

3.app/views/home.blade.php

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ $title }}</title>
</head>
<body>
    <h1>{{ $title }}</h1>
    <div>{{ link_to('post/create', '新增') }}</div>
    @if (isset($posts))
        <ol>
        @foreach ($posts as $post)
            <li>{{ link_to('post/'.$post->id, $post->title) }}
            ({{ link_to('post/'.$post->id.'/edit', '編輯') }})</li>
        @endforeach
        </ol>
    @endif
</body>
</html>
@if ... @endif 是 blade 樣板系統的 if 語法。@foreach ... @endforeach 則是迴圈,功能都和 php 相同。因為我們還沒有新增任何文章,所以必須檢查 isset($posts),才不會出錯。

使用 {{}} 來顯示資料。$posts 中儲存的是 Post 物件的以變數 $post 表示,可以取出它的屬性,例如標題 $post->title

link_to('連結位址', '顯示的文字'); 可以產生 HTML 中的 a 連結標籤。

當你新增一筆資料後,看起來會像這樣: 接下來,我們來讓"新增"的功能可以動作。

新增文章

1.app/routes.php

Route::get('post/create', 'HomeController@create');

2.app/controllers/HomeController.php

public function create()
{
    return View::make('create')
            ->with('title', '新增文章');
}
新增一個 create() 方法,回傳一個 view,這個 view 會有一個表單來新增文章。

3.新增 app/views/create.blade.php

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ $title }}</title>
</head>
<body>
    <h1>{{ $title }}</h1>
    {{Form::open(['url'=>'post', 'method'=>'post'])}}
    {{Form::label('title', '標題')}}<br>
    {{Form::text('title')}}<br>
    {{Form::label('content', '內容')}}<br>
    {{Form::textarea('content')}}<br>
    {{Form::submit('發表文章')}}
    {{Form::close()}}
</body>
</html>
看起來會像這樣: 接下來要取得表單資料並儲存到資料庫。

4.app/routes.php

Route::post('post', 'HomeController@store');
這裡的 Route::post() 就是表單中的 'url'=>'post' 所傳送的位址。

5.app/controllers/HomeController.php

public function store()
{
    $input = Input::all();

    $post = new Post;
    $post->title = $input['title'];
    $post->content = $input['content'];
    $post->save();

    return Redirect::to('post');
}
結合在 Model 一篇所學到的概念,將取得的值存入資料庫。
先 new 一個 Post 物件出來,接著將值指定給 $post 的屬性,最後 save() 就新增到資料庫了。

最後使用 Redirect::to('post') 導向首頁。

顯示內容

現在要讓文章的標題被點選後,顯示文章的內容。

1.app/routes.php

Route::get('post/{id}', 'HomeController@show');

2.app/controllers/HomeController.php

public function show($id)
{
    $post = Post::find($id);

    return View::make('show')
        ->with('title', 'My Blog - '. $post->title)
        ->with('post', $post);
}

3.app/views/show.blade.php

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ $title }}</title>
</head>
<body>
    @if (isset($post))
        <h1>{{ $post->title }}</h1>
        <p>{{ $post->content }}</p>
    @endif

    {{ link_to(URL::previous(), '回上一頁') }}
</body>
</html>
為了避免發生錯誤,在 blade 中可以使用 @if@endif 的方式來處理條件,假如 $post 有被建立,才顯示其內容。最後面我們加了一個"回上一頁"的連結。

結果畫面:

修改內容

1.app/routes.php

Route::get('post/{id}/edit', 'HomeController@edit');
這裡的 post/{id}/edit 是對應到前面我們所寫的
{{ link_to('post/'.$post->id.'/edit', '編輯') }}

2.app/controllers/HomeController.php

public function edit($id)
{
    $post = Post::find($id);

    return View::make('edit')
            ->with('title', '編輯文章')
            ->with('post', $post);
}
使用 $id 找到這篇文章,將它送給 view。

3.app/views/edit.blade.php

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ $title }}</title>
</head>
<body>
    <h1>{{ $title }}</h1>
    {{Form::open(['url'=>'post/'.$post->id, 'method'=>'put'])}}
    {{Form::label('title', '標題')}}<br>
    {{Form::text('title', $post->title)}}<br>
    {{Form::label('content', '內容')}}<br>
    {{Form::textarea('content', $post->content)}}<br>
    {{Form::submit('儲存')}}
    {{Form::close()}}
</body>
</html>
這裡和 create.blade.php 大同小異,差別在:
  1. url 改為 post/id 的型式,id 就是 $post 變數中 Post 物件的 id 屬性。
  2. form 的 method 要改成 put。
  3. Form::textForm::textarea 的第二個參數要給值。
結果畫面: 接著就是儲存資料。

4.app/routes.php

Route::put('post/{id}', 'HomeController@update');
你會看到這個 route 是 put 並且網址為 post/{id},這就是為什麼表單 url 及 method 要修改的理由。

5.app/controllers/HomeController.php

public function update($id)
{
    $input = Input::all();

    $post = Post::find($id);
    $post->title = $input['title'];
    $post->content = $input['content'];
    $post->save();

    return Redirect::to('post');
}
update($id) 方法中,使用 find($id) 去找出這筆資料,並重新指定內容,save() 後就會對資料庫送出更新的動作。

什麼都有了,就是不能刪除,把它加入吧~

刪除內容

1.app/routes.php

Route::delete('post/{id}', 'HomeController@destroy');

2.app/controllers/HomeController.php

public function destroy($id)
{
    $post = Post::find($id);
    $post->delete();

    return Redirect::to('post');
}
一樣,先找到這筆資料,然後刪除。

3.app/views/edit.blade.php

刪除的做法有點醜,要用到表單,先不管。把它加在原有表單後後面:
//...略
<br>
{{ Form::open(['url'=>'post/'.$post->id, 'method'=>'delete']) }}
    <button type="submit">刪除</button>
{{ Form::close() }}
現在你已經可以刪除內容了。

總結

一路寫下來,你會發現 Route -> Controller (Model) -> View 這樣的開發流程,只要一直重覆這個流程,功能就會慢慢完成。

這裡面其實還有一些技巧,可以讓程式碼更精簡,讓你寫的更少。
本文網址:http://blog.tonycube.com/2015/01/laravel-10.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

7 則留言

  1. 你好~不好意思~ 我之前學的語法如下:
    <button type="submit" class="btn btn-success" onclick="javascript:location='user/login';">註冊</button>
    是打算按下按鈕,會傳值以及跳到login介面,如果要以laravel的導向來使用的話,是在route、controller都還要另外加語法來呼叫嗎? 那該怎麼使用呢? 因為嘗試過你上面的寫法 但還是Error。

    回覆刪除
    回覆
    1. 你用 onclick 的話,submit 的作用就會被取代,表單就不會送出去。
      你所謂的傳值,應該是把註冊資料送到後端,儲存後才轉向 login 介面吧,假設是這樣,
      那你就必須 submit 你的資料,然後用 controller 去接值,做儲存之類的動作,
      再重新導向 login 頁面。

      在 controller 中,用
      return Redirect::to('user/login');
      就會導向你要的頁面。

      所以是
      button -> submit -> 傳值給 controller -> 處理後重新導向 user/login

      刪除
  2. 作者已經移除這則留言。

    回覆刪除
  3. public function update(Request $request)
    {
    $input = $request->all();
    $post = Post::find($id); //??這裡怎麼寫?
    $post->title = $input['title'];
    $post->content = $input['content'];
    $post->save();
    return Redirect('post');
    }

    update也修正但是也是卡在id


    ErrorException (E_NOTICE)
    Undefined variable: id

    回覆刪除
    回覆
    1. 假設你的 Route 是
      Route::put('/update/{id}', 'XxxController@update');

      在 XxxController 裡面的對應方法就會是

      public function update(Request $request, $id)
      {
          // 直接使用傳入的 id 來找資料
          $post = Post::find($id);

          // 取得表單傳入的資料將其更新
          $input = $request->all();
          $post->title = $input['title'];
          ....
          $post->save();
          ....
      }

      刪除
  4. 作者已經移除這則留言。

    回覆刪除

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。