CakePHP系列(二)----博客(Blog)案例(三)

创建一个树类


让我们继续完善我们的博客应用程序,想象我们想要分类我们的文章。 我们想要对类别进行排序,为此,我们将使用Tree行为来帮助我们组织类别。

但首先,我们需要修改我们的表。


我们将使用migrations插件在我们的数据库中创建一个表。 如果您的数据库中已有文章表,请将其清除。

现在打开你的应用程序的composer.json文件。 通常你会看到migrations插件已经在require下。 如果没有,请通过执行以下命令添加:

composer require cakephp/migrations:~1.0

迁移插件现在将位于应用程序的插件文件夹中。 另外,添加Plugin::load('Migrations'); 到您的应用程序的bootstrap.php文件。

加载插件后,运行以下命令创建迁移文件:

bin/cake bake migration CreateArticles title:string body:text category_id:integer created modified

将在/ config / Migrations文件夹中生成一个迁移文件,其中包含以下内容:

<?php

use Migrations\AbstractMigration;

class CreateArticles extends AbstractMigration
{
    public function change()
    {
        $table = $this->table('articles');
        $table->addColumn('title', 'string', [
            'default' => null,
            'limit' => 255,
            'null' => false,
        ]);
        $table->addColumn('body', 'text', [
            'default' => null,
            'null' => false,
        ]);
        $table->addColumn('category_id', 'integer', [
            'default' => null,
            'limit' => 11,
            'null' => false,
        ]);
        $table->addColumn('created', 'datetime', [
            'default' => null,
            'null' => false,
        ]);
        $table->addColumn('modified', 'datetime', [
            'default' => null,
            'null' => false,
        ]);
        $table->create();
    }
}

运行其他命令以创建categories表。 如果需要指定字段长度,可以在字段类型的括号内进行,即:

bin/cake bake migration CreateCategories parent_id:integer lft:integer[10] rght:integer[10] name:string[100] description:string created modified

这将在config / Migrations中生成以下文件:

<?php

use Migrations\AbstractMigration;

class CreateCategories extends AbstractMigration
{
    public function change()
    {
        $table = $this->table('categories');
        $table->addColumn('parent_id', 'integer', [
            'default' => null,
            'limit' => 11,
            'null' => false,
        ]);
        $table->addColumn('lft', 'integer', [
            'default' => null,
            'limit' => 10,
            'null' => false,
        ]);
        $table->addColumn('rght', 'integer', [
            'default' => null,
            'limit' => 10,
            'null' => false,
        ]);
        $table->addColumn('name', 'string', [
            'default' => null,
            'limit' => 100,
            'null' => false,
        ]);
        $table->addColumn('description', 'string', [
            'default' => null,
            'limit' => 255,
            'null' => false,
        ]);
        $table->addColumn('created', 'datetime', [
            'default' => null,
            'null' => false,
        ]);
        $table->addColumn('modified', 'datetime', [
            'default' => null,
            'null' => false,
        ]);
        $table->create();
    }
}

现在已创建迁移文件,您可以在创建表之前对其进行编辑。 我们需要将parent_id字段的'null' => false更改为'null' => true ,因为顶级类别的parent_id为null。

运行以下命令创建表:

bin/cake migrations migrate

修改表


随着我们的表设置,我们现在可以专注于分类我们的文章。

我们假设你已经有第2部分的文件(表,控件和模板的文章)。所以我们只是添加对类别的引用。

我们需要将文章和类别表关联起来。 打开src / Model / Table / ArticlesTable.php文件并添加以下内容:

// src/Model/Table/ArticlesTable.php

namespace App\Model\Table;

use Cake\ORM\Table;

class ArticlesTable extends Table
{
    public function initialize(array $config)
    {
        $this->addBehavior('Timestamp');
        // Just add the belongsTo relation with CategoriesTable
        $this->belongsTo('Categories', [
            'foreignKey' => 'category_id',
        ]);
    }
}


生成框架类别代码


通过启动Bake命令创建所有文件:

bin/cake bake model Categories
bin/cake bake controller Categories
bin/cake bake template Categories

或者,你可以只用一行Bake执行所有:

bin/cake bake all Categories

Bake工具已经创建了所有的文件。 如果你想重新熟悉CakePHP的工作原理,你可以给他们一个快速阅读。

▲ 注意: 如果你在Windows上,记得使用\而不是/。

您需要在 src / Template / Categories / add.ctp src / Template / Categories / edit.ctp中编辑 以下内容:

echo $this->Form->input('parent_id', [
    'options' => $parentCategories,
    'empty' => 'No parent category'
]);



将TreeBehavior附加到CategoriesTable


TreeBehavior帮助您管理数据库表中的分层树结构。 它使用MPTT逻辑来管理数据。 MPTT树结构针对读取进行了优化,这通常使得它们非常适合阅读诸如博客的重型应用程序。

如果打开src / Model / Table / CategoriesTable.php文件,您将看到TreeBehavior已在initialize()方法中附加到您的CategoriesTable。 Bake将此行为添加到包含lftrght列的任何表:

$this->addBehavior('Tree');

通过附加TreeBehavior,您将能够访问一些功能,如重新排序类别。 我们会看到这一刻。

但是现在,您必须在类别添加和编辑模板文件中删除以下输入:

