When creating a single-page app we should use some kind of framework to do some of the job for us, so we can focus on the actual functionality. AngularJS fits here perfectly, because features like dynamic dependency injection and bi-directional data binding are just great. Sometimes we also require some kind of server. If you've chosen PHP then Laravel may be your best option, as it's easy to work with and pretty powerful.
Introduction
In this tutorial you will create a simple customer/transaction management system with the ability to add and remove both transactions and customers. This is probably not the kind of thing you make very often, but it shows how to use features of both frameworks.
Before we start you should setup a MySQL database which we will use (Laravel supports many more of them, but this is still the most popular one). You don't need any web server since we will be using PHP's built-in one (but please keep in mind, that this solution is only for the development and should never be used in production - it lacks many features that are required for your app to work properly in public). For that, we will need at least PHP version 5.4.0.
Preparation
The first thing we have to do is to install Laravel. The full process is described on Laravel's website. After that, you should have your project directory created with all of Laravel's files in there. Navigate to that directory in your command line and run this command there:
If all goes OK, you should see that the local development server was started on locahost:8000. Open your browser and navigate there, you should see Laravel's welcome page:
Now we can proceed to the actual application.
Migrations and Models
Models in Laravel are just like in any other MVC framework. It's using the Eloquent ORM to ease the work for you - you will probably never need to write an SQL query again (unless you'll want something that Eloquent does not support). Using migrations you can modify the database structure with the ability to rollback changes if something goes wrong. You can read more about migrations in the documentation.
In our app we will use two models:
Customer - will hold the customer data
Transaction - will hold the information about a transaction
Let's start by creating migrations for them. If you have not done so already, shut down the server we started earlier (Ctrl + C).
Customers
First, invoke this command:
This will create a migration file with a basic structure for you. Now navigate to app/database/migrations. There should be a file with its name starting with a timestamp and ending with "create_customers_table". Laravel automatically created this basic structure for you. The up() method is called when the migration is applied, and down() when it's rolled back.
First call the Schema::create() method. It takes two arguments - the schema's name and a callback function:
The callback is executed when the table is created. The table object is passed as the $table variable and we manipulate the table's structure using it. Let's add an auto-incrementing id field:
Next there will be three string fields for the customer's first name, surname and email:
We make the email field unique by calling the unique() method on it.
The last method is for the timestamps:
This will create two date fields in the schema: created_at and updated_at. These will be used by Eloquent to store the time when the item was created and updated.
Finally, the code should look like this:
The down() method is much simpler - it just deletes the schema:
Transactions
The code here will be similar to the customers' one. First invoke this command:
Now locate the appropriate file in the app/database/migrations and open it. Like earlier, start by creating the schema:
Now add the fields for the id, transaction's name, its cost and the id of the customer that it belongs to:
And of course the timestamps:
The final code should look like this:
And now the down() method:
Database Configuration
Now before you apply the migrations you'll have to configure the connection to your database. Open the app/config/database.php file and go to line 55. Here is the configuration data for MySQL (there are few others in there, for example you could use SQLite or Postgres):
After you have filled that in, you are good to go. Make sure you saved the file and invoke this command from your app's main directory (the one with the artisan file in it):
And thats it. If there were no errors, that means that the tables were created successfully. You can connect to your db using, for example, phpMyAdmin to check manually if you want.
Models
In Laravel, creating a model after you've configured your database using migrations is really quick. Navigate to app/models and delete the example User.php file that is there. Now create two files named Customer.php and Transaction.php.
Let's start with Customer.php. Every model in Laravel has to extend the Eloquent class:
Now we will define a relationship between the customer and their transactions. This is done by defining a public method in the model with the name of the property we would like to have in it (in this case transactions):
Now in the body of the function there will be only one line:
This tells Eloquent that it should provide all transactions with customer_id of the customer under a property named transactions.
Now we will do pretty much the same for the transactions, but we will reverse the relationship to make the transaction's owner accessible via the customer property:
This is done using the $this->belongsTo() method of the model.
Controllers
Now to actually use the models we have to create controllers for them. Head to the app/controllers directory, delete the HomeController.php only - BaseController.php is important as our controllers will extend it. Now create two files: CustomerController.php and TransactionController.php.
CustomerController
This controller will handle everything related to the customers - adding, removing and showing a list of them. Start by defining the class:
We will be using Laravel's feature named RESTful controllers. It makes creating routes easier because we only have to define the base URI and Laravel will handle everything for us. This requires you to start your function names with the appropriate HTTP verb and then continue with the subroute name (using camelCase). So for example, if we would have a method named getNames and the base URI would be /customers, then the method will be accessible at /customers/names.
The getIndex(), postIndex(), deleteIndex() etc. methods will be mapped to the default route (in this case /customers).
Now let's define our first route - getting the customer by their id:
Let's get the id from the query parameters (Laravel provides a nice Input class to deal with that, so you don't have to use $_GET, $_POST and $_FILES):
And search for the user in the database using that id:
Every method of the controller has to return a value that is a string or has a __toString() method. In this case the Customer model that is returned will be converted to JSON before sending.
Now lets return a list of all users (this will be accessible under /customers/all):
As you can see, we can get all customers using the model's all() method.
Now the longest part, adding a new customer:
First let's check if all information needed was provided. We can do this using the Input::has() method:
Let's put all of the input fields in the $input variable to avoid calling Input::get() over and over. This can be done using Input::all():
Next we will check if any of the inputs are empty. If so, we will return a HTTP 400 Bad Request error with a more verbose message:
Since we wanted to return a status code other than 200 instead of just returning the message as a string, we used Response::make(), which takes the data to send as the first parameter and the status code as the second. Take a look at the docs if you want to know more about responses.
Now we finally create a new Customer model and feed it with the data provided:
After that we can save the newly created model and respond to the request with it:
Here we handle the case if not all of the inputs were provided:
Finally, we also need the ability to remove the customers. This one is really short:
We start by getting the id of the customer to delete:
Next, we search for and delete the customer:
After that, we respond to the request with the id provided:
Now before the routes can be accessed, we have to hook them. Open the app/routes.php file, delete everything but the comment and add this line at the end of the file:
This will tell Laravel to route all requests at /customers to our CustomerController. Now you can use CURL to play with it. First start the server with php artisan serve and then you can, for example, create a customer:
Then you can get the list of all customers:
TransactionController
This, like the model is very similar to the CustomerController. First create the class:
Then let's define the method to get all transactions for a user:
As you can see we are using the relationship defined earlier to get the transactions (now recall the query you had to write to achieve the same thing using plain PHP and SQL).
The next thing will be the creation of transactions:
Like earlier, we are checking if all of the required information is provided:
If so, assign it to an $input variable:
Check if any of the values provided are empty and if so return an error:
Now create the transaction and supply it with all of the info provided:
Now we need to add it to the appropriate customer. Let's find them by the id provided and add the $transaction to their transactions list:
This is done using the transactions->save() method provided by Laravel. Now we can respond with the transaction created:
And handle the case where none or not all of the data was provided:
After that there is also a method to delete the transaction in the same way that we deleted the customer:
Now just add the route and you can test the controller using CURL:
Conclusion
Alright, this is the end of the first part - in the second part of this tutorial, we will create the front-end using AngularJS. Feel free to add more features to your app (like editing customers or sorting), in case you did not find the information you were looking for, take a look at Laravel's documentation.