.. include:: /Includes.rst.txt .. index:: BlogController; newAction() BlogController; createAction() =========================== Action: creating a new post =========================== After the first journey through the blog example, here follows a more complex action. It is about the creation of a new post. The user is offered a form in the front end, where he can insert the title and the content of a new post and select an existing author for this post. After clicking the *submit* button, the list of the last posts of the current blog are displayed - now with the just created post in the first place. The steps of this example are mirrored in the actions ``new`` and ``create``. The method ``newAction()`` displays the form, while the method ``createAction()`` creates the post after the submission of the form. It puts the submitted data into the repository, and redirects to the method ``indexAction()``. Calling the method ``newAction()`` is done with a link in the front end, that looks - a bit challenging - like this: .. code-block:: html :caption: Example frontend output Create a new Post This is created with the following Fluid code in the template *EXT:blog_example/Resources/Private/Templates/Post/Index.html*: .. index:: Fluid; f:link.action .. code-block:: html :caption: EXT:my_extension/Resources/Private/Templates/SomeTemplate.html [create another post] .. todo: Either remove the class attribute here or add it above. There are people (like me) that are confused by code examples where things are not 100% correct. Same for the title attribute. franzholz: I do not understand this comment. I consider the class as useful for some cases. Can we remove the comment? The tag ```` creates a link to a special controller action combination: ``tx_blogexample_pi1[controller]=Post`` and ``tx_blogexample_pi1[action]=new``. The current blog is given as an argument with ``tx_blogexample_pi1[blog]=12``. Because the blog cannot be sent as an object, it must be converted into a unique identifier - the *UID*. In our case, this is the UID 12. Extbase creates the request out of these three parameters and redirections to the according ``PostController``. The conversion of the UID back to the corresponding ``blog`` object is done automatically by Extbase. Lets take a look at the called method ``newAction()``: .. code-block:: php :caption: EXT:blog_example/Classes/Controller/PostController.php view->assignMultiple([ 'authors' => $this->personRepository->findAll(), 'blog' => $blog, 'newPost' => $newPost, 'remainingPosts' => $this->postRepository->findByBlog($blog), ]); return $this->responseFactory->createHtmlResponse($this->view->render()); } } The method ``newAction()`` expects a ``blog`` object and an optional ``post`` object as parameter. This can sound weird at first, because in the beginning there is no blog and no post object. They have to be created after submission of the form. Actually the parameter ``$newPost`` is empty (``null``) at the first call. .. index:: Blog Example; PostController Extbase; PropertyMapper The ``PostController``, which is derived from ``\FriendsOfTYPO3\BlogExample\Controller\AbstractController`` and its parents ``\TYPO3\CMS\Extbase\Mvc\Controller\ActionController`` and ``\TYPO3\CMS\Extbase\Mvc\Controller\AbstractController``, prepares all parameters, before an action method is called. The controller method :php:`mapRequestArgumentsToControllerArguments` calls the method :php:`setValue` in a loop for each parameter. This method delegates the conversion to an instance of the class :php:`\TYPO3\CMS\Extbase\Property\PropertyMapper`, that has mainly two functions: it converts the parameter from the call (initiated from our link) into the target object and it checks, if the parameter is valid. The target for the parameter ``$blog`` is an instance of the class :php:`\FriendsOfTYPO3\BlogExample\Domain\Model\Blog`, for the parameter ``$newPost`` it is an instance of the class :php:`\FriendsOfTYPO3\BlogExample\Domain\Model\Post`. A source parameter with value 12 for the :php:`convert` method of the PropertyMapper will make a conversion into the blog object for record with :php:`$blog->uid == 12`. Extbase determines the target type of the conversion by the :php:`$targetType` passed to the :php:`convert` method. If it is not declared in the :php:`$propertyMappingConfiguration`, the php type of the action is used. The PHP class parsing is done in :php:`TYPO3\CMS\Extbase\Reflection\ClassSchema`. The type of the parameters are given in the function definition. For a better understanding you may keep the formerly required param notations in the comments as well: .. deprecated:: 11.3 Using the :php:`@param` DocBlock annotation without adding the actual PHP type declaration has been deprecated with TYPO3 11.3. .. index:: Action; Parameters .. code-block:: php :caption: EXT:blog_example/Classes/Controller/PostController.php /** * @param \MyVendor\MyExtension\Blog $blog */ public function createAction(\MyVendor\MyExtension\Blog $blog); The link is created with the name of the argument ``$blog``. In this way, the link between the request parameter and the ``newAction()`` is resolved. The link parameter: .. code-block:: none :caption: Example link parameter tx_blogexample_pi1[blog]=12 is assigned to the parameter: .. code-block:: php :caption: EXT:blog_example/Classes/Controller/PostController.php \FriendsOfTYPO3\BlogExample\Domain\Model\Blog $blog of the ``newAction()`` with the name "blog". With the help of the UID 12 the corresponding blog object can be identified, reconstructed, and given to the ``newAction()``. In the first line of the ``newAction()`` the view gets an array of persons in the parameter ``authors`` which is taken from the ``PersonRepository`` with the ``findAll()`` method. In the second and third line, the view gets the parameter ``blog`` and ``newPost``. The following actions are called automatically by the controller after calling ``newAction()``. .. code-block:: php :caption: EXT:blog_example/Classes/Controller/PostController.php $form = $this->view()->render(); return $form; .. todo: return $this->htmlResponse($this->view->render()); Here you see the full template *Post/New.html*: .. code-block:: html :caption: EXT:blog_example/Resources/Private/Templates/Post/New.html [cancel]

