* This article is part of the original Jobeet Tutorial, created by Fabien Potencier, for Symfony 1.4.
With the addition of feeds on Jobeet, job seekers can now be informed of new jobs in real-time.

On the other side of the fence, when you post a job, you will want to have the greatest exposure possible. If your job is syndicated on a lot of small websites, you will have a better chance to find the right person. That’s the power of the long tail. Affiliates will be able to publish the latest posted jobs on their websites thanks to the web services we will develop today.

Affiliates

As we already said in day 2 of this tutorial, an affiliate retrieves the current active job list.

The fixtures

Let’s create a new fixture file for the affiliates:

Now, to persist the data defined in your fixture file, just run the following command:

In the fixture file, the tokens are hardcoded to simplify the testing, but when an actual user applies for an account, the token will need to be generated Let’s create a function to do that in our Affiliate class. Start by adding the setTokenValue method to lifecycleCallbacks section, inside your ORM file:

Now, the setTokenValue method will be generated inside the entity file when you will run the following command:

Let’s modify the method now:

Reload the data:

The Job Web Service

As always, when you create a new resource, it’s a good habbit to define the route first:

As usually, after you modify a routing file, you need to clear the cache:

The next step is to create the api action and the templates, that will share the same action. Let us now create a new controller file, called ApiController:

To retrieve the affiliate using his token, we will create the getForToken() method. This method also verifies if the affiliate account is activated, so there is no need for us to check this one more time. Until now, we haven’t used the AffiliateRepository yet, so it doesn’t exist. To create it, modify the ORM file as following, then run the command you used before to generate the entities.

Once created, it is ready to be used:

After identifying the affiliate by his token, we will use the getActiveJobs() method to give the affiliate the jobs he required, belonging to the selected categories. If you open your JobRepository file now, you will see that the getActiveJobs() method doesn’t share any connection with the affiliates. Because we want to reuse that method, we need to make some modifications inside of it:

As you can see, we populate the jobs array using a function called asArray(). Let’s define it:

The xml Format

Supporting the xml format is as simple as creating a template:

The json Format

Support the JSON format is similar:

The yaml Format

If you try to call the web service with a non-valid token, you will receive a 404 page as a response, for all the formats. To see what you accomplished until now, access the following links: http://jobeet.local/app_dev.php/api/sensio-labs/jobs.xml or http://jobeet.local/app_dev.php/api/symfony/jobs.xml. Change the extension in the URL, depending on which format you prefer.

Web Service Tests

Inside the ApiControllerTest file, we test that the request formats are correctly received and the pages requested are correctly returned.

The Affiliate Application Form

Now that the web service is ready to be used, let’s create the account creation form for affiliates. For that, you need to write the HTML form, implement validation rules for each field, process the values to store them in a database, display error messages and repopulate fields in case of errors.

First, create a new controller file, named AffiliateController:

Then, change the Affiliates link in the layout:

Now, we need to create an action to match the route from the link you just modified it earlier:

We have the name of the route, we have the action, but we do not have the route. so let’s create it:

Also, add this to your routing file:

The form file also needs to be created. But, even if the Affiliate has more fields, we won’t display them all, because some of them must not be editable by the end user. Create your Affiliate form:

Now, we need to decide whether or not the Affiliate object is valid after the form has applied the submitted data to it. To do this, add the following code to your validation file:

In the validation schema, we used a new validator, called UniqueEntity. It validates that a particular field (or fields) in a Doctrine entity is (are) unique. This is commonly used, for example, to prevent a new user to register using an email address that already exists in the system.

Don’t forget to clear your cache after applying the validation constraints!

Finally, let’s create the view for the form too:

When the user submits a form, the form data must be persisted into database, if valid. Add the new create action to your Affiliate controller:

When submitting, the create action is performed, so we need to define the route:

After the affiliate registers, he is redirected to a waiting page. Let’s define that action and create the view too:

Now, the route:

After defining to routes, in order to work, you need to clear the cache.

Now, if you click on the Affiliates link on the homepage, you will be directed to the affiliate form page.

Tests

The last step is to write some functional tests for the new feature.

The Affiliate Backend

For the backend, we will work with SonataAdminBundle. As we said before, after an affiliate registers, he needs to wait for the admin to activate his account. So, when the admin will access the affiliates page, he will see only the inactivated accounts, to help him be more productive.

First of all, you need to declare the new affiliate service inside your services.yml file:

After that, create the Admin file:

To help the administrator, we want to display only the inactivated accounts. This can be made by setting the ‘is_active’ filter to false:

Now, create the AffiliateAdmin controller file:

Let’s create the activate and deactivate batch actions:

For the new batch actions to be functional, we have to add them in the getBatchActions from the Admin class:

For this to work, you need to add the two methods, activate and deactivate, in the entity file:

Let’s now create two individual actions, activate and deactivate, for each item. Firstly, we will create routes for them. That’s why, in your Admin class, you will extend the configureRoutes function:

It’s time to implement the actions in the AdminController:

Now, create the templates for the new added action buttons:

Inside your Admin file, add the new actions and buttons to the configureListFields function, so that they would appear on the page, to each account individually:

Now, clear your cache and try it on!

That’s all for today! Tomorrow, we will take care of the emails the affiliates will receive when their accounts have been activated.
Creative Commons License
This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.