Now we have all the required code on the API to accept URLs. Let's see the changes required on the frontend to be able to post the URL and show the result on the wall. As usual, let's have a look at a screenshot of the folder structure and new files.
Let's create a new entity to store the data related to a link. This class is really easy and just contains getters and setters for the column names. Let's see a couple of examples and the list of properties contained inside the class.
protected $id = null; protected $userId = null; protected $url = null; protected $title = null; protected $createdAt = null; protected $updatedAt = null;
Now let's see two simple getters and setters.
public function setTitle($title) { $this->title = $title; } public function setUpdatedAt($updatedAt) { $this->updatedAt = new DateTime($updatedAt); } public function getId() { return $this->id; } public function getUserId() { return $this->userId; }
Of course if we want the users to use the new functionality, we should provide them with a way to provide us with the information we need. This form will allow them to specify the URL of the web page they want to share, as simple as that. Again, this form will have one special section, the field used for the URL information.
namespace WallForms; use ZendFormElement; use ZendFormForm;
As usual we start with the following declaration of namespaces at the beginning of the class:
class LinkForm extends Form
The declaration of the class will follow the same approach as the other forms we already created, but in this case we are not implementing the InputFilterProviderInterface
interface because the field we are going to use will automatically add the needed validators.
public function __construct($name = null) { parent::__construct('link-content'), $this->setAttribute('method', 'post'), $this->setAttribute('class', 'well input-append'), $this->prepareElements(); }
The structure of the form will follow the approach of having specialized methods for each task. That leaves us with the following constructor:
public function prepareElements() { $this->add(array( 'name' => 'url', 'type' => 'ZendFormElementUrl, 'attributes' => array( 'class' => 'span11', ), )); $this->add(new ElementCsrf('csrf')); $this->add(array( 'name' => 'submit', 'attributes' => array( 'type' => 'submit', 'value' => 'Submit', 'class' => 'btn' ), )); }
This is how the prepareElements()
method looks. As you can see we are adding the field URL to allow the users to insert the URL and is a Url
element. This includes the new URL HTML5 element on the form and automatically adds the ZendValidateUri
validator. Remember that if we use the ZendFormElementUrl
element we should use the formUrl()
helper on the view.
This file will take care of rendering the fields associated with the LinkForm. The content is similar to other files we saw before.
<?php $form = $this->form; ?> <?php $form->prepare(); ?> <?php echo $this->form()->openTag($form) ?> <!-- Url input text --> <?php echo $this->formElement($form->get('url')); ?> <?php echo $this->formElementErrors($form->get('url')); ?> <!-- Submit button --> <?php echo $this->formElement($form->get('submit')); ?> <!-- CSRF --> <?php echo $this->formElement($form->get('csrf')); ?> <?php echo $this->formElementErrors($form->get('csrf')); ?> <?php echo $this->form()->closeTag() ?>
Did you see it? Yes, we are not using the formUrl()
helper, instead, we are using the usual formElement()
helper. Why? Because the formElement()
helper will introspect the field we are trying to print and will decide which is the best helper for the job and will use it. It's like a universal view helper for form elements.
As usual we cannot put the entire code of the view because it's huge but we are going to see in this section how to include the new form on the view.
<div id="wall-link"> <?php echo $this->partial( 'forms/link-content-form.phtml', array('form' => $linkContentForm) ); ?> </div>
As you can see, we are calling a partial that includes the elements of the form and we are passing the form itself as a parameter to that partial. When you render a partial you can pass all the variables you want and change its name using the second parameter of the partial()
method. It accepts an array and the names you use on the keys will become the name of the variable that contains the value you pass inside the partial.
<?php elseif ($entry instanceOf WallEntityLink) : ?> <p> <a href="<?php echo $entry->getUrl() ?>"> <?php echo $entry->getTitle() != ''? $entry->getTitle() : $entry->getUrl(); ?> </a> </p> <?php endif; ?>
This is the code we will use to represent a link on the wall. It's a simple link pointing to the URL and using the title of the website as a text of the link. It's really simple but you can extend the base system to fetch the images of the web page and use one of them to represent the page similar to Facebook. You can also extract the content of the description
meta tag and use it here to further explain the purpose of the website.
As we did with the other content, we should adapt the User
entity to create new entities for the links. This is really easy and we just need to add the following lines to the setFeed()
method:
public function setFeed($feed) { $hydrator = new ClassMethods(); foreach ($feed as $entry) { if (array_key_exists('status', $entry)) { $this->feed[] = $hydrator->hydrate( $entry, new Status() ); } else if (array_key_exists('filename', $entry)) { $this->feed[] = $hydrator->hydrate( $entry, new Image() ); } else if (array_key_exists('url', $entry)) { $this->feed[] = $hydrator->hydrate( $entry, new Link() ); } } }
As you can see we are adding a new case to our if
block and testing if the entry has a key called url
, in which case we proceed to hydrate a new Link
object.
The following is the last file we have to modify in this chapter to make the new functionality work:
use WallFormsLinkForm;
This is the first thing to do. We should add this line to be able to use the new form we created for the users.
Then we should make three changes in the
indexAction()
method in order to include and process the new form.
$linkForm = new LinkForm();
This line goes in the block where we create the other forms; we just need to create an instance of the new one.
if (array_key_exists('url', $data)) { $result = $this->createLink($linkForm, $user, $data); }
This second block goes inside the if
block that checks if we are dealing with a POST request. In here, we are checking the type of the request based on the keys found in the data and based on that call, the specialized method createLink()
, which will take care of the rest. The rest of the code should look familiar because it is the same one we used on the two previous forms but we have just adapted the names of the variables to match the new forms.
$linkForm->setAttribute( 'action', $this->url()->fromRoute( 'wall', array('username' => $user->getUsername()) ) );
This is the last block of code we need in this method and we will add it at the end, next to the other two similar blocks of code we have. We are just setting the URL for the action
parameter on the form.
Now let's review the new method createLink()
that we have to add. It's really simple and looks like the other one we already added, specially with the
createStatus()
method that is basically the same.
protected function createLink($form, $user, array $data) { return $this->processSimpleForm($form, $user, $data); }
The following screenshot shows how our wall looks with the new functionality: