Wern Ancheta

Adventures in Web Development.

Introduction to Shotgun

| Comments

One of my pain points as a teacher is checking student activities. That includes seat works, assignments and quizzes. Checking takes a lot of time. In one of my classes, it took me 4 hours to check 48 papers which has 50 items. The thing I hate is that its repetitive like doing factory work. That is why I started creating Shotgun, a quiz maker app. The idea is to create a quiz using it and then have students access the quiz at a specific time. Once the student has submitted the quiz, the score is automatically computed.

Shotgun allows for creating of classes. This allows the teacher to add the name of the class, some details and a textarea where the student details can be entered.

create a new class

Once a class has been created, it is then listed in the classes page.

classes

From there, the update link can be clicked to access the page for updating the class. This is where the class details can be updated. Students that are no longer entering the class can also be dropped so they’re no longer included in the list.

classes

Next is the creation of new quizzes. Currently, only 3 types of quizzes can be created: identification, multiple choice and true/false. True/false still take a bit of effort though. As it uses the same functionality for multiple choice. Which means that true and false has to be added as a choice.

classes

Once the quiz is created, it is listed in the quizzes page.

quizzes

A quiz can be scheduled by going to the scheduling page. This is where the quiz, class, the start time and end time can be added. The students can only take the quiz between the time specified.

schedule quiz

While the time added in the quiz is not the same as the current time, the teacher can still update the details of the quiz such as the class who is going to take it, the quiz to be taken and also the start time and end time.

scheduled quizzes

When it’s time to take the quiz. The teacher then asks the students to access the quiz page on the browser. The teacher gives the quiz code and the students enter it together with their ID number.

start quiz

If the current time is between the start time and end time, the actual quiz is rendered. Every quiz can only be taken once by a student, so once it has been taken, the student cannot take it again. And while taking the quiz, the student cannot open a new tab or open any other window in the computer. The quiz will be automatically submitted when this is done. This is done through JavaScript so if JavaScript is disabled in the browser, the quiz won’t be rendered at all.

take quiz

Once the quiz is done, the teacher can then view the scores of the students.

take quiz

Or export it to a spreadsheet.

take quiz

From there, the teacher can just copy the scores and paste it to their own class record spreadsheet.

Problems

This is all well and good but there are still some hard problems that needs solving. First is the fact that the identification type of questions that you can create are rigid. There should only be a few acceptable answers. And since I’m primarily teaching web development. There is a need for questions that asks students to code something. If you’re a programmer you know that there can be many ways to solve a specific problem. There are many ways which you can code something. And it’s close to impossible to consider all of those when adding an acceptable answer to a quiz item. One possible solution is to use the output of the code as the answer. So for example, if you ask the student to write a function that would return the sum of 2 numbers that were supplied as the arguments. So in the back-end, you add the following function:

1
2
3
var sum = function(num1, num2){
    return num1 + num2;
};

Then you also add the arguments to be used. And then those arguments will be used to execute the function that you added. Then the program will check if it has the same result as the function that was coded by the student. If it does then the answer is considered correct. The only problem is that I still have no idea how to code that kind of thing. It’s basically telling a program to execute a program that is stored in the string of text. The solution for now is to stick with multiple choice type of question.

Another problem is letter casing. Answers can be typed in many ways: ALL CAPS, Capitalized, or all lower case. I’m still yet to figure out what’s the best way to do this. Because some questions might require answers to be in a specific letter case and some don’t. The only solution I can think of right now is to have an option in the quiz item that allows for specifying if the letter casing should match what was included in the answer list or not. If not then have the program convert the answers (answers by students, answers included by teacher) to lower case and then compare. If yes then compare the answers as it is.

Future Plans

Here are my future plans for this project.

  • Add signup, forgot password and logout.
  • Add functionality for deleting answers and choices.
  • Random order for quiz items for every student. This will make it hard for students to copy answers from their classmates.
  • Support for code based answers (as mentioned in the problems section).

That’s it! If you want to use this project or contribute to it, you can download it on Github.

More Podcasts I Listen To

| Comments

Time flies so fast, I can’t believe that its been more than a year since I last posted something about the podcasts I listen to. Before I was only listening to developer-related podcasts such as Shoptalkshow and Ruby Rogues. But I’ve discovered that there are more great podcasts out there outside my own little developer world. Here are some of those:

Radiolab

Radiolab is a podcast hosted by Jad Abumrad and Robert Krulwich. It mostly focuses on science and history topics. Its very entertaining and truly a great snack for the brain.

Developer Tea

One of the newer podcasts on development produced by Jonathan Cutrell. The thing I really like about this podcast is that its very short, the longest episode I’ve heard so far is abou 13 minutes. So it doesn’t really take much of your time. You can listen to it while you’re on a tea break might be the inspiration why its called developer tea. And because they are short, you can expect to hear only the most essential advice that are useful for you as a developer.

Nocturne

Nocturne is a podcast about the night. It features stories of people’s experiences in the night. I found out about it when I was searching for scary podcasts. Though I later found out that Nocturne isn’t really that. But the quality of the podcast really made me an avid listener.

Lore

Lore is a podcast featuring true life scary stories. This includes stories of ghosts and local folklore such as the Jersey Devil.

NoSleep Podcast

NoSleep Podcast is a fiction horror podcast. I think its scary but I also think it can be scarier. Though if they would make it more scary, I probably would no longer listen. I think its scariness level is manageable for most people.

Stuff You Should Know

A podcast from the howstuffworks.com network. If you have read howstuffworks.com before then you can expect the same kind of content on this podcast. Any topic under the sun which answers the question on how it works.

Stuff To Blow Your Mind

As the name suggests, this podcast mainly focuses on stuff that can blow your mind.

Planet Money

A podcast from NPR that’s all about money and the economy.

Invisibilia

A new podcast from NPR which features stories on the invisible forces that control human behavior. I first heard about it while I was listening to Radiolab. I didn’t hesitate to try an episode since I already know the quality of podcasts from NPR.

Last Podcast On The Left

Yet another podcast that I found while I was looking for scary podcasts. Guess what, Last Podcast On The Left isn’t really scary. The Last Podcast On The Left covers all the horrors our world has to offer both imagined and real, from demons and slashers to cults and serial killers, The Last Podcast is guaranteed to satisfy your blood lust. At least that’s what their description says. So if you dig those stuff then this podcast is for you.

Using PDO in PHP

| Comments

In this tutorial I’m going to walk you through how to use the PDO extension in PHP to connect to a MySQL database.

Connecting to the Database

The PDO extension is installed by default on modern versions of PHP so you don’t have to worry about not having it on the machine. You should be upgrading to a recent version any way to take advantage of the security patches and other updates.

To connect to the database, you have to supply a data source name (DSN) as the first argument when creating a new instance of the PDO class. And then pass in the username and password of the user you want to login to the database as the second and third argument. You need to wrap the code in a try..catch block because it will return an error if there’s a problem connecting to the database. Next, set the error mode to return an exception if there’s an error executing a specific database query. And finally, set the emulation of prepared statements to false. This allows you to use the native parametrized query feature of the database instead of emulating it in the PHP side.

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$dsn = 'mysql:dbname=DATABASE-NAME;host=DB-HOST';
$username = 'DATABASE-USER';
$password = 'USER-PASSWORD';
try {
    $db = new PDO($dsn, $username, $password);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
} catch (PDOException $e){
    echo 'could not connect to the database';
}
?>

Inserting Data

Open up phpmyadmin or any database management tool that you’re using and create a new database. Then execute the following query to create a users table. We will be using this table for executing queries in the database. If you’re following along, don’t forget to update the data source name to match the name of the database.

1
2
3
4
5
6
CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL,
  `name` varchar(300) NOT NULL,
  `age` int(11) NOT NULL,
  `email` varchar(300) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=latin1;

Once that’s created, you can now try inserting a new user row in the users table. Just pass in the typical INSERT query as an argument to the query method using the new PDO instance that you created earlier.

1
2
3
4
5
6
7
<?php
$name = 'yoh asakura';
$age = 10;
$email = 'yoh-asakura@gmail.com';

$db->query("INSERT INTO users SET name = '$name', age = '$age', email = '$email'");
?>

Updating Data

If you want to update a specific user, you still use the query method. The only difference is the query that you are passing in. This time you have to pass in an UPDATE query to set the new values and then use the WHERE clause to specify which specific row you want to update. In this case it’s the first row in the users table.

1
2
3
4
5
6
7
8
<?php
$id = 1;
$name = 'ren tao';
$age = 10;
$email = 'ren-tao@gmail.com';

$db->query("UPDATE users SET name = '$name', age = '$age', email = '$email' WHERE id = '$id'");
?>

Deleting Data

If you want to delete a specific row, use the DELETE query and a WHERE clause to specify which rows you want to delete.

1
2
3
4
<?php
$id = 1;
$db->query("DELETE  FROM users WHERE id = '$id'");
?>

Selecting Data

