11 – Add Blog post

Now that we have an InputFilter setup, we can create the addAction.

Open up the PostController and copy in the following function:

public function addAction()
{
    /** @var PostForm $form */
    $form = $this->getServiceLocator()->get('post_form');

    /** @var Request $request */
    $request = $this->getRequest();
    if ($request->isPost()) {
        $form->setData($request->getPost());

        if ($form->isValid()) {
            /** @var Post $post */
            $post = $form->getObject();
            $post->generateSlug();

            //Save post to DB
            $this->getEntityManager()->persist($post);
            $this->getEntityManager()->flush();

            //Redirect user to view new post
            $this->redirect()->toRoute('blog/view', [
            'id'   => $post->getId(),
            'slug' => $post->getSlug(),
            ]);
        }
    }

    return [
        'form' => $form,
    ];
}

Open up your browser and have a look at the add page. You’ll find the error “ServiceNotFoundException” telling us that the ServiceManager couldn’t create an instance of post_form. The first line in our addAction() function tries to call for this.

The only thing we haven’t done so far is register the factory for creating this intance. Let’s do so now and watch the magic happen. Open up the Blog module file Module.php and create the following function:

public function getServiceConfig()
{
    return [
        'factories' => [
            'post_form' => function ($sm)
            {
                $form = new PostForm();
                $form->setInputFilter(new PostInputFilter());

                //Set Doctrine Object as Hydrator
                $form->setHydrator(new DoctrineObject($sm->get(ConnectionString::DOCTRINE_DEFAULT)));
                //Set Doctrine Entity
                $form->setObject(new Post);

                return $form;
            },
        ],
    ];
}

The name is again not by choice. Zend looks for it in the Module.php file and executes it if it’s present. As you can see it does nothing more that return an array. That array however, contains the configuration for what the ServiceManager of Zend will know as post_form; the Form object for our Post entity.

Make sure to also include the classes below into Module.php or you’ll find yourself facing an error when you view the page.

use Application\Doctrine\ConnectionString;

use Blog\Form\PostForm;
use Blog\InputFilter\PostInputFilter;
use DoctrineModule\Stdlib\Hydrator\DoctrineObject;

We first create a new $form, setting in that the PostForm object by instantiation. On this we set an InputFilter, our PostInputFilter, also by instantiation.

Next up we change the Hydrator. Zend automagically sets it’s default Hydrator, and while it’s perfectly ok to use it, it doesn’t work correctly when handling a Doctrine entity. Therefore we change it to the DoctrineHydrator. Last but not least we set the object we want to be managed by the DoctrineHydrator to be our Post entity and then return the finished $form variable.

An obvious question to ask is: why not do this in our addAction function in the PostController? The answer is both simpel in it’s explanation and complex in it’s execution. We do it like this because it makes it possible to use a single UnitTest to test the result when we request the post_form from the ServiceManager. However, Unit testing is outside the scope of this tutorial. If you wish to test it however, feel free to research how to do so and add it into your project.

So, back to the addAction function. We now have our form available. Obviously we’re using a GET request to show our form, so we won’t be using any of the code within the if() statement when we’re going to just print the form in the client. We just return the $form so the add.phtml view can print it.

The code in the if() statement get’s executed when a client sends us data from the form. A form, by default, sends its data back to the URL it got the form from. Unless that was modified, which, in our case, it is not.

After checking and making sure that we are indeed receiving data (via a POST request using the $this->getRequest()->isPost() function), we set the received data into the $form, which contains our fully ready for use post_form from the ServiceManager.

Next up we check if the $form object is valid. The isValid() method executes Zend magic. It checks all data set in the object to the filters and validators set in the object and returns either true to indicate that it’s valid, or it sets an array of messages on the $form object and returns a false.

In case the response is false the next step is easy, as messages explaining why it’s false have been set by the isValid() function, we simply return the $formcontaining the messages. Zend magic will take care of displaying the errors for us. Go on, try it.

If the $form object is valid, we continue execution of the code within the second if() statement. First we get the object contained within the $form object by using the getObject() method and store it separately for re-use. We then generate the slug, for which we created a function within the Post entity earlier in the tutorial, this function also stores it in the appropriate variable of the Post object instance.

Then we use Doctrine to “persist” our new object. When executing the persist() Doctrine method it means that Doctrine ‘reserves’ the object, or any object that’s not saved but is in memory (of the server), a place in our database. At this point however, that is not permanent and the data is not yet stored! To permanently store it in the database we execute the Doctrine flush() method.

When objects get “flushed” they also get updated with ID’s assigned to them by the database. Doctrine does not generate these ID’s as with a multiple server setup this might cause ID’s clashes. It let’s the database handle this.

Now that our new Post object is saved, we have a new post available to show the user. Common practice is to show show the user what they’ve created, so next up we’ll redirect the client to show the new post with the $this->redirect()->toRoute() function. This function also destroy’s further execution after returning, so there is no need to ‘return’ anything.

Feel free to try it. Create as many posts as you like.

When you return to the index page however, you’ll notice there’s no way to access the ‘add’ page. Let’s update the index page with a simple link to the add page. Above the <section> element in the index.phtml view page, add the <section> below:

<section class="nav">
    <a href="<?= $this->url('blog/add') ?>" title="<?= $this->translate('Add new blog post') ?>">
        <?= $this->translate('Add new blog post') ?>
    </a>
</section>

We’ve now finished creating the adding of post. Consequently, after the indexing and viewing of a Post, this was the biggest one. We’ve just got editing and deleting of posts to go.