一、前言

本节教程将大概完成文章和标签管理以及标签关联。

二、Let's go

1.文章管理

首先创建管理后台文章列表视图:

$ php artisan generate:view admin.articles.list

修改views/admin/articles/list.blade.php

@extends('_layouts.default')

@section('main')
<div class="am-g am-g-fixed blog-g-fixed">
<div class="am-u-sm-12">
<table class="am-table am-table-hover am-table-striped ">
<thead>
<tr>
<th>Title</th>
<th>Tags</th>
<th>Author</th>
<th>Managment</th>
</tr>
</thead>
<tbody>
@foreach ($articles as $article)
<tr>
<td><a href="{{ URL::route('article.show', $article->id) }}">{{{ $article->title }}}</a></td>
<td>
@foreach ($article->tags as $tag)
<span class="am-badge am-badge-success am-radius">{{ $tag->name }}</span>
@endforeach
</td>
<td><a href="{{ URL::to('user/' . $article->user->id . '/articles') }}">{{{ $article->user->nickname }}}</a></td>
<td>
<a href="{{ URL::to('article/'. $article->id . '/edit') }}" class="am-btn am-btn-xs am-btn-primary"><span class="am-icon-pencil"></span> Edit</a>
{{ Form::open(array('url' => 'article/' . $article->id, 'method' => 'DELETE', 'style' => 'display: inline;')) }}
<button type="button" class="am-btn am-btn-xs am-btn-danger" id="delete{{ $article->id }}"><span class="am-icon-remove"></span> Delete</button>
{{ Form::close() }}
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
<div class="am-modal am-modal-confirm" tabindex="-1" id="my-confirm">
<div class="am-modal-dialog">
<div class="am-modal-bd">
</div>
<div class="am-modal-footer">
<span class="am-modal-btn" data-am-modal-cancel>No</span>
<span class="am-modal-btn" data-am-modal-confirm>Yes</span>
</div>
</div>
</div>
<script>
$(function() {
$('[id^=delete]').on('click', function() {
$('.am-modal-bd').text('Sure you want to delete it?');
$('#my-confirm').modal({
relatedTarget: this,
onConfirm: function(options) {
$(this.relatedTarget).parent().submit();
},
onCancel: function() {
}
});
});
});
</script>
@stop

nav.blade.php中增加一个Articles的超链接:

<li class="{{ (isset($page) and ($page == 'articles')) ? 'am-active' : '' }}"><a href="{{ URL::to('admin/articles') }}">Articles</a></li>

创建一个管理员控制器,在app/controllers下创建一个名为AdminController.php的文件,修改:

class AdminController extends \BaseController {

    public function articles()
{
return View::make('admin.articles.list')->with('articles', Article::with('user', 'tags')->orderBy('created_at', 'desc')->get())->with('page', 'articles');
}
}

Route::group(array('prefix' => 'admin')中增加:

Route::get('articles', 'AdminController@articles');

管理文章可以重用上节教程写的业务逻辑,修改下ArticleController.php,把destroy()中最后的Redirect::to('home')改成Redirect::back(), 再修改一下home.blade.php,加一个是否是管理员的判断,这样当点击作者跳转到用户主页时,除了作者自己管理员也能操作文章:

@if ($user->id == Auth::id() or (Auth::check() and Auth::user()->is_admin))

现在点击导航栏的Articles,就会出现所有的文章:

这样管理员就可以操作所有的文章了。

我们还可以再修改下admin/users/list.blade.php,当点击用户列表的昵称时也会跳转到用户主页:

<a href="{{ URL::to('user/' . $user->id . '/articles') }}">{{{ $user->nickname }}}</a>

现在访问用户列表页面:

2.显示标签列表

创建一个标签列表视图:

$ php artisan generate:view admin.tags.list

修改admin/tags/list.blade.php

@extends('_layouts.default')

@section('main')
<div class="am-g am-g-fixed blog-g-fixed">
<div class="am-u-sm-12">
<table class="am-table am-table-hover am-table-striped ">
<thead>
<tr>
<th>TagName</th>
<th>ArticleCount</th>
<th>CreateDateTime</th>
<th>Managment</th>
</tr>
</thead>
<tbody>
@foreach ($tags as $tag)
<tr>
<td>{{{ $tag->name }}}</td>
<td>{{ $tag->count }}</td>
<td>{{ $tag->created_at->format('Y-m-d H:i') }}</td>
<td>
<a href="{{ URL::to('tag/'. $tag->id . '/edit') }}" class="am-btn am-btn-xs am-btn-primary"><span class="am-icon-pencil"></span> Edit</a>
{{ Form::open(array('url' => 'tag/' . $tag->id, 'method' => 'DELETE', 'style' => 'display: inline;')) }}
<button type="button" class="am-btn am-btn-xs am-btn-danger" id="delete{{ $tag->id }}"><span class="am-icon-remove"></span> Delete</button>
{{ Form::close() }}
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
<div class="am-modal am-modal-confirm" tabindex="-1" id="my-confirm">
<div class="am-modal-dialog">
<div class="am-modal-bd">
</div>
<div class="am-modal-footer">
<span class="am-modal-btn" data-am-modal-cancel>No</span>
<span class="am-modal-btn" data-am-modal-confirm>Yes</span>
</div>
</div>
</div>
<script>
$(function() {
$('[id^=delete]').on('click', function() {
$('.am-modal-bd').text('Sure you want to delete it?');
$('#my-confirm').modal({
relatedTarget: this,
onConfirm: function(options) {
$(this.relatedTarget).parent().submit();
},
onCancel: function() {
}
});
});
});
</script>
@stop

再在nav.blade.php中增加Tags选项:

<li class="{{ (isset($page) and ($page == 'tags')) ? 'am-active' : '' }}"><a href="{{ URL::to('admin/tags') }}">Tags</a></li>

Route::group(array('prefix' => 'admin')中增加:

Route::get('tags', 'AdminController@tags');

AdminController.php中增加:

public function tags() {
return View::make('admin.tags.list')->with('tags', Tag::all()->orderBy('count', 'desc'));
}

现在点击导航栏上方的Tags超链接:

3.修改标签

创建修改标签的视图:

$ php artisan generate:view tags.edit

修改views/tags/edit.blade.php

@extends('_layouts.default')

@section('main')
<div class="am-g am-g-fixed">
<div class="am-u-sm-12">
<h1>Edit Tag</h1>
<hr/>
@if (Session::has('message'))
<div class="am-alert am-alert-{{ Session::get('message')['type'] }}" data-am-alert>
<p>{{ Session::get('message')['content'] }}</p>
</div>
@endif
@if ($errors->has())
<div class="am-alert am-alert-danger" data-am-alert>
<p>{{ $errors->first() }}</p>
</div>
@endif
{{ Form::model($tag, array('url' => URL::route('tag.update', $tag->id), 'method' => 'PUT', 'class' => "am-form")) }}
<div class="am-form-group">
{{ Form::label('name', 'TagName') }}
{{ Form::text('name', Input::old('name')) }}
</div>
<p><button type="submit" class="am-btn am-btn-success">
<span class="am-icon-pencil"></span> Modify</button>
</p>
{{ Form::close() }}
</div>
</div>
@stop

创建标签控制器:

$ php artisan generate:controller TagsController

修改TagsController.php

public function __construct()
{
$this->beforeFilter('auth', array('only' => array('create', 'store', 'edit', 'update', 'destroy')));
$this->beforeFilter('csrf', array('only' => array('store', 'update', 'destroy')));
} public function edit($id)
{
return View::make('tags.edit')->with('tag', Tag::find($id));
} public function update($id)
{
$rules = array(
'name' => array('required', 'regex:/^\w+$/'),
);
$validator = Validator::make(Input::only('name'), $rules);
if ($validator->passes()) {
Tag::find($id)->update(Input::only('name'));
return Redirect::back()->with('message', array('type' => 'success', 'content' => 'Modify tag successfully'));
} else {
return Redirect::back()->withInput()->withErrors($validator);
}
}

把这个控制器加到routes.php中:

Route::resource('tag', 'TagController');

现在就能修改标签了:

4.删除标签

修改TagsController.php

public function destroy($id)
{
$tag = Tag::find($id);
$tag->count = 0;
$tag->save();
foreach ($tag->articles as $article) {
$tag->articles()->detach($article->id);
}
return Redirect::back();
}

我这里删除标签只是把它的文章数置为0,然后清除与相关文章的关联,你可以自己试下删除一个标签,再看看文章的标签是否去除了。

5.关联标签

当我们点击首页文章、标签栏和显示文章内容的标签的时候应该跳转到显示相应标签下所有文章的页面:

我们对上述地方加上超链接地址:

<a href="{{ URL::to('tag/' . $tag->id . '/articles') }}">{{ $tag->name }}</a>

创建指定标签的文章列表视图:

$ php artisan generate:view articles.specificTag

修改views/articles/specificTag.blade.php

@extends('_layouts.default')

@section('main')
<div class="am-g am-g-fixed">
<div class="am-u-sm-12">
<br/>
<blockquote>Tag: <span class="am-badge am-badge-success am-radius">{{{ $tag->name }}}</span></blockquote>
@foreach ($articles as $article)
<article class="blog-main">
<h3 class="am-article-title blog-title">
<a href="{{ URL::route('article.show', $article->id) }}">{{{ $article->title }}}</a>
</h3>
<h4 class="am-article-meta blog-meta">
by <a href="{{ URL::to('user/' . $article->user->id . '/articles') }}">{{{ $article->user->nickname }}}</a> posted on {{ $article->created_at->format('Y/m/d H:i') }} under
@foreach ($article->tags as $tag)
<a href="{{ URL::to('tag/' . $tag->id . '/articles') }}" style="color: #fff;" class="am-badge am-badge-success am-radius">{{ $tag->name }}</a>
@endforeach
</h4>
<div class="am-g">
<div class="am-u-sm-12">
@if ($article->summary)
<p>{{ $article->summary }}</p>
@endif
<hr class="am-article-divider"/>
</div>
</div>
</article>
@endforeach
{{ $articles->links() }}
</div>
</div>
@stop

TagController.php增加:

public function articles($id)
{
$tag = Tag::find($id);
$articles = $tag->articles()->orderBy('created_at', 'desc')->paginate(10);
return View::make('articles.specificTag')->with('tag', $tag)->with('articles', $articles);
}

routes.phpRoute::resource('tag', 'TagController');的上方增加:

Route::get('tag/{id}/articles', 'TagController@articles');

现在当我们点击页面上的标签时,就会显示该标签下的所有文章了:

6.显示所有标签

我们还需要一个显示所有标签的页面,先创建视图:

$ php artisan generate:view tags.list

修改views/tags/list.blade.php

@extends('_layouts.default')

@section('main')
<div class="am-g am-g-fixed">
<div class="am-u-sm-12">
<h1>All Tags</h1>
<hr/>
@foreach ($tags as $tag)
<a href="{{ URL::to('tag/' . $tag->id . '/articles') }}" class="am-badge am-radius {{ array('', 'am-badge-primary', 'am-badge-secondary', 'am-badge-success', 'am-badge-warning', 'am-badge-danger')[rand(0, 5)] }}">{{{ $tag->name }}} {{ $tag->count }}</a>
@endforeach
<br/>
<br/>
</div>
</div>
@stop

现在点击首页的Tags链接时就会跳转到显示所有标签的页面了:

7.小结

本节教程就到此结束了,这个博客系统想要实现的功能也基本完成了,下节开始将讲解优化、单元测试、部署和扩展开发等内容,你可以继续完善,例如在管理文章和标签的时候提供一个搜索功能,给它们都加上分页,在首页加上一个搜索文章的功能,给文章加上评论功能等等,在评论功能方面现在有很多第三方评论插件,可以快速帮你实现。

最后的代码下载:

$ git clone https://github.com/shiyanlou/laravel-blog-5.git

本文详细出自实验楼

转载请注明出处

 

Laravel大型项目系列教程(五)之文章和标签管理的更多相关文章

  1. Laravel大型项目系列教程(二)之用户管理

    Laravel大型项目系列教程(二) 一.前言 本节教程将大概实现用户的注册.修改个人信息.管理用户功能. 二.Let's go 1.创建用户注册视图 $ php artisan generate:v ...

  2. Laravel大型项目系列教程(三)之发表文章

    Laravel大型项目系列教程(三)之发表文章 一.前言 上一节教程中完成了用户管理,这节教程将大概完成发表Markdown格式文章并展示的功能. 二.Let's go 1.数据库迁移 文章模块中我们 ...

  3. Laravel大型项目系列教程(一)

    Laravel大型项目系列教程(一) 一.课程概述 1.课程介绍 本教程将使用Laravel完成一个多用户的博客系统,大概会包含如下内容: 路由管理. 用户管理,如用户注册.修改信息.锁定用户等. 文 ...

  4. Laravel大型项目系列教程(四)显示文章列表和用户修改文章

    小编心语:不知不觉已经第四部分了,非常感谢很多人给小编提的意见,改了很多bug,希望以后能继续帮小编找找茬~小编也不希望误导大家~这一节,主要讲的 是如何显示文章列表和让用户修改文章,小编预告一下(一 ...

  5. ABP框架搭建项目系列教程基础版完结篇

    返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 经过前面十二篇的基础教程,现在终于该做个总结了. 回顾 第一篇,我们建议新手朋友们先通过ABP官网的启动模板生成解决方案,因为这样 ...

  6. 一步一步使用ABP框架搭建正式项目系列教程之本地化详解

    返回总目录<一步一步使用ABP框架搭建正式项目系列教程> 本篇目录 扯扯本地化 ABP中的本地化 小结 扯扯本地化 本节来说说本地化,也有叫国际化.全球化的,不管怎么个叫法,反正道理都是一 ...

  7. Android Studio系列教程五--Gradle命令详解与导入第三方包

    Android Studio系列教程五--Gradle命令详解与导入第三方包 2015 年 01 月 05 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://s ...

  8. CRL快速开发框架系列教程五(使用缓存)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  9. C#微信公众号开发系列教程五(接收事件推送与消息排重)

    微信公众号开发系列教程一(调试环境部署) 微信公众号开发系列教程一(调试环境部署续:vs远程调试) C#微信公众号开发系列教程二(新手接入指南) C#微信公众号开发系列教程三(消息体签名及加解密) C ...

随机推荐

  1. C#中一些常用的加密和哈希处理

    URL编码,默认UTF8编码方式 /// <summary> /// URL编码,默认UTF8编码方式 /// </summary> /// <param name=&q ...

  2. 【腾讯Bugly干货分享】微信终端跨平台组件 mars 系列(二) - 信令传输超时设计

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/9DJxipJaaBC8yC-buHgnTQ 作者简介: ...

  3. DIP原则、IoC以及DI

    一.DIP原则 高层模块不应该依赖于底层模块,二者都应该依赖于抽象. 抽象不应该依赖于细节,细节应该依赖于抽象. 该原则理解起来稍微有点抽象,我们可以将该原则通俗的理解为:"依赖于抽象&qu ...

  4. 实现了一个百度首页的彩蛋——CSS3 Animation简介

    在百度搜索中有这样一个彩蛋:搜索“旋转”,“跳跃”,“反转”等词语,会出现相应的动画效果(搜索“反转”后的效果).查看源码可以发现,这些效果正是通过CSS3的animation属性实现的. 实现这个彩 ...

  5. ASP.NET Web API Selfhost宿主环境中管道、路由

    ASP.NET Web API Selfhost宿主环境中管道.路由 前言 前面的几个篇幅对Web API中的路由和管道进行了简单的介绍并没有详细的去说明一些什么,然而ASP.NET Web API这 ...

  6. Javascript数组操作

    使用JS也算有段时日,然对于数组的使用,总局限于很初级水平,且每每使用总要查下API,或者写个小Demo测试下才算放心,一来二去,浪费不少时间:思虑下,堪能如此继续之?当狠心深学下方是正道. 原文链接 ...

  7. Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结

    Atitit. 破解  拦截 绕过 网站 手机 短信 验证码  方式 v2 attilax 总结 1. 验证码的前世今生11.1. 第一代验证码 图片验证码11.2. 第二代验证码  用户操作 ,比如 ...

  8. Python初学者之网络爬虫(二)

    声明:本文内容和涉及到的代码仅限于个人学习,任何人不得作为商业用途.转载请附上此文章地址 本篇文章Python初学者之网络爬虫的继续,最新代码已提交到https://github.com/octans ...

  9. Bootstrap3系列:按钮组

    1. 基本实例 1.1 示例代码 <div class="btn-group"> <button type="button" class=&q ...

  10. PHP 面向对象编程和设计模式 (5/5) - PHP 命名空间的使用及名称解析规则

    PHP高级程序设计 学习笔记 2014.06.12 命名空间概述 PHP 在 5.3.0 以后的版本开始支持命名空间.什么是命名空间?从广义上来说,命名空间是一种封装事物的方法.在很多地方都可以见到这 ...