Editing a Post
To demonstrate the ability to use the Form Population Filter (FPF), we're going to make an
edit post page. So to start, we need to create the action, views and
templates.
bloggie$ dev/bin/agavi action-wizard
Module name: Posts
Action name: Post.Edit
Space-separated list of views to create for Add [Success]: Input Success Error
bloggie$
The Action has nothing special in it, other than a new method for the Posts_PostManager model, it does nothing more than update the database row for
the post and the getDefaultViewName() has been replaced with executeRead() so the validation would
work.
<?php
class Posts_Post_EditAction extends BlogPostsBaseAction
{
/**
* Serves Write (POST) requests.
*
* @param AgaviRequestDataHolder the incoming request data
*
* @return mixed <ul>
* <li>A string containing the view name associated
* with this action; or</li>
* <li>An array with two indices: the parent module
* of the view to be executed and the view to be
* executed.</li>
* </ul>
*/
public function executeWrite(AgaviRequestDataHolder $rd)
{
$post = $rd->getParameter('post');
$post->setTitle($rd->getParameter('title'));
$post->setCategoryId($rd->getParameter('category'));
$post->setContent($rd->getParameter('content'));
$postManager = $this->getContext()->getModel('PostManager', 'Posts');
$postManager->storeEdit($post);
return 'Success';
}
public function executeRead(AgaviRequestDataHolder $rd)
{
return 'Input';
}
public function isSecure()
{
return true;
}
}
?>
As pointed out in the action, there's a new method in the Posts_PostManager called storeEdit(), it's a rather simple
update query being
executed.
public function storeEdit(Posts_PostModel $post)
{
$con = $this->getContext()->getDatabaseManager()->getDatabase()->getConnection();
$sql = 'UPDATE posts SET title=?, category_id=?, content=? WHERE id=?';
$stmt = $con->prepare($sql);
$stmt->bindValue(1, $post->getTitle(), PDO::PARAM_STR);
$stmt->bindValue(2, $post->getCategoryId(), PDO::PARAM_INT);
$stmt->bindValue(3, $post->getContent(), PDO::PARAM_STR);
$stmt->bindValue(4, $post->getId(), PDO::PARAM_INT);
$stmt->execute();
return $stmt->execute();
}
The validation code is not really any different from the experiences you have had with it
before, except it's a mixture between the add action and the show
action
<?xml version="1.0" encoding="UTF-8"?>
<ae:configurations
xmlns="http://agavi.org/agavi/config/parts/validators/1.0"
xmlns:ae="http://agavi.org/agavi/config/global/envelope/1.0"
parent="%core.module_dir%/Posts/config/validators.xml"
>
<ae:configuration>
<validators method="read">
<validator class="Posts_PostValidator" name="post">
<arguments>
<argument>post</argument>
</arguments>
<errors>
<error>The parameter post must contain a valid post id</error>
</errors>
<ae:parameters>
<ae:parameter name="export">post</ae:parameter>
</ae:parameters>
</validator>
</validators>
<validators method="write">
<validator class="Posts_PostValidator" name="post">
<arguments>
<argument>post</argument>
</arguments>
<errors>
<error>The parameter post must contain a valid post id</error>
</errors>
<ae:parameters>
<ae:parameter name="export">post</ae:parameter>
</ae:parameters>
</validator>
<validator class="string">
<arguments>
<argument>title</argument>
</arguments>
<errors>
<error>The title field has an invalid value.</error>
<error for="required">Please provide a title.</error>
<error for="max_error">The title must be shorter than 255 characters.</error>
</errors>
<ae:parameters>
<ae:parameter name="max">255</ae:parameter>
</ae:parameters>
</validator>
<validator class="string">
<arguments>
<argument>content</argument>
</arguments>
<errors>
<error>The content field has an invalid value.</error>
<error for="required">Please provide a post body.</error>
<error for="max_error">The post body must be shorter than 65536 characters.</error>
</errors>
<ae:parameters>
<ae:parameter name="max">65536</ae:parameter>
</ae:parameters>
</validator>
<validator class="inarray">
<arguments>
<argument>category</argument>
</arguments>
<errors>
<error>Please choose a valid category.</error>
<error for="required">Please choose a category.</error>
</errors>
<ae:parameters>
<ae:parameter name="values">
<ae:parameters>
<ae:parameter>1</ae:parameter>
<ae:parameter>2</ae:parameter>
</ae:parameters>
</ae:parameter>
</ae:parameters>
</validator>
</validators>
</ae:configuration>
</ae:configurations>
The code used for this section isn't anything special until you get to the Posts_Post_EditInputView, where we introduce a new feature to the project. The
FPF code is rather simplistic and is rather easy to use the code below simply creates a new
AgaviParameterHolder and uses the form control names as the keys, the
values for these keys is what is going to be shown in the form's control value attribute. We
add the AgaviParameterHolder object as an attribute directory to the
request object with the namespace "org.agavi.filter.FormPopulationFilter" so Agavi knows what
it
is.
<?php
class Posts_Post_EditInputView extends BlogPostsBaseView
{
public function executeHtml(AgaviRequestDataHolder $rd)
{
$this->setupHtml($rd);
$post = $rd->getParameter('post');
$form = new AgaviParameterHolder(array(
'post' => $post->getId(),
'title' => $post->getTitle(),
'content' => $post->getContent(),
'category' => $post->getCategoryId(),
));
$this->setAttribute('_title', 'Edit Post');
$this->setAttribute('post', $post);
$this->getContext()->getRequest()->setAttribute('populate', array('edit' => $form), 'org.agavi.filter.FormPopulationFilter');
}
}
?>
And the corresponding template, this is the same code for the add template but with an ID set
on the
form:<form id="edit" action="<?php echo $ro->gen('posts.post.edit', array('post' => $t['post'])); ?>" method="post">
<fieldset>
<div class="form_row">
<label for="input_title">Title:</label>
<input type="text" name="title" id="input_title" />
</div>
<div class="form_row">
<label for="input_content">Content:</label>
<textarea name="content" id="input_content"></textarea>
</div>
<div class="form_row">
<label for="input_category">Category:</label>
<select name="category" id="input_category">
<option value="1">No category</option>
<option value="2">Agavi</option>
</select>
</div>
<div class="form_row form_row_submit">
<input type="hidden" name="post" />
<button type="submit" class="submit">Add Post</button>
</div>
</fieldset>
</form>
The Success view is no different from the view used for Posts_AddSuccessView.
To make the page actually viewable, we need to add a line to the app/config/routing.xml, so the "Post" block now looks like
this:
<route name=".post" pattern="^/(post:\d+)(-{title:[-\w]+})?" action="Post">
<callbacks>
<callback class="PostRoutingCallback" />
</callbacks>
<route name=".show" pattern="^$" action=".Show" />
<route name=".edit" pattern="^/edit$" action=".Edit" />
</route>