echo $this->Form->input('lft');
echo $this->Form->input('rght');

此外,您应该从CategoriesTable模型中的lft和rght列的验证器中禁用或除去requirePresence:


public function validationDefault(Validator $validator)
{
    $validator
        ->add('id', 'valid', ['rule' => 'numeric'])
        ->allowEmpty('id', 'create');

    $validator
        ->add('lft', 'valid', ['rule' => 'numeric'])
    //    ->requirePresence('lft', 'create')
        ->notEmpty('lft');

    $validator
        ->add('rght', 'valid', ['rule' => 'numeric'])
    //    ->requirePresence('rght', 'create')
        ->notEmpty('rght');
}

当保存类别时,这些字段由TreeBehavior自动管理。

使用网络浏览器,使用/yoursite/categories/add controller操作添加一些新类别。


使用TreeBehavior重新排序类别


在类别索引模板文件中,您可以列出类别并对其重新排序。

让我们修改你的CategoriesController.php中的索引方法,并添加moveUp()moveDown()方法,以便能够重新排序树中的类别:

class CategoriesController extends AppController
{
    public function index()
    {
        $categories = $this->Categories->find()
            ->order(['lft' => 'ASC']);
        $this->set(compact('categories'));
        $this->set('_serialize', ['categories']);
    }

    public function moveUp($id = null)
    {
        $this->request->allowMethod(['post', 'put']);
        $category = $this->Categories->get($id);
        if ($this->Categories->moveUp($category)) {
            $this->Flash->success('The category has been moved Up.');
        } else {
            $this->Flash->error('The category could not be moved up. Please, try again.');
        }
        return $this->redirect($this->referer(['action' => 'index']));
    }

    public function moveDown($id = null)
    {
        $this->request->allowMethod(['post', 'put']);
        $category = $this->Categories->get($id);
        if ($this->Categories->moveDown($category)) {
            $this->Flash->success('The category has been moved down.');
        } else {
            $this->Flash->error('The category could not be moved down. Please, try again.');
        }
        return $this->redirect($this->referer(['action' => 'index']));
    }
}

src / Template / Categories / index.ctp中将现有内容替换为:


<div class=>
    <h3><?= __('Actions') ?></h3>
    <ul class="side-nav">
        <li><?= $this->Html->link(__('New Category'), ['action' => 'add']) ?></li>
    </ul>
</div>
<div class="categories index large-10 medium-9 columns">
    <table cellpadding="0" cellspacing="0">
    <thead>
        <tr>
            <th>Id</th>
            <th>Parent Id</th>
            <th>Lft</th>
            <th>Rght</th>
            <th>Name</th>
            <th>Description</th>
            <th>Created</th>
            <th class="actions"><?= __('Actions') ?></th>
        </tr>
    </thead>
    <tbody>
    <?php foreach ($categories as $category): ?>
        <tr>
            <td><?= $category->id ?></td>
            <td><?= $category->parent_id ?></td>
            <td><?= $category->lft ?></td>
            <td><?= $category->rght ?></td>
            <td><?= h($category->name) ?></td>
            <td><?= h($category->description) ?></td>
            <td><?= h($category->created) ?></td>
            <td class="actions">
                <?= $this->Html->link(__('View'), ['action' => 'view', $category->id]) ?>
                <?= $this->Html->link(__('Edit'), ['action' => 'edit', $category->id]) ?>
                <?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $category->id], ['confirm' => __('Are you sure you want to delete # {0}?', $category->id)]) ?>
                <?= $this->Form->postLink(__('Move down'), ['action' => 'moveDown', $category->id], ['confirm' => __('Are you sure you want to move down # {0}?', $category->id)]) ?>
                <?= $this->Form->postLink(__('Move up'), ['action' => 'moveUp', $category->id], ['confirm' => __('Are you sure you want to move up # {0}?', $category->id)]) ?>
            </td>
        </tr>
    <?php endforeach; ?>
    </tbody>
    </table>
</div>

修改ArticlesController


ArticlesController ,我们将得到所有类别的列表。 这将允许我们在创建或编辑文章时为文章选择类别:

// src/Controller/ArticlesController.php

namespace App\Controller;

use Cake\Network\Exception\NotFoundException;

class ArticlesController extends AppController
{

    // ...

    public function add()
    {
        $article = $this->Articles->newEntity();
        if ($this->request->is('post')) {
            $article = $this->Articles->patchEntity($article, $this->request->getData());
            if ($this->Articles->save($article)) {
                $this->Flash->success(__('Your article has been saved.'));
                return $this->redirect(['action' => 'index']);
            }
            $this->Flash->error(__('Unable to add your article.'));
        }
        $this->set('article', $article);

        // Just added the categories list to be able to choose
        // one category for an article
        $categories = $this->Articles->Categories->find('treeList');
        $this->set(compact('categories'));
    }
}

修改文章模板

文章添加文件应该看起来像这样:

<!-- File: src/Template/Articles/add.ctp -->

<h1>Add Article</h1>
<?php
echo $this->Form->create($article);
// just added the categories input
echo $this->Form->input('category_id');
echo $this->Form->input('title');
echo $this->Form->input('body', ['rows' => '3']);
echo $this->Form->button(__('Save Article'));
echo $this->Form->end();

当您访问地址/ yoursite / articles / add时,您应该会看到要选择的类别列表。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值