[create post]

Here you see the full partials template *PostForm.html*: .. code-block:: html :caption: EXT:blog_example/Resources/Private/Templates/Post/PostForm.html
TYPO3 takes the rendered form and includes it at the appropriate place in the final HTML page (see figure 3-5). .. figure:: /Images/ManualScreenshots/Frontend/3-BlogExample/figure-3-5.png :align: center Figure 3-5: The rendered form Clicking the *submit* button submits the form, then it calls the ``createAction`` of the ``PostController`` with the submitted form data. This is the stripped-down method: .. todo: Given the query params, the then called plugin on the same page dispatches the request to the desired controller and action. This is important because many people ask for Extbase magic when they only need to understand HTTP. franzholz: The lines above should not be described here, but somewhere else. .. code-block:: php :caption: EXT:blog_example/Classes/Controller/PostController.php /** * Creates a new post * * @param Blog $blog The blog the post belogns to * @param Post $newBlog A fresh Blog object which has not yet been added to the repository * @return ResponseInterface */ public function createAction(Blog $blog, Post $newPost) : ResponseInterface { // TODO access protection $blog->addPost($newPost); $newPost->setBlog($blog); $this->addFlashMessage('created'); $this->redirect('index', null, null, ['blog' => $blog]); } The arguments ``$blog`` and ``$post`` are filled and validated equivalent to the method ``newAction()``. .. note:: During the conversion of the arguments into the target object's property values, the above-mentioned ``PropertyMapper`` checks if any errors are encountered during the validation. The validation effected on the base of the property definitions of the target object. More about the subject validating you will find in the section :ref:`validating-domain-objects`. The post is added to the blog with ``$blog->addPost($newPost)``. After that, the following processing is forwarded by ``$this->redirect('index', ...)`` to the method ``indexAction()``. Thereby the blog - now with the new post - is passed as argument. So that the new post is available in the blog. And it must be persisted. This is done automatically at the end in the dispatcher of Extbase. .. index:: Action; redirect Extbase; ForwardResponse .. note:: What is :php:`redirect()`? With Extbase, requests can be further dispatched either by returning a `ForwardResponse` or by using :php:`redirect()`. The difference is: ``redirect()`` starts a completely new page call (new request-response cycle), while a :php:`ForwardResponse` is handled as part of the current request cycle. This has an important consequence: When using ``redirect()`` the changes are persisted before the call of the target action, whereas when returning a :php:`ForwardResponse` changes need to be persisted manually by calling :php:`$persistenceManager->persistAll();`.