Selecting data still uses the same query method. Only this time you have to pass in a SELECT query. Then you can loop through the results and access the column that you want to output just like you would when accessing an item in an associative array.

1
2
3
4
5
6
<?php
$results = $db->query("SELECT name FROM users");
foreach($results as $row){
    echo $row['name'] . "<br>";
}
?>

If you think objects look better, you can use the setAttribute method to modify the default fetch mode.

1
2
3
<?php
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
?>

Prepared Statements

Prepared statements makes your queries more secure. Why? Because data is treated as data when you use prepared statements. This means that SQL statements such as OR DROP TABLE users wouldn’t work if the user inputs an SQL statement instead of the expected data. This is implemented in PDO by calling the prepare method and then passing in the query that you wish to execute. But instead of supplying the data directly, you replace it with placeholders. In this case the placeholder is :name. You then call the execute method to actually execute the query. This method accepts an associative array containing the placeholder as the key and the actual value that you want to pass in as its value. Finally, you call the FetchAll method to fetch all the results that was returned.

1
2
3
4
5
6
7
8
9
10
11
<?php
$query = $db->prepare("SELECT name FROM users WHERE name LIKE :name");
$query->execute(array(
    ':name' => 'Mr.%'
));

$results = $query->FetchAll();
foreach($results as $row){
    echo $row->name . "<br>";
}
?>

For queries that’s only expected to return a single row, you can use the fetch method instead.

1
2
3
4
5
6
<?php
$query = $db->prepare('SELECT name FROM users WHERE id = :id');
$query->execute(array(':id' => 2));
$user = $query->fetch();
echo $user->name;
?>

Transactions

Transactions in databases is a sequence of database operations that are treated as a single unit. You can use it to ensure that all the queries that you want to execute are all completed successfully. If one fails, nothing is actually committed to the database.

To test transactions, open up your database management tool of choice and execute the following. This will create the other_details table which stores the other details of a user.

