### 创建你的第一个字段集
> module/Blog/src/Form/PostFieldset.php
```
<?php
namespace Blog\Form;
use Zend\Form\Fieldset;
use Blog\Model\Post;
use Zend\Hydrator\Reflection as ReflectionHydrator;
class PostFieldset extends Fieldset
{
public function init()
{
$this->setHydrator(new ReflectionHydrator());
$this->setObject(new Post('', ''));
$this->add([
'type' => 'hidden',
'name' => 'id',
]);
$this->add([
'type' => 'text',
'name' => 'title',
'options' => [
'label' => 'Post Title',
],
]);
$this->add([
'type' => 'textarea',
'name' => 'text',
'options' => [
'label' => 'Post Text',
],
]);
}
}
```
**创建表单类**
> module/Blog/src/Form/PostForm.php
~~~
<?php
namespace Blog\Form;
use Zend\Form\Form;
class PostForm extends Form
{
public function init()
{
$this->add([
'name' => 'post',
'type' => PostFieldset::class,
'options' => [
'use_as_base_fieldset' => true,
],
]);
$this->add([
'type' => 'submit',
'name' => 'submit',
'attributes' => [
'value' => 'Insert new Post',
],
]);
}
}
~~~
### 模型
帖子数据表的增删改查
**帖子命令类**
> module/Blog/src/Model/PostCommand.php
~~~
<?php
namespace Blog\Model;
class PostCommand implements PostCommandInterface
{
/**
* {@inheritDoc}
*/
public function insertPost(Post $post)
{
}
/**
* {@inheritDoc}
*/
public function updatePost(Post $post)
{
}
/**
* {@inheritDoc}
*/
public function deletePost(Post $post)
{
}
}
~~~
**数据库命令类**
> module/Blog/src/Model/ZendDbSqlCommand.php
~~~
<?php
namespace Blog\Model;
use RuntimeException;
use Zend\Db\Adapter\AdapterInterface;
use Zend\Db\Adapter\Driver\ResultInterface;
use Zend\Db\Sql\Delete;
use Zend\Db\Sql\Insert;
use Zend\Db\Sql\Sql;
use Zend\Db\Sql\Update;
class ZendDbSqlCommand implements PostCommandInterface
{
/**
* @var AdapterInterface
*/
private $db;
/**
* @param AdapterInterface $db
*/
public function __construct(AdapterInterface $db)
{
$this->db = $db;
}
/**
* {@inheritDoc}
*/
public function insertPost(Post $post)
{
$insert = new Insert('posts');
$insert->values([
'title' => $post->getTitle(),
'text' => $post->getText(),
]);
$sql = new Sql($this->db);
$statement = $sql->prepareStatementForSqlObject($insert);
$result = $statement->execute();
if (! $result instanceof ResultInterface) {
throw new RuntimeException(
'Database error occurred during blog post insert operation'
);
}
$id = $result->getGeneratedValue();
return new Post(
$post->getTitle(),
$post->getText(),
$result->getGeneratedValue()
);
}
/**
* {@inheritDoc}
*/
public function updatePost(Post $post)
{
}
/**
* {@inheritDoc}
*/
public function deletePost(Post $post)
{
}
}
~~~
**数据库命令工厂类**
> module/Blog/src/Factory/ZendDbSqlCommandFactory.php
~~~
<?php
namespace Blog\Factory;
use Interop\Container\ContainerInterface;
use Blog\Model\ZendDbSqlCommand;
use Zend\Db\Adapter\AdapterInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
class ZendDbSqlCommandFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
return new ZendDbSqlCommand($container->get(AdapterInterface::class));
}
}
~~~
### 增加新建帖子功能
**创建写作控制器**
> module/Blog/src/Controller/WriteController.php
```
<?php
namespace Blog\Controller;
use Blog\Form\PostForm;
use Blog\Model\Post;
use Blog\Model\PostCommandInterface;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class WriteController extends AbstractActionController
{
/**
* @var PostCommandInterface
*/
private $command;
/**
* @var PostForm
*/
private $form;
/**
* @param PostCommandInterface $command
* @param PostForm $form
*/
public function __construct(PostCommandInterface $command, PostForm $form)
{
$this->command = $command;
$this->form = $form;
}
public function addAction()
{
$request = $this->getRequest();
$viewModel = new ViewModel(['form' => $this->form]);
// 注意下面的通用表单处理逻辑
if (! $request->isPost()) {
return $viewModel;
}
$this->form->setData($request->getPost());
if (! $this->form->isValid()) {
return $viewModel;
}
$post = $this->form->getData();
try {
$post = $this->command->insertPost($post);
} catch (\Exception $ex) {
// An exception occurred; we may want to log this later and/or
// report it to the user. For now, we'll just re-throw.
throw $ex;
}
return $this->redirect()->toRoute(
'blog/detail',
['id' => $post->getId()]
);
}
}
```
**控制器工厂类**
> module/Blog/src/Factory/WriteControllerFactory.php
~~~
<?php
namespace Blog\Factory;
use Blog\Controller\WriteController;
use Blog\Form\PostForm;
use Blog\Model\PostCommandInterface;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
class WriteControllerFactory implements FactoryInterface
{
/**
* @param ContainerInterface $container
* @param string $requestedName
* @param null|array $options
* @return WriteController
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$formManager = $container->get('FormElementManager');
return new WriteController(
$container->get(PostCommandInterface::class),
$formManager->get(PostForm::class)
);
}
}
~~~
**模块配置**
> module/Blog/config/module.config.php
~~~
<?php
namespace Blog;
use Zend\Router\Http\Literal;
use Zend\Router\Http\Segment;
use Zend\ServiceManager\Factory\InvokableFactory;
return [
// This lines opens the configuration for the RouteManager
'router' => [
'routes' => [
'blog' => [
'type' => Literal::class,
'options' => [
'route' => '/blog',
'defaults' => [
'controller' => Controller\ListController::class,
'action' => 'index',
],
],
'may_terminate' => true,
'child_routes' => [
'detail' => [
'type' => Segment::class,
'options' => [
'route' => '/:id',
'defaults' => [
'action' => 'detail',
],
'constraints' => [
'id' => '[1-9]\d*',
],
],
],
// 添加以下路由:
'add' => [
'type' => Literal::class,
'options' => [
'route' => '/add',
'defaults' => [
'controller' => Controller\WriteController::class,
'action' => 'add',
],
],
],
],
],
],
],
'controllers' => [
'factories' => [
Controller\ListController::class => Factory\ListControllerFactory::class,
// 添加以下行:
Controller\WriteController::class => Factory\WriteControllerFactory::class,
],
],
'view_manager' => [
'template_path_stack' => [
__DIR__ . '/../view',
],
],
'service_manager' => [
'aliases' => [
Model\PostRepositoryInterface::class => Model\ZendDbSqlRepository::class,
// 添加以下行:
Model\PostCommandInterface::class => Model\ZendDbSqlCommand::class,
],
'factories' => [
Model\PostRepository::class => InvokableFactory::class,
Model\ZendDbSqlRepository::class => Factory\ZendDbSqlRepositoryFactory::class,
// 添加以下 2 行:
Model\PostCommand::class => InvokableFactory::class,
Model\ZendDbSqlCommand::class => Factory\ZendDbSqlCommandFactory::class,
],
],
];
~~~
**模板文件**
> module/Blog/view/blog/write/add.phtml
~~~
<h1>Add a blog post</h1>
<?php
$form = $this->form;
$form->setAttribute('action', $this->url());
$fieldset = $form->get('post');
$title = $fieldset->get('title');
$title->setAttribute('class', 'form-control');
$title->setAttribute('placeholder', 'Post title');
$text = $fieldset->get('text');
$text->setAttribute('class', 'form-control');
$text->setAttribute('placeholder', 'Post content');
$submit = $form->get('submit');
$submit->setAttribute('class', 'btn btn-primary');
$form->prepare();
echo $this->form()->openTag($form);
?>
<fieldset>
<div class="form-group">
<?= $this->formLabel($title) ?>
<?= $this->formElement($title) ?>
<?= $this->formElementErrors()->render($title, ['class' => 'help-block']) ?>
</div>
<div class="form-group">
<?= $this->formLabel($text) ?>
<?= $this->formElement($text) ?>
<?= $this->formElementErrors()->render($text, ['class' => 'help-block']) ?>
</div>
</fieldset>
<?php
echo $this->formSubmit($submit);
echo $this->formHidden($fieldset->get('id'));
echo $this->form()->closeTag();
~~~