waitless is a client-server application using Laravel to manage the waiting guests in a restaraunt.
It uses two clients, where one is used to welcome new guests and register them into the system and the other is used inside the restaurant by the service to allocate the guests to a table.
git clone git@github.com:janschill/waitless.git
chmod +x install.sh
The installation script will instantiate an sqlite database and will – when prompted – start a localhost server on localhost:8080
.
It will create an application key and migrate the database and populate it with needed data.
Pusher will have to be setup manually, due to the requirement of an account.
If you do not want to use the install.sh
script you can get the application running as follow:
composer install
and node install
to get all dependenciesnpm install -g gulp-cli
)npm run dev
(only needed for Pusher).env
php artisan key:generate
)php artisan migrate
php artisan db:seed
At the moment waitless
is programmed very specific to fullfill a clients desire, but it is planned to refactor the whole project, to use a modern JavaScript framework and make the whole project more generic.
To configure the server (Raspberry Pi) to have a static IP address follow this guide: Guide
Most important file:
sudo vi /etc/dhcpcd.conf
In the following we will introduce the technologies used in this project. We will give a brief introduction and explain: how it works, how we implemented it, error that may have occured and explain why we chose the service over others or at all.
Vagrant provides a simple, elegant way to manage and provision Virtual Machines.
Homestead is an official, pre-packaged Vagrant box that provides a development environment without requiring to install PHP, a web server, and any other server software on the local machine.
Homestead.yaml
, change map
to absolute directory.vagrant reload
in a terminal window.vagrant up
.ifconfig
when connected through ssh.If you encounter a problem like The following SSH command responded with a non-zero exit status. Vagrant assumes that this means the command failed!
:
vagrant ssh
sudo apt-get install ifupdown
exit
vagrant reload
Maybe a newer vagrant version than in apt might fix this?
composer install
vendor/bin/homestead make
(ssh-keygen -t rsa -C "test@waitless.com")
vagrant up
vagrant ssh
cd code
mv /home/vagrant/code/.env.example /home/vagrant/code/.env
If this fails, check if .env.example existst. If not: touch .env and past this into it: Example env file
In the VM:
php artisan key:generate
php artisan migrate
Now connect to the database and execute the SQL-file to initialize the table data.
Navigate to the root directory of your Vagrant project. With vagrant up
the VM is started and now reachable in your browser at 192.168.10.10
. If not check your Homestead.yml file and check the value of ip
It is also available at homestead.test
. On Linux, you need to modify your etc/hosts
-file to use that domain at 192.168.10.10
.
valet park
in the current directory to make all folders accessible under foldername.test
valet link app-name
to serve a single app in the current directory under app-name.test
We are following Laravel coding conventions like Eloquent. Where every database table has a corresponding domain model in PHP. These are used to interact with the database.
Each model has a controller – when needed. These controllers control the data with functions like index
(action to list all the data) or show
(action to show single/specific data), these get called from the router and serve to the view, which render them in the browser.
Migrations are used to progressively adapt the database as you develop your application. Whenever you want to change the structure within your database you write a migration, which can also rollback:
function up()
{
// Make database changes like addColumn
}
function down()
{
// Rollback like dropColumn
}
In the next chapter we talk about testing, to successfully test an application, the database needs data, which we populate in Laravel using Seeds
and Factories
.
Create a ExampleTableSeeder.php
file in database/seeds
.
use Illuminate\Database\Seeder;
class ExampleTableSeeder extends Seeder {
public function run ()
{
factory('App\ExampleModel', 10)->create();
}
}
Now in the database/factories/ModelFactory.php
file we will, tell the seeder with what kind of data we want to create our seeds.
$factory->define(App\ExampleModel::class, function (Faker $faker) {
return [
'row_name_1' => $faker->sentence,
'row_name_2' => rand(0,10)
];
});
Here we can use the fakeer
instance to let Faker generate us dummy data or we use our own.
To prevent appending the generated data and just add the generated data to an empty table, we need to truncate the tables. We do that in database/seeds/DatabaseSeeder.php
. Here we also call our seeders.
protected $toTruncate = ['example_table_1', 'example_table_2'];
public function run()
{
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
foreach ($this->toTruncate as $table) {
DB::table($table)->truncate();
}
$this->call('Example1TableSeeder');
$this->call('Example2TableSeeder');
}
When working in database, we need to dump the composer autoload.
composer dump-autoload
To run seeds
php artisan db:seed
Unit testing concetrates on the smallest portion of the program code – a single unit or function. It tests if a function returns an expected result.
Theses test will be written in the tests/Unit
directory and are excuted with phpunit
in the command line. We wrote a copule of tests, which are tested with Travis.
For example we always had to have four states
, those had to be in the database on going live. So we wrote a Seeder, which populated the database table and after that a test would make sure thoses states were in the correct table with always same id.
Laravel's tinker is a read-eval-print-loop
, which takes user input and returns the result to command line. Tinker allows direct interaction with the application. For example if we want to restore a soft deleted record, will be as follows:
php artisan tinker
# Tinker shell gets opened
App\Model::withTrashed()->where('id', 1)->restore();
Our application had to have at least two active clients, where one would create records, which get added dynamically to the frontend, without a page reload and immediately notifies the other client that it should get this new data. To achieve this the WebSocket protocol had to be used.
Laravel has a built-in support for Pusher, which we chose, based on the great integration. Signing up with Pusher and creating an application on its dashboard, we were able to implement the needed keys to our front- and backend.
With Laravel's events and broadcasting we created a channel on which the clients listened for the change, which then triggered JavaScript, which updated the DOM accordingly.
For Continous Integration we are using Travis CI, which allows private CIs for students. Setting up is pretty straight forward:
.travis.yml
file is in the root of your repository.For Laravel and this application in particular there are a few extra steps that have to be taken care of:
.env.travis
file which holds the environment settings for this Laravel application.app/config/database.php
.After that Travis detects if the repository includes a .travis.yml
file in the root directory and launches – if present – it.
For deployment we are using a single deploy.sh
shell-script, because our application runs in production on a Raspberry Pi not directly connected to the outside (only Pusher). This deployment is not ideal, because we cannot deploy from Travis and we always have to be in the network (or VPN).
In the shell script we make sure the composer and node packages are installed and updated, run our bundlers and other tasks and then upload the files using rsync
. After that we set all necessary production setting to true.
One way to automatically trigger the deployment script is to use Git hooks
. These are located in ./.git/hooks/
there you can configure the desired hook to call a script or even be the script.
The GitHub Student Pack also includes some benefits to Sentry, so we included it in our project and we will try to see if is of any good use. So far in development it did not give any more insight, but I am sure, once the application is running in production (beta) we will be able to track down errors and find a solution quicker than just relying on descriptions of error occured during usage.