1
2
3
4
5
CREATE TABLE IF NOT EXISTS `other_details` (
`id` int(11) NOT NULL,
  `school` varchar(300) NOT NULL,
  `city` varchar(300) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=latin1;

For the example below, I’m using a library called Faker. You can use it to generate fake data to be inserted into the database. You can install it through composer by executing the following command in your working directory.

1
composer require fzaninotto/faker

Once that’s done installing, you can include the autoload file so that it’s loaded in the current file. You can then create a new instance of it and then use the generator that you want. In the code below I’m using the name, numberBetween, email, company and city generators.

1
2
3
4
5
6
7
8
9
10
11
12
<?php
require_once 'vendor/autoload.php';

$faker = Faker\Factory::create();

$name = $faker->name;
$age = $faker->numberBetween(10, 35);
$email = $faker->email;

$school = $faker->company;
$city = $faker->city;
?>

You can then create a new transaction by calling the beginTransaction method. Any queries that are executed after calling this wouldn’t actually commit to the database until you call the commit method. In the example below, I’m executing a query to insert a new user into the users table as well as the other_details table. If any of those 2 queries fails, it won’t be committed to the database.

1
2
3
4
5
6
7
8
9
10
11
<?php
$db->beginTransaction();

$query = $db->prepare("INSERT INTO users SET name = :name, age = :age, email = :email");
$query->execute(array(':name' => $name, ':age' => $age, ':email' => $email));

$query2 = $db->prepare("INSERT INTO other_details SET school = :school, course = :city");
$query2->execute(array(':school' => $school, ':city' => $city));

$db->commit();
?>

Conclusion

That’s it! In this tutorial, you’ve learned how to use the PDO extension in PHP. Note that it’s not only the MySQL database that PDO supports. It also supports other databases such as CUBRID, PostgreSQL, SQLite and many others.

Quick Tip: Introduction to Phpsh

| Comments

In this quick-tip I’ll introduce you to a tool called phpsh. This project has been created for quite some time now. It was created at Facebook but is no longer actively being developed. But this shouldn’t stop you from using it. It’s a really important tool to have especially when you want to quickly test a PHP script. PHPsh is an interactive shell for PHP. It’s features include the following:

  • readline history
  • tab completion
  • quick access to documentation

You can download it directly from this link.

Once you’re done downloading phpsh, extract the zip file and navigate to the extracted folder. Then execute the following commands to install it in your system.

1
2
python setup.py build
sudo python setup.py install

Once that’s done, you can now open any terminal window and execute phpsh to start using it.

To get documentation regarding a specific function, use the d command followed by the name of the function you want to look up. Here are a few examples.

1
2
3
d echo
d array_push
d array_filter

It will then output the documentation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# echo

(PHP 4, PHP 5)

echo -- Output one or more strings

### Description

void echo ( string $arg1 [, string $... ] )

Outputs all parameters. 

echo() is not actually a function (it is a language construct), so you are not required to use parentheses with it. echo() (unlike some other language constructs) does not behave like a function, so it cannot always be used in the context of a function. Additionally, if you want to pass more than one parameter to echo(), the parameters must not be enclosed within parentheses. 

echo() also has a shortcut syntax, where you can immediately follow the opening tag with an equals sign. This short syntax only works with the [short_open_tag][1] configuration setting enabled. 

` I have <?=$foo?> foo. `

### Parameters

arg1     

The parameter to output. 

...     

### Return Values

No value is returned. 

### 

   [1]: #ini.short-open-tag

Aside from directly accessing the docs, you can also write and execute any PHP code that you wish to test. Here’s a screenshot of me declaring an array and then looping through it.

phpsh

You can also connect to a database and perform operations on it.

db

That’s it for this quick-tip. I hope I’ve encouraged you to use phpsh on your projects.

Introduction to Absentist

| Comments

Lately I’ve been working on a few projects that will ease up all the housekeeping work that I need to do as a teacher. Things like checking the attendance of students and checking the works of students.

When I started working as a teacher, I used a spreadsheet to monitor attendance. There’s a column for the name of the student and a column for meeting days. That’s about 36 columns for the laboratory, where I meet them 2 times per week. And then 18 columns for the lecture, where I meet them once per week. What I do is to put an A in the cell where the student and the day intersects if the student is absent. And when a student accumulates 2 of those A’s in the laboratory, then they’re ripe for dropping. And for the lecture, they only need one. When I say drop, it means dropping the class card of the student to the Student Affairs Office. I won’t dive in too much with the details but this process is implemented so the students wouldn’t want to be absent too often. Because its really a pain to claim class cards.

Going back to my old process in monitoring attendance, here’s what the spreadsheet that I used for monitoring looks like:

attendance spreadsheet

Well, guess what. This quickly turned into a headache. Because there’s no way to monitor which students are currently dropped, which one’s are ripe for dropping and which one’s has already returned their class cards to me.

As a programmer, I always want to make my work easy. Make the computer do most of the work as much as possible. So I decided to work on this project which I now call as Absentist. It’s an attendance monitoring app which is custom built for my current needs. The way it works is simple. First, the teacher creates a class and adds the students. This part asks for the details such as the name of the class, some additional details that the teacher wants to enter, the number of absences needed before dropping the class card, the meeting days, then the start time and end time for each meeting day. Since the school already has a system for accessing class details. All I needed to do was to export it to a spreadsheet and then copy-paste it to a textarea. Then in the back-end, I simply parsed the pasted data so I can extract the ID Number, First Name, Last Name, Middle Initial and the gender of the student.

new class

Once a class has been created, it is listed in the classes page. This page has the links for updating a class, viewing students that are ripe for dropping and students that are already dropped.

new class

Here’s what the interface for dropping looks like:

to drop

From here, the teacher can do two things: first is to mark the class card as dropped. This should be done once all the class cards has been dropped. Currently there’s no button for dropping everything with a single click but this would do for now. There should only be a few clicks needed. Next is the absences link, this shows all the days that the student was absent.

absences

Next is the page for viewing class card that has already been dropped. From here, the teacher can click on the claim button to mark that the student has returned their class card. When this button is clicked, the absences counter for that student goes back to 0.

dropped

But how is the attendance actually updated you ask? It is through the attendance page. This uses the days and time that has been entered on the class settings. When the attendance page is accessed in a time between the start time and end time that was entered and the day matches. Then it will automatically show a list of students in the class. From there, the teacher can call on the students one by one. If a student is absent but is not excused then the absent button beside that student is clicked. If excused then the excused button is clicked. The only difference between the 2 is that excused absences aren’t counted as an actual absence. Its just there for the sake of recording.

update attendance

Once the roll call is done, the teacher can then filter the list to only show the students who are absent or excused. This is useful for verifying if all the students in the list are really absent or excused. If not then the absent or excused button is clicked again to remove the student from the list. Once that’s done, the update attendance button is clicked to commit the changes to the database. This increments the absences counter for the student if they are absent. Or marks the student to be dropped if the absences counter becomes equal to that of what was added to the class settings.

update attendance

Future Plans

Future plans for this project includes the following:

  • Adding students one at a time. This would be useful for when a student comes in late or for instances where there’s no available spreadsheet export for student data.
  • Different start and end times for each meeting day.
  • User Documentation

That’s it! If you want to use this project or contribute to it, you can download it on Github.

Database Migrations in PHP With Phinx

| Comments

Gone are the days where you use the export functionality of your database management tool and share the SQL file to your team mates. Most PHP frameworks today already comes with a database migration tool which you can use to construct and make changes to your database and easily share them through your version control system of choice. In this tutorial I’ll be walking you through Phinx, a database migration tool for PHP.

If you don’t know what a database migration is, it’s basically a way to version your database. Pretty much like what you do with version control systems like Git, SVN or Mercurial. It allows you to make changes to your database and easily rollback any of those changes later on if you make a mistake or if there are some changes that needs to be implemented. You can then share the changes you’ve made to your team by committing it to your version control system and pushing it to the main repository of your project. Your team mates can then pull those changes into their own copy and run the migrations so that they have the same state of the database as you do.

Installation

You can install Phinx through Composer by executing the following commands on your terminal. If you have an existing project, you can navigate to your project directory and execute it from there.

1
2
composer require robmorgan/phinx
composer install --no-dev

Next create a migrations folder. This is where the database migrations are going to be stored.

Finally, execute the following command to initialize Phinx.

1
php vendor/bin/phinx init

Configuration

When Phinx was initialized, you might have noticed that it created a phinx.yml file on the root of your project. This file is the Phinx configuration. This is where you can modify the database used by Phinx for production, development and testing environments. By default Phinx uses the development environment so go ahead and modify the details for that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
paths:
    migrations: %%PHINX_CONFIG_DIR%%/migrations

environments:
    default_migration_table: phinxlog
    default_database: development
    production:
        adapter: mysql
        host: localhost
        name: production_db
        user: root
        pass: ''
        port: 3306
        charset: utf8

    development:
        adapter: mysql
        host: localhost
        name: development_db
        user: root
        pass: ''
        port: 3306
        charset: utf8

    testing:
        adapter: mysql
        host: localhost
        name: testing_db
        user: root
        pass: ''
        port: 3306
        charset: utf8

Usage

Using Phinx mainly composed of the following workflow:

  1. Create a migration
  2. Modify the migration class
  3. Run the migration
  4. If you need to make a change to a previous migration, roll it back, make the change to the migration class and run the migration again.

Creating Migrations

To create a new migration, you use the Phinx shell script. Below is a migration for creating a users table.

1
php vendor/bin/phinx create CreateUsersTable

This creates a new file in the migrations directory. For me it created a file named 20150727004941_create_users_table.php. The filename is made up of the timestamp and the machine-friendly version of the name of the migration that you provided.

It’s best practice that you name your migrations based on what they do, so that you can easily look for them if you need to modify something. Each migration should only be doing one specific task so that you can easily roll them back without having to worry about side-effects. Creating a users table should add the fields that are necessary to that table. But if you’re modifying a specific table, in most cases, you should only modify one field at a time. For example, you need to modify the data type from INT to VARCHAR. Only modify one field. But if it makes sense to change two or more fields in a single migration, then do so. For example, if you need to modify the length of the username and password fields so they can accomodate more data.

Going back to the migration file. Open it up if you haven’t yet. Here’s how it looks like by default.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

use Phinx\Migration\AbstractMigration;

class CreateUsersTable extends AbstractMigration
{
    /**
     * Change Method.
     *
     * Write your reversible migrations using this method.
     *
     * More information on writing migrations is available here:
     * http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class
     */
    public function change()
    {

    }
}
?>

Phinx already creates a skeleton class for you s you only need to modify what’s in the change function. This is where you need to add the code for modifying your database. In this case the change is to create a users table. Add the following inside the change function.

1
2
3
4
5
6
7
<?php
  $table = $this->table('users');
  $table->addColumn('username', 'string')
      ->addColumn('email', 'string')
      ->addColumn('password', 'string')
      ->create();
?>

The table is declared using the table function. This accepts the name of the table as its argument. The fields are then added by calling the addColumn method in the table. This accepts 2 required arguments: the name of the field and the data type. Finally, the create function is called to actually create the table. Once that’s done, save the file.

Let’s pretend we forgot to add the photo field, so create another migration to add that.

1
php vendor/bin/phinx migrate AddPhotoFieldToUsersTable

Add the following inside the change method.

1
2
3
$table = $this->table('users');
$table->addColumn('photo', 'string', array('after' => 'username'))
        ->update();

Nothing new here, the only thing that’s changed is the method to be called to actually execute the change that you need to make. In this case instead of create, the update method is used. This is how Phinx will know that you are trying to update the users table by adding the photo field.

Running Migrations

You can run all the migrations that haven’t been run yet by using the migrate command.

1
php vendor/bin/phinx migrate

It would output something similar to the following when the migration is run.

1
2
3
4
5
6
7
8
9
10
11
warning no environment specified, defaulting to: development
using adapter mysql
using database tester

 == 20150727004941 CreateUsersTable: migrating
 == 20150727004941 CreateUsersTable: migrated 0.3325s

 == 20150727013547 AddPhotoFieldToUsersTable: migrating
 == 20150727013547 AddPhotoFieldToUsersTable: migrated 0.5018s

All Done. Took 0.6773s

You can now check if the table was actually created by opening your database management tool of choice. Also notice that there is a phinxlog table in your database. This is used by Phinx to keep track of which specific migrations were run and the start and end time for each. The migration is determined by its version, which is basically the first part of the file name for a specific migration file. On my testing, the version is 20150727004941.

Rolling Back Changes

To rollback changes you can use the rollback command which does exactly the opposite of the migrate command. All it does is rollback everything that has changed on the last migrate.

1
php vendor/bin/phinx rollback

The command above outputs something similar to the following:

1
2
3
4
5
6
7
8
9
10
11
warning no environment specified, defaulting to: development
using adapter mysql
using database tester

 == 20150727013547 AddPhotoFieldToUsersTable: reverting
 == 20150727013547 AddPhotoFieldToUsersTable: reverted 0.4672s

 == 20150727004941 CreateUsersTable: reverting
 == 20150727004941 CreateUsersTable: reverted 0.1503s

All Done. Took 0.6175s

Conclusion

That’s it! In this tutorial, you’ve learned how to create database migrations with Phinx. Be sure to check out the official documentation if you want to learn more.

Working With the Filesystem With Flysystem

| Comments

Installation

You can install Flysystem via Composer.

1
composer require league/flysystem

Usage

To use Flysystem, you first have to include the vendor autoload file which you got when you installed Flysystem on your working directory. After that, use the Filesystem class in the League\Flysystem namespace and the Local class in the League\Flysystem\Adapter namespace. The Filesystem class allows you to use the main Flysystem package. And the Local class allows you to use the local adapter. With Flysystem it’s not just the local filesystem that you can work with. It has adapters for any cloud storage service that you can think of. Theres an adapter for Dropbox, FTP, AWS S3, Rackspace and even a Zip archive. So the Local class allows you to work with files in your local filesystem.

1
2
3
4
5
6
<?php
require_once 'vendor/autoload.php';

use League\Flysystem\Filesystem;
use League\Flysystem\Adapter\Local;
?>

Next, create a new instance of the Local class and pass in the path to the base path you want to work with. This allows you to create an adapter for a local path in your filesystem. In the example below, it’s the upload directory located in the root of my working directory. After that, create a new instance of the Filesystem class and pass in the local adapter as the argument.

1
2
3
4
<?php
$adapter = new Local(__DIR__ . '/uploads');
$filesystem = new Filesystem($adapter);
?>

Once that’s done, you can now use Flysystem to wreack havoc on your local filesystem.

Check if File Exists

To check if a file exists, you can use the has method and then pass in the path to the file. Remember that this uses the root path that you passed in when you created the local adapter.

1
2
3
<?php
$exists = $filesystem->has('path/to/image.png');
?>

Read Files

Reading files only really makes sense for text files. You can use the read method for this.

1
2
3
<?php
$contents = $filesystem->read('path/to/file.txt');
?>

Write to Files

When writing to files, the path doesn’t need to already exist. You can pass in a long path and it will create the individual directories that precedes the actual file.

1
2
3
<?php
$contents = $filesystem->write('path/to/file.txt');
?>

Copy Files

Copying files can work with any file type and the destination doesn’t need to be the same path where the original file exists.

1
2
3
<?php
$filesystem->copy('original.txt', 'path/to/copy.txt');
?>

Rename Files

You can use the rename method to rename files. This also doubles as a move function because you can assign the same name to the file but have a different path.

1
2
3
4
<?php
$filesystem->rename('original_name.txt', 'new_name.txt'); //rename
$filesystem->rename('original_name.txt', 'path/to/original_name.txt'); //move
?>

Delete Files

If you want to delete a file, use the delete method.

1
2
3
<?php
$filesystem->delete('path/to/file.txt');
?>

Listing Contents of a Directory

To list the contents of the root directory, you need to call the listContents method. This returns an array containing the items in the root directory. Note that this isn’t a recursive function. This means that only the direct children of the root directory is going to be listed.

1
2
3
4
5
6
7
8
<?php
$contents = $filesystem->listContents();
foreach ($contents as $object) {
  if ($object['type'] == 'file') {
    echo $object['basename'] . "<br>";
  }
}
?>

Get File Information

You can use any of the functions below to get specific information about the file.

1
2
3
4
5
<?php
$mimetype = $filesystem->getMimetype('path/to/photo.jpg'); // image/jpeg
$timestamp = $filesystem->getTimestamp('path/to/photo.jpg'); // 1438143700
$size = $filesystem->getSize('path/to/photo.jpg'); // 101771
?>

Exceptions

When performing an operation on the filesystem, be sure to wrap it in a try..catch block so that you can handle the errors accordingly. In the example below, if file.txt doesn’t exists in the directory, it would return an error.

1
2
3
4
5
6
7
<?php
try {
    $filesystem->delete('file.txt');
} catch (Exception $e) {
    echo $e->getMessage();
}
?>

Conclusion

In this tutorial, you’ve learned how to ease filesystem work with the Flysystem library. You have barely scratch the surface with what’s possible with Flysystem. Be sure to check out their official website to learn more.

Getting Started With Ionic

| Comments

Hybrid Mobile App Development has been gaining traction lately. With the advent of tools such as Cordova, Sencha Touch and Titanium. There’s no more stopping web developers from creating their own mobile apps with web technologies. Yes I just said web technologies, that’s HTML, CSS, JavaScript and a little bit of talking to a server and you can already create a fancy mobile app. And because of this, lots of mobile frameworks has popped out. There’s Ionic, Onsen UI, Junior, Mobile Angular UI, and Kendo UI to name a few. Of those I’ve only ever tried jQuery Mobile and Ionic. At first I tried jQuery Mobile since I was already using jQuery for a long time. But it didn’t take me long to realize that it wasn’t for me nor the project that I was working on at that time. It just didn’t have what I need. jQuery Mobile is just a set of UI components that I could use in a mobile app. It didn’t have the foundation in which I could build upon. What I needed was a framework that would allow me to just start writing the app without having to worry about laying out the structure myself. This is where Ionic came in. It didn’t take me long to find it since it’s the first result that came up when I googled ‘mobile hybrid app framework’. Ionic utilizes Angular for its UI interactions, gestures and animations. And the best part is you can also use it to structure your app, because Angular itself is a JavaScript framework. Ok this intro is getting long. Let’s proceed with the fun stuff.

Setup

Node

In order to start working with Ionic, you first have to install Node. Go ahead and download the installer for your platform if you don’t already have it. If you’re an Ubuntu user, you can install Node using NVM (Node Version Manager). To install NVM, execute the following commands in order:

1
2
3
4
5
sudo apt-get install build-essential libssl-dev

curl https://raw.githubusercontent.com/creationix/nvm/v0.16.1/install.sh | sh

source ~/.profile

The first command, installs the build tools and SSL development libraries. The second downloads the NVM installer, and the third sources the ~/.profile file so that your current command-line session knows about the changes. This basically allows you to use the NVM command without having to logout.

Next, you can now list the available Node versions:

1
nvm ls-remote

This will list out a whole bunch of Node versions that are available. But usually you would want to install the current version, which is the last item on the list. At the time of writing of this article, the current version is v0.12.7. So you can go ahead and install that using the nvm install command:

1
nvm install v0.12.7

Now when you check the Node version installed on your machine, you would see v0.12.7.

1
node -v

Next you need to set this version as the default, otherwise you’ll have to execute nvm use v0.12.7 every time you need to use Node.

1
2
nvm alias default v0.12.7
nvm use default

Cordova and Ionic

Now we’re ready to install Cordova and Ionic:

1
npm install -g cordova ionic

Once that’s done installing, you can create a new project using the ionic start command. There are currently 3 available starter templates you can use: blank, tabs, and sidemenu. In this tutorial we’re going to use the tabs.

1
ionic start demoApp tabs

Ionic Directory Structure

The command above will create a demoApp directory which contains the following:

1
2
3
4
5
6
7
8
9
hooks
plugins
scss
www
bower.json
config.xml
gulpfile.js
ionic.project
package.json

The hooks directory is where you will put the scripts for customizing Cordova commands. I’ve never had the need to use this feature so I can’t share anything about it. But if you’re just getting started, you wouldn’t normally need to touch this directory.

The platforms directory is where the different platforms in which your app will be compiled to is stored. Note that its not there by default, you have to install a platform first.

The plugins directory is where Cordova plugins gets installed.

The scss directory is where the main Ionic sass file (ionic.app.scss) is stored. It contains the primary variables for customizing the colors used in your app.

The www directory is where you would usually work. This contains the HTML, JavaScript and CSS files. I won’t walk you through each of the contents of the www directory as they’re pretty self-explanatory.

The bower.json file contains the front-end dependencies of your app. By default it depends on Ionic. All bower dependencies are installed on the www/lib directory by default. You can install new one’s by using the bower install command and then link them on the index.html file in the www directory. When you install new libraries using bower, use the --save or --saveDev option so that it will save the package name on the bower.json file. The --save option is used to specify that the library you’re installing is a front-end asset. For example, jQuery or Bootstrap. While the --saveDev option is used for development only. Things like jshint or jasmine.

The config.xml file is where you can change the name, description and author of your app. You can also set your preference for device orientation (either portrait or landscape), features and URL’s which your app is allowed to access.

The gulpfile.js file is the Gulp config file used by Ionic. Normally you wouldn’t need to touch this. What you need to understand is that this is used by Ionic to execute tasks such as compiling sass files to CSS or watching a specific directory for changes.

The ionic.project file is where you can update the name and app_id of your app. You won’t really need to touch this.

Lastly, the package.json file. This contains the dependencies of the Ionic framework. You won’t really need to touch this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "name": "demoapp",
  "version": "1.0.0",
  "description": "demoApp: An Ionic project",
  "dependencies": {
    "gulp": "^3.5.6",
    "gulp-sass": "^1.3.3",
    "gulp-concat": "^2.2.0",
    "gulp-minify-css": "^0.3.0",
    "gulp-rename": "^1.2.0"
  },
  "devDependencies": {
    "bower": "^1.3.3",
    "gulp-util": "^2.2.14",
    "shelljs": "^0.3.0"
  },
  "cordovaPlugins": [
    "cordova-plugin-device",
    "cordova-plugin-console",
    "cordova-plugin-whitelist",
    "cordova-plugin-splashscreen",
    "com.ionic.keyboard"
  ],
  "cordovaPlatforms": []
}

Platforms

With Cordova there’s only a select few platforms that it supports. So it’s not completely write once, compile to all kind of thing. There are different sets of problems to solve for each platform in which you plan to release your app. The common platforms that you may want to install are android, ios and browser. For a list of all the platforms supported by Cordova, you can check out the Cordova Platform Guides. Each platform has a different dependency. Usually it’s the SDK or the recommended developer tool for that platform. For Android, it’s the Android SDK, for iOS it’s Xcode, for Windows it’s Visual Studio. I’m only going to walk you through the Android platform in this tutorial.

You can download the Android SDK installer from this page. Under the SDK Tools Only section, download the package for your platform. I’m on Ubuntu so I will download the one for Linux. Once the download is done, extract the files using the tar command or you can also right click on the file and select the archive manager of your choice.

1
tar -xvzf android-sdk_r24.3.3-linux.tgz

After extraction, it would yield an android-sdk-linux folder which contains the following:

1
2
3
4
add-ons
platforms
tools
SDK Readme.txt

From that directory, navigate to the tools directory and execute the android command:

1
./tools/android

This will open up the Android SDK Manager which you can use to install the tools that you need to develop Android apps. At this point you might wonder why we need to install the same things that Android developers need to install. Well, that’s because we’re still subjected to the same rules even if we write our apps using HTML, CSS, and JavaScript. Since apps created with Cordova and Ionic are just utilizing the Android WebView. Which is basically just a browser without a frame. That’s where the HTML, CSS and JavaScript are used. And Cordova just acts as a middleman between the WebView and the native Android functionalities. So if you need to use the camera for your app, Cordova uses the Android API to call for the camera. And once you’re done taking a picture it’s also the one responsible for returning the data back to your app. This means that Cordova just abstracts away the parts which we usually need to work on as native app developers so we can write our code in JavaScript instead of Java.

Back to where we left. Let’s now install the tools we need to get Cordova do its job. Check the following items on the Android SDK Manager and click on Install. This might take a while depending on your download speed.

Tools – Android SDK Tools

Android 5.1.1 (API 22) – SDK Platform

Android 5.0.1 (API 21) – SDK Platform – Google APIs

Android 4.4W.2 (API 20) – SDK Platform

Android 4.4.2 (API 19) – SDK Platform – Google APIs (ARM System Image)

Extras – Android Support Repository – Android Support Library – Google Repository

Once that’s done installing, add the path in which the Android SDK is installed to your environment. In Ubuntu and OSX, you can add the following on your .bashrc file:

1
2
3
export ANDROID_HOME=/path/to/android-sdk-linux/sdk
PATH=$PATH:/path/to/android-sdk-linux/sdk/tools
export PATH

In Windows, there’s something called the Environment Variables. I’ve written about it in my old blog: How to set environment variables.

Once that’s done, you can now install the Android platform, you can use the ionic platform add command followed by the name of the platform you want to install.

1
ionic platform add android

Using Sass

You can use sass with ionic by executing the following command while inside your project directory:

1
ionic setup sass

What this does is install the packages and tasks needed to compile sass. Then remove the following from your index.html file:

1
2
<link href="lib/ionic/css/ionic.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">

It also adds the link to the ionic.app.css file which is basically just the compiled version of the ionic.app.scss file found in the scss directory.

1
<link href="css/ionic.app.css" rel="stylesheet">

Finally, it adds the following in your ionic.project file. This tells ionic to start the sass and watch command when gulp starts. It also specifies the watch patterns, so that every time you make a change to a file that matches the pattern, the sass command gets executed and compiles the sass files to css.

1
2
3
4
5
6
7
8
  "gulpStartupTasks": [
    "sass",
    "watch"
  ],
  "watchPatterns": [
    "www/**/*",
    "!www/lib/**/*"
  ]

If you want to change the default colors used by Ionic, this is where you can do that. Be sure to uncomment the variables just like what we have below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
To customize the look and feel of Ionic, you can override the variables
in ionic's _variables.scss file.

For example, you might change some of the default colors:
*/

$light:                           #fff !default;
$stable:                          #f8f8f8 !default;
$positive:                        #387ef5 !default;
$calm:                            #11c1f3 !default;
$balanced:                        #33cd5f !default;
$energized:                       #ffc900 !default;
$assertive:                       #ef473a !default;
$royal:                           #886aea !default;
$dark:                            #444 !default;


// The path for our ionicons font files, relative to the built CSS in www/css
$ionicons-font-path: "../lib/ionic/fonts" !default;

// Include all of Ionic
@import "www/lib/ionic/scss/ionic";

Now anytime you make a change to the file while running ionic serve, it will compile it to the ionic.app.css found at the www/css directory.

Developing an App

You can start developing your app by executing ionic serve from the root directory of your project. This will launch a new browser tab containing the app. If you’re using Chrome, you can click on the phone icon on the left of the elements tab when you open the developer tools. This would show your app inside a smaller screen depending on the device that you specify. You can change the device by clicking on the drawer icon which looks like this: >__. And then click on the emulation tab then select the device from the model dropdown. You might need to refresh the page after doing this so that it will render correctly.

app window

Now open the index.html file in the root directory of your project. This is where every thing is hooked up. If you have ever developed a single-page app before, this would be familiar to you. Basically how a single-page app works is that every script that you need is linked in the index.html file. You might be thinking this is a bad practice since it will take too long for the page to load. Well it’s not since the front-end assets are included in the app locally. It wouldn’t need to download it over the internet so it’s fast even if we have a lot of files linked in there.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>


    <!-- compiled css output -->
    <link href="css/ionic.app.css" rel="stylesheet">

    <!-- ionic/angularjs js -->
    <script src="lib/ionic/js/ionic.bundle.js"></script>

    <!-- cordova script (this will be a 404 during development) -->
    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="js/app.js"></script>
    <script src="js/controllers.js"></script>
    <script src="js/services.js"></script>
  </head>
  <body ng-app="starter">
    <!--
      The nav bar that will be updated as we navigate between views.
    -->
    <ion-nav-bar class="bar-stable">
      <ion-nav-back-button>
      </ion-nav-back-button>
    </ion-nav-bar>
    <!--
      The views will be rendered in the <ion-nav-view> directive below
      Templates are in the /templates folder (but you could also
      have templates inline in this html file if you'd like).
    -->
    <ion-nav-view></ion-nav-view>
  </body>
</html>

Ok let’s break this file down. First we set the charset to utf-8 and viewport so that the initial and maximum scale is 1, we also set the user-scalable option to no. This basically means the user wouldn’t be able to resize or zoom the app.

1
2
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">

Next we have the title. This means nothing since we’re on an app not a website. So users wouldn’t be able to see this. You can leave it as blank.

1
<title></title>

And we also have the main ionic css file.

1
2
 <!-- compiled css output -->
<link href="css/ionic.app.css" rel="stylesheet">

Angular is bundled together with the Ionic JavaScript.

1
2
<!-- ionic/angularjs js -->
<script src="lib/ionic/js/ionic.bundle.js"></script>

We also need to link the cordova.js file so we can use Cordova within our app. This would allow us to use Cordova plugins as well via cordova.plugins.

1
2
<!-- cordova script (this will be a 404 during development) -->
<script src="cordova.js"></script>

Then we have our custom JavaScript files. This is where we put code that makes the app do things for us. Note that the js/app.js file is the main JavaScript file. It is where we link every thing together. This is where we intialize a new module in which we could hook up different parts of our app. If we need to use a new service, this is where we hook it up. If we want to add a new state, this is where we add it. If we need to call a specific function every time the app starts, this is where we do it. Next we have the js/controllers.js file, in the default controller created by Ionic, all the controllers are added in a single file. This is fine for really small apps but for medium to large size apps it’s recommended to have a single controller for each entity in your app. For example, you might have a user controller where you put all the code that has something to do with the user. Things like updating user settings. The controller is where you usually put code that responds to a specific event such as clicking a button or pulling to refresh. Lastly, we have the js/services.js file. A service is responsible for adding a specific functionality to your app. You would want to create a service for making requests to your server, or storing data in local storage. It’s recommended that you search for existing solutions first before writing your own services. So you won’t waste time re-implementing the same thing.

1
2
3
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/services.js"></script>

Then we have the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<body ng-app="starter">
    <!--
      The nav bar that will be updated as we navigate between views.
    -->
    <ion-nav-bar class="bar-stable">
      <ion-nav-back-button>
      </ion-nav-back-button>
    </ion-nav-bar>
    <!--
      The views will be rendered in the <ion-nav-view> directive below
      Templates are in the /templates folder (but you could also
      have templates inline in this html file if you'd like).
    -->
    <ion-nav-view></ion-nav-view>
</body>

In a typical Angular app we set the ng-app attribute to the name of the module. Ionic has used starter as the name of the module by default. You can change that on your app.js file. Here the name of the module is starter.

1
angular.module('starter', ['ionic', 'starter.controllers', 'starter.services'])

You can change it to the following if you want. Here the name of the module is changed to my_awesome_app:

1
angular.module('my_awesome_app', ['ionic', 'my_awesome_app.controllers', 'my_awesome_app.services'])

If you did change the name of the module. You also need to change the value of the ng-app attribute:

1
<body ng-app="my_awesome_app">

As well as your controllers and services:

1
2
angular.module('my_awesome_app.controllers', [])
angular.module('my_awesome_app.services', [])

Going back to the app.js file. This is the code responsible for setting the name of the module and the services and controllers it depends on. By default it depends on the ionic service, and your custom controllers and services.

1
angular.module('my_awesome_app', ['ionic', 'my_awesome_app.controllers', 'my_awesome_app.services'])

You can think of my_awesome_app.controllers and my_awesome_app.services as a submodule of the my_awesome_app module. We declared those two modules in the js/controllers.js and js/services.js file.

1
2
angular.module('my_awesome_app.controllers', [])
angular.module('my_awesome_app.services', [])

You might be wondering what’s the need for these sub-modules? Well, their main purpose is to have a different parent module for each controller and service. So every controller would depend on the my_awesome_app.controllers module and all services would depend on the my_awesome_app.services module. We do this because simply depending on the main module wouldn’t work:

1
angular.module('my_awesome_app', [])

Next we have the run function. This is where Ionic executes functions which needs to be executed every time the app is opened. All function calls should be wrapped in the $ionicPlatform.ready event to make sure all the plugins and other features that we need are loaded. Inside the event, we check if the Cordova keyboard plugin is accessible. If it is then we hide the keyboard accessory bar. Finally we use the lightContent statusbar (light text for dark backgrounds) by calling the styleLightContent method provided by the StatusBar plugin.

1
2
3
4
5
6
7
8
9
10
11
12
13
.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if (window.StatusBar) {
      // org.apache.cordova.statusbar required
      StatusBar.styleLightContent();
    }
  });
})

Next we set the app configuration by calling the config method in the Angular module. You can use this to set the routes of your app.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
.config(function($stateProvider, $urlRouterProvider) {

  // Ionic uses AngularUI Router which uses the concept of states
  // Learn more here: https://github.com/angular-ui/ui-router
  // Set up the various states which the app can be in.
  // Each state's controller can be found in controllers.js
  $stateProvider

  // setup an abstract state for the tabs directive
    .state('tab', {
    url: "/tab",
    abstract: true,
    templateUrl: "templates/tabs.html"
  })

  // Each tab has its own nav history stack:

  .state('tab.dash', {
    url: '/dash',
    views: {
      'tab-dash': {
        templateUrl: 'templates/tab-dash.html',
        controller: 'DashCtrl'
      }
    }
  })

  .state('tab.chats', {
      url: '/chats',
      views: {
        'tab-chats': {
          templateUrl: 'templates/tab-chats.html',
          controller: 'ChatsCtrl'
        }
      }
    })
    .state('tab.chat-detail', {
      url: '/chats/:chatId',
      views: {
        'tab-chats': {
          templateUrl: 'templates/chat-detail.html',
          controller: 'ChatDetailCtrl'
        }
      }
    })

  .state('tab.account', {
    url: '/account',
    views: {
      'tab-account': {
        templateUrl: 'templates/tab-account.html',
        controller: 'AccountCtrl'
      }
    }
  });

  // if none of the above states are matched, use this as the fallback
  $urlRouterProvider.otherwise('/tab/dash');

});

Breaking it down, we use the $stateProvider to set different states. A state is equivalent to a route in your app. You can call the state method to create a new route, this accepts the name of the state as its first argument and the config as its second.

1
2
3
4
5
6
 // setup an abstract state for the tabs directive
    .state('tab', {
    url: "/tab",
    abstract: true,
    templateUrl: "templates/tabs.html"
})

A state can be abstract or not. You usually declare a state as an abstract one if it has a child state. In the above example the tab state is an abstract one. This means you don’t access it directly from your browser. Instead, you access its child states. In this case the child states are dash, chats, chat-detail and account.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  .state('tab.dash', {
    url: '/dash',
    views: {
      'tab-dash': {
        templateUrl: 'templates/tab-dash.html',
        controller: 'DashCtrl'
      }
    }
  })
 .state('tab.chats', {
      url: '/chats',
      views: {
        'tab-chats': {
          templateUrl: 'templates/tab-chats.html',
          controller: 'ChatsCtrl'
        }
      }
    })
    .state('tab.chat-detail', {
      url: '/chats/:chatId',
      views: {
        'tab-chats': {
          templateUrl: 'templates/chat-detail.html',
          controller: 'ChatDetailCtrl'
        }
      }
    })

  .state('tab.account', {
    url: '/account',
    views: {
      'tab-account': {
        templateUrl: 'templates/tab-account.html',
        controller: 'AccountCtrl'
      }
    }
  });

An abstract state takes the following options:

  • url – the URL that you will use to access the state. For an abstract state, this would be the parent URL that each child state will use.
  • abstract – a boolean value that is set to true to specify that the state is an abstract one.
  • templateUrl – the path to where the template is located locally.

A child state would accept the same options, the only difference is that you have to set the views option and the add a single property with the name of the view. Then that property would have the templateUrl property and controller which is basically the name of the controller that the state uses. The controller property is optional, you can set this on the template if you want. But you have to note that you can’t specify the controller name on both the template and the app.js file. Otherwise methods that run every time the controller is executed is called twice. Here is a sample child state. As you can see the url is set to /chats but you would need to specify the URL of the abstract state first. So accessing it in the brower would be tab/chats.

1
2
3
4
5
6
7
  url: '/chats',
  views: {
    'tab-chats': {
      templateUrl: 'templates/tab-chats.html',
      controller: 'ChatsCtrl'
    }
  }

Next we specify the views with the view property. As I’ve said earlier, this accepts the name of the view as its property. This is tied with the name of the view in the ion-tabs directive. You can find it in the templates/tabs.html file. The view name property in the ion-nav-view directive should be the same as the name of view in your state declaration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!--
Create tabs with an icon and label, using the tabs-positive style.
Each tab's child <ion-nav-view> directive will have its own
navigation history that also transitions its views in and out.
-->
<ion-tabs class="tabs-icon-top tabs-color-active-positive">

  <!-- Dashboard Tab -->
  <ion-tab title="Status" icon-off="ion-ios-pulse" icon-on="ion-ios-pulse-strong" href="#/tab/dash">
    <ion-nav-view name="tab-dash"></ion-nav-view>
  </ion-tab>

  <!-- Chats Tab -->
  <ion-tab title="Chats" icon-off="ion-ios-chatboxes-outline" icon-on="ion-ios-chatboxes" href="#/tab/chats">
    <ion-nav-view name="tab-chats"></ion-nav-view>
  </ion-tab>

  <!-- Account Tab -->
  <ion-tab title="Account" icon-off="ion-ios-gear-outline" icon-on="ion-ios-gear" href="#/tab/account">
    <ion-nav-view name="tab-account"></ion-nav-view>
  </ion-tab>


</ion-tabs>

Now open up the controllers.js file. On the first line we’re declaring a new module called my_awesome_app.controllers. If you remember from earlier, this is one of the modules that we specified as a dependency for the main module in the app.js file.

1
angular.module('my_awesome_app.controllers', [])

Then we create a new controller by using the controller method. This accepts the name of the controller as its first argument and the function to execute when the controller is accessed as its second. For the DashCtrl, we have an empty function body as we do not need to execute anything.

1
.controller('DashCtrl', function($scope) {})

For the ChatCtrl, we get a list of chat messages using the Chats services. We’ll go through that in a moment, but for now understand that to use a service you need to declare it as a parameter in the function body of the controller. This way you can access it from inside the function and call the different methods that are accessible from that service. Also notice that we have also declared a $scope variable as a parameter. This allows us to pass in data to the current scope. We do this so we can access the data in the view. Back to the Chats service, we are calling the all method in the Chats service. This returns an array of messages. We then assign whatever it returns to the chats property in the $scope. Note that you can name it anything you want. Next we’re also assigning a remove method to the $scope. What this does is remove a specific chat message.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.controller('ChatsCtrl', function($scope, Chats) {
  // With the new view caching in Ionic, Controllers are only called
  // when they are recreated or on app start, instead of every page change.
  // To listen for when this page is active (for example, to refresh data),
  // listen for the $ionicView.enter event:
  //
  //$scope.$on('$ionicView.enter', function(e) {
  //});

  $scope.chats = Chats.all();
  $scope.remove = function(chat) {
    Chats.remove(chat);
  }
})

Here’s the view utilizing the ChatsCtrl. It’s in the templates/tab-chats.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<ion-view view-title="Chats">
  <ion-content>
    <ion-list>
      <ion-item class="item-remove-animate item-avatar item-icon-right" ng-repeat="chat in chats" type="item-text-wrap" href="#/tab/chats/">
        <img ng-src="">
        <h2></h2>
        <p></p>
        <i class="icon ion-chevron-right icon-accessory"></i>

        <ion-option-button class="button-assertive" ng-click="remove(chat)">
          Delete
        </ion-option-button>
      </ion-item>
    </ion-list>
  </ion-content>
</ion-view>

The ChatDetailCtrl is the controller responsible for showing the details of a specific chat message. Here we’re using a new parameter in the function body called $stateParams. This allows us to get the value of a specific route parameter. Route parameters are passed in the URL of the app. If you go back to the app.js file, you can see from the tab.chat-detail state’s URL is /chats/:chatId. The :chatId here is the route parameter. Every route parameter in Angular always starts in a colon followed by the name. So in the ChatDetailCtrl we are merely getting the value passed in this route parameter and then using it as an argument for the get method in the Chats service. This method basically fetches a specific chat message from the array of chats. We then just assign the value to the chat variable in the $scope.

1
2
3
.controller('ChatDetailCtrl', function($scope, $stateParams, Chats) {
  $scope.chat = Chats.get($stateParams.chatId);
})

You can see this being used in the templates/chat-detail.html.

1
2
3
4
5
6
7
8
<ion-view view-title="">
  <ion-content class="padding">
    <img ng-src="" style="width: 64px; height: 64px">
    <p>
      
    </p>
  </ion-content>
</ion-view>

Finally we have the AccountCtrl. Nothing fancy here. All we’re doing is passing in an object to the scope.

1
2
3
4
5
.controller('AccountCtrl', function($scope) {
  $scope.settings = {
    enableFriends: true
  };
});

We can see this being used from the view in templates/tab-account.html:

1
2
3
4
5
6
7
8
9
<ion-view view-title="Account">
  <ion-content>
    <ion-list>
    <ion-toggle  ng-model="settings.enableFriends">
        Enable Friends
    </ion-toggle>
    </ion-list>
  </ion-content>
</ion-view>

From the above HTML, the enableFriends property is used as the model for the ion-toggle directive which basically just outputs a switch UI. In this case the switch should be turned on since the value of the enableFriends property is true.

Now we take a look at the service file at js/services.js. Same with the controllers, we declare a new module called my_awesome_app.services. From there we call the factory method in order to create a service. We call this service Chats. Inside the function body, we have an array of objects containing the details for each chat message. After that, we expose the methods that we want the controllers that will use this service to use by returning them. Here we have 3 methods, the all method which just returns all the chat messages. The remove method which removes a specific chat message from the array of chat messages. And last is the get method, which returns a specific chat message based on the id.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
angular.module('my_awesome_app.services', [])

.factory('Chats', function() {
  // Might use a resource here that returns a JSON array

  // Some fake testing data
  var chats = [{
    id: 0,
    name: 'Ben Sparrow',
    lastText: 'You on your way?',
    face: 'https://pbs.twimg.com/profile_images/514549811765211136/9SgAuHeY.png'
  }, {
    id: 1,
    name: 'Max Lynx',
    lastText: 'Hey, it\'s me',
    face: 'https://avatars3.githubusercontent.com/u/11214?v=3&s=460'
  },{
    id: 2,
    name: 'Adam Bradleyson',
    lastText: 'I should buy a boat',
    face: 'https://pbs.twimg.com/profile_images/479090794058379264/84TKj_qa.jpeg'
  }, {
    id: 3,
    name: 'Perry Governor',
    lastText: 'Look at my mukluks!',
    face: 'https://pbs.twimg.com/profile_images/598205061232103424/3j5HUXMY.png'
  }, {
    id: 4,
    name: 'Mike Harrington',
    lastText: 'This is wicked good ice cream.',
    face: 'https://pbs.twimg.com/profile_images/578237281384841216/R3ae1n61.png'
  }];

  return {
    all: function() {
      return chats;
    },
    remove: function(chat) {
      chats.splice(chats.indexOf(chat), 1);
    },
    get: function(chatId) {
      for (var i = 0; i < chats.length; i++) {
        if (chats[i].id === parseInt(chatId)) {
          return chats[i];
        }
      }
      return null;
    }
  };
});

Plugins

Plugins allows you to add native functionalities to your app. Things like the camera, calendar, contacts, or flashlight can be controlled using JavaScript through the use of plugins.

You can install plugins by using the ionic plugin add command. Here’s an example of how we might add the camera plugin:

1
ionic plugin add cordova-plugin-camera

If you decide later on that you no longer need a plugin, you can use the ionic plugin rm command:

1
ionic plugin rm cordova-plugin-camera

Every plugin already has the necessary instructions which will setup everything that is needed in order for it to work when installed. Things like putting the necessary permissions in the AndroidManifest.xml file so that you can use specific features of the device.

I won’t dive in much into plugins, what’s important is that you know they are available and you can use Google to look for them. There’s the Cordova Plugin Repository and Github if you want to look for a plugin that can solve your specific problem.

Changing the App Icon and Splash Screens

To change the icon of the app, simply put an icon.png, icon.psd, or icon.ai on the resources directory in the root of your app. For the splash it’s splash.png, splash.psd, or splash.ai. The recommended icon size is 500x500 and the splash image is 1200x1200. Once you’ve added the files, execute ionic resources from the terminal to generate your icons and splash screens.

Compiling to Android

You can create an apk file using the ionic build android command. This will create the android-debug.apk file under the platforms/android/build/outputs/apk directory. Note that this is the debug version of the app. You can use this for testing on your mobile device. But you cannot submit it to the Google Play Store. To do that you’ll have to build a release version for your apk by adding the --release option when using the cordova build. Note that we’re using cordova instead of ionic. Ionic simply wraps the Cordova commands so you can use them interchangeably.

1
cordova build --release android

Next, generate a keystore for the app by using keytool. Breaking down the command below, we’re setting the following options:

  • genkey – not actually an option, but a command to generate the key.
  • keystore – the file name you want to give to the keystore
  • alias – the alias of the key.
  • keyalg – the algorithm to be used to generate the key.
  • keysize – the size of the key in bytes.
  • validity – the number of days in which this keystore will be valid.
1
keytool -genkey -v -keystore demoApp.keystore -alias demoApp -keyalg RSA -keysize 2048 -validity 10000

Executing the command above will ask you for the keystore password and some questions. Just provide an answer to each question since the information that you supply will be used to generate the keystore. Here’s how it looks like in my machine:

keytool

If you cannot use keytool, then maybe you don’t have Java installed yet. You can install it by executing the following commands in order.

1
2
3
4
5
6
7
sudo apt-get install default-jre

sudo apt-get install default-jdk

sudo apt-get install openjdk-7-jre

sudo apt-get install openjdk-7-jdk

Now we’re ready to sign the apk file with the keystore that we generated. To do that, first copy the demoApp.keystore to the platforms/android/build/outputs/apk directory, open a terminal on that directory then execute the following command:

1
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore demoApp.keystore android-release-unsigned.apk demoApp

This will ask you for the password that you entered earlier when you created the keystore.

Finally, to generate the apk that you can submit in the Google Play Store, use zipalign. This accepts the name of the unsigned apk file and the name of the signed apk which it will generate.

1
zipalign -v 4 android-release-unsigned.apk demoApp.apk

If you need the key you can execute the following:

1
keytool -exportcert -alias demoApp -keystore demoApp.keystore | openssl sha1 -binary | openssl base64

Conclusion

That’s it! In this tutorial you’ve learned the basics of working with the Ionic framework. We have only scratched the surface in this tutorial, be sure to check out the resources below to learn more.

Resources

Using the Twig Templating Engine in PHP

| Comments

Separation of concerns is a design principle in Computer Science for separating a program into sections, each with their own responsibility. MVC, an architectural pattern used in most PHP frameworks allows developers to implement separation of concerns. One part of MVC is the View which handles the presentation layer of the application. In this tutorial I’ll walk you through Twig, a templating engine for PHP. This allows us to separate the view from the business logic of the app.

Installation

Execute the following on your terminal to install Twig.

1
composer require twig/twig

In your working directory, create a template folder for storing the Twig templates and a cache folder for storing the cached templates. Twig puts the compiled version of templates into this folder so that the next time it’s requested and there’s no change in the template, it serves the cached version instead. Be sure to change the file permissions of the cache folder so that Twig can write into it. I had to do the following to have it work.

1
sudo chmod -R 777 cache

Usage

To use Twig, include the vendor autoload file.

1
2
3
<?php
require_once 'vendor/autoload.php';
?>

Next create a new instance of the Twig_Loader_Filesystem class and supply the path to the templates directory as its argument. After that, create a new instance of the Twig_Environment class and pass in the loader and an array of options as its argument. In this case, only the cache item is specified. This allows you specify the path of the cache directory.

1
2
3
4
5
6
<?php
$loader = new Twig_Loader_Filesystem('templates');
$twig = new Twig_Environment($loader, array(
    'cache' => 'cache',
));
?>

To load a template, use the loadTemplate method on the Twig instance that you created earlier. Then pass in the path to the template that you want to use. After that, you can now output the view by calling the render method on the template. This accepts the data that you want to pass in to the view.

1
2
3
4
<?php
$template = $twig->loadTemplate('index.html');
echo $template->render(array('name' => 'John Doe', 'age' => 19));
?>

On the templates directory, create the index.html file that you were referring to in the loadTemplate method and then add the following code.

1
2
3
4
5
6
7
8
9
10
11
12
13

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>twig</title>
</head>
<body>
    <h1>Hi {{ name }}!</h1>
    <h2>You are {{ age }} years old</h2>
</body>
</html>

From the above code, you can see that the way the individual items in the array that you passed in the render method is by wrapping the name of the item in double curly braces. Here’s how it’s going to look like when access from the browser.

twig hello world

Note that Twig is pretty forgiving when it comes to data that you pass in to the template. For example, if you do not pass in the age, it wouldn’t throw an error at you.

1
2
3
<?php
echo $template->render(array('name' => 'John Doe'));
?>

Outputting Raw HTML

Twig automatically escapes HTML so if you pass in HTML as data for your template, it is outputted as is.

1
2
3
<?php
echo $template->render(array('name' => 'John Doe', 'html_string' => '<h3>hi Im an html inside a template</h3>'));
?>

If you want to get the HTML interpreted by the browser, you have to use the raw filter.

1
2
3
4
5
6
7

<body>
    <h1>Hi {{ name }}!</h1>
    <h2>You are {{ age }} years old</h2>
    {{ html_string | raw }}
</body>

Looping through Arrays

You can also load arrays for the data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
$template = $twig->loadTemplate('index.html');

$data = array(
    'users' => array(
        array(
            'name' => 'Yoh Asakura',
            'age' => 10
        ),
        array(
            'name' => 'Ash Ketchum',
            'age' => 14
        ),
        array(
            'name' => 'Naruto Uzumaki',
            'age' => 25
        )
    )
);

echo $template->render($data);
?>

And the way you output them in your template is by using the for tag. Here’s an example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<h1>Users</h1>
<table border="1">
    <thead>
        <tr>
            <th>Name</th>
            <th>Age</th>
        </tr>
    </thead>
    <tbody>
        
        {% for user in users %}
        <tr>
            <td>{{ user.name }}</td>
            <td>{{ user.age }}</td>
        </tr>
        {% endfor %}
        
    </tbody>
</table>

To use the for tag, assign an alias for each item in the array that you specified. In this case, the array is users and each item is represented by the user variable. Inside the for tag, you can then access each user field. After you have outputted all the user details, close it with the endfor tag.

for

Conditions

Twig allows you to use tags such as if, else, elseif, and if not for checking for simple conditions in your templates. Here’s an example of using the if tag for checking if the age of the user is greater than or equal to 14.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<h1>Users</h1>
<table border="1">
    <thead>
        <tr>
            <th>Name</th>
            <th>Age</th>
        </tr>
    </thead>
    <tbody>
        
        {% for user in users %}
            {% if user.age >= 14 %}
            <tr>
                <td>{{ user.name }}</td>
                <td>{{ user.age }}</td>
            </tr>
            {% endif %}
        {% endfor %}
        
    </tbody>
</table>

if

Layouts

Layouts can be used in order to avoid repitition of re-occurring elements of the page such as the header and the footer. To use layouts, you need a base template (base.html). This is the template that contains all the re-occurring elements of the page. This is essentially the main template in which all the other templates (child templates) inherits from. Your main template is where you usually declare the content block. This is the block that’s going to get replaced by the content that you supply on your child template.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" href="assets/css/style.css" />
        <title></title>
    </head>
    <body>
        <div id="content">
        
        {% block content %}{% endblock %}
        
        </div>
    </body>
</html>

From your child template (child.html), use the extends tag to let Twig know which template you want to inherit from. Below it, you use the same block that you used in your main template. In this case the name of the block is content. Inside the block, you put in the contents that you want to get rendered.

1
2
3
4
5
6

{% extends "base.html" %}
{% block content %}
   <h1>Hello World!</h1>
{% endblock %}

Notice that in the main template there’s also a stylesheet. You need to create it on the assets/css directory. Here’s the contents of the style.css file.

1
2
3
body {
    background: orange;
}

Finally, from your PHP file, all you need to do is render the child template.

1
2
3
4
<?php
$template = $twig->loadTemplate('child.html');
echo $template->render(array('title' => 'my page'));
?>

Here’s how its going to look like:

layouts

Filters

Twig also comes with filters. Filters as the name suggests, allows you to filter the content that you pass into it.

Format

If you need to perform a find and replace on a string, you can use the format filter. Here’s how you can use it.

1
2
3
4
5
6
<?php
$data = array(
    'name' => 'Ami Damaru',
    'age' => 110
);
?>
1
2
3
4
5
<p>

{{ "Hi I'm %s, I am %s years old" | format(name, age) }}

</p>

As you have seen above, to use the format filter, simply pipe it to the string that you want to perform find and replace on. Each string that you want to replace within the string should be %s. So in this case, the name and age is substituted for that value. It should result in the following output:

1
Hi I'm Ami Damaru, I am 110 years old
nl2br

The nl2br filter allows you to replace line breaks (\n) in your string with <br /> tags. This is useful if you want to output a string which uses line breaks instead of <br /> tags.

1
2
3
4
5
6
7
<?php
$data = array(
    'string' => "The quick brown fox\n jumps over the heade\n of the lazy dog"
);

echo $template->render($data);
?>
1
2
3
4
5
<p>

    {{ string | nl2br }}

</p>
date and date_modify

The date and date_modify filters allows you to modify the formatting of a date.

1
2
3
4
5
6
7
<?php
$date = array(
    'date' => '2015-03-17'
);

echo $template->render($data);
?>
1
2
3
4
5

<p>
    {{ date | date_modify("+1 week") | date('M d, Y') }}
</p>

The code above will output.

1
Aug 03, 2015
upper and lower

upper and lower filters allows you to change the individual letters in a string into uppercase or lowercase.

1
2
3
4

{{ 'MAKE ME LOWER' | lower }}
{{ 'make me higher' | upper }}

The output will be:

1
make me lower MAKE ME HIGHER

Conclusion

That’s it! In this tutorial, you’ve learned how to work with Twig, a templating engine for PHP. For more information about Twig, check out the official docs.

What Playing Clash of Clans Can Teach You About Life

| Comments

  1. You need to prioritize. There’s only like 2 or 3 builder huts when you start playing the game. That’s why it’s important to prioritize which things you upgrade. This is because upgrading takes time. And cancelling an upgrade will only return you half of the original resources you spent on the upgrade. This usually means there’s no turning back after you’ve clicked on that upgrade button. Just like in life you have to prioritize. You can’t just aimlessly be doing everything that seems interesting.

  2. You need the right strategy for every raid that you do. Not every base is the same. There are those whose traps are laid outside the walls. This usually means that it will be triggered the moment your troops lay their first step to loot the resources. There are traps that are laid right before key defenses such as the mortar or air defense. Just like in life you need to carefully plan out your every move, especially the most important one’s such as career decisions.

  3. You can’t protect everything. Put your town hall outside in order to protect what’s really important. Some players might disagree to this and say that if you have designed your base well then that’s the ultimate defense that keeps other players from attacking your village. Some players might also be prioritizing trophies instead of loots and that’s why they keep their town halls at the very center of their village. Those are all valid arguments. Some players might value trophies more than the loots. But come to think of it. There’s over 6 million people who have it installed on Android. I don’t know about iOS but 6 million people is a lot. This means that no matter how strong you think your village is. There’s always someone who can 3-star it effortlessly and take away a ton of loot. So it’s important to realize that you can’t protect everything. You have to prioritize what you really want to protect and design your village in such a way that what you want to protect is protected in the best possible way. Just like in life you can’t get everything that you want. It’s important to love what you currently have.

  4. There’s always someone out there whose stronger than you. There’s no need to feel bad whenever some other 3-starred your village. Just like in life you don’t need to feel bad about yourself whenever you see someone who is effortlessly better than you at the thing you’re good at. What’s important is that you work hard to get better each day.

  5. Revenge is for the weak. I don’t know for other players but I pretty much don’t care about other players attacking my village. It doesn’t really matter whether they 3-starred me or they took a whole bunch of loot. They’re just playing the game just like me. It’s natural for your village to get attacked. It’s natural for other players to take some resources out of your village. Just like it’s natural for you take others as well. But maybe it’s just me. I heard you would get a lot more trophies if you revenge on someone. But trophies aren’t really important to me. I pretty much gave up on trying to go higher when I reached the crystal league. I tried going higher in order to get the gems as the reward but it’s just hard to look for town halls that are unprotected.

  6. Time is money but you can also use money to buy time. When I gave up on reaching the master league in order to get the gem reward for reaching it. And eventually buy the 5th builder with it. I just bought some gems with some real money in order to buy the 5th builder. I don’t really regret it since I just saved myself a lot of time trying to find unprotected town halls and get a measely amount of trophy. This is an example of buying time with money. With the 5th builder upgrades would be faster. And I no longer need to aim to get the gem reward for entering the master, champion, titan or legend leagues.

  7. Patience. Upgrades takes time, creating troops and spells takes time. Gold mines, elixir collectors, heck dark elixir drills takes time. Heroes takes time to sleep. Cool-down for requesting clan castle troops takes time. Searching for a good village to raid takes time. Patience is really a virtue. Especially so when it comes to playing clash of clans. Where every move you do takes time.

  8. Collaboration. It’s important to collaborate with your clan mates during a war. You can’t always have a mirror that directly matches yours. Often times your mirror is far stronger than you are. Sometimes the town hall doesn’t even match. That’s why it’s important to collaborate with your clan mates so that you can adjust accordingly. Just like in life it’s important to collaborate with your fellow employees, with your community and with your family.

  9. Progress will come naturally if you just stick to it. When I first started I really envied my friends on facebook because their villages looks so strong and tough and mine looks really week. But 6 months later I saw that my village is pretty much already on par with them or even stronger. I’m not addicted to the game though. I really only play on my free time. But I always stick to it every day. And that is why I can see that I’ve come a long way since I first started. This is similar to anything that you want to achieve in life. As a developer I always see to it that I learn something new each day. Or have a better understanding of what I previously learned. Just stick to doing something each day and progress will come naturally.

  10. Even heroes needs sleep. So do you. Sleep is needed in order to recharge your mind and body. The brain needs sleep in order to consolidate the things you’ve learned during the day. So even if you think you’re a superhero who only needs 3 hours of sleep in order to get by. You’re not. You can’t really hack your way out of sleep. That’s what makes us human. We need rest in order to recharge.

  11. Donate and you will be rewarded. In clash of clans there is this donation system wherein a clan member can ask for troops to be put in the clan castle. Those troops will serve as guards for your village. If you always donate troops whenever someone asks for it, you will be remembered and your clan mates would love to donate troops to you as well. The same is true in life as well. Always donate to the less fortunate people and you will be rewarded.