Mo PHP Todolist App PDF
Mo PHP Todolist App PDF
Want a build a simple mobile app to create and manage your to-do lists? It's easy with the Slim PHP micro-framework, jQuery Mobile, and the Google Tasks API. I'll show you how I did it. To view the introductory video Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks please access the online version of the article. I used to keep track of my to-do list with a Windows desktop application. I'd pop it open every time I remembered something important, type in a brief label, assign a due date, and save it. The application would launch every time I logged in to the system, so I'd immediately know what needed attention and when. This Windows app worked well, except for two limitations: I couldn't check my to-do list or add tasks when I was away from my computer.
Then I found Google Tasks. It enabled me to check my tasks, and add new ones, while I was on the go.
Google Tasks is integrated with Gmail (though not many people are aware of it), and it lets you create and manage to-do lists online. Since you can access your task list through a browser, it's easy to add, view, and close tasks even while you're on the move. Get the code at JazzHub
developerWorks
ibm.com/developerWorks/
This framework gets your application's user interface up and running quickly, with minimal platform and browser compatibility issues. READ: OAuth 2.0 authentication
Step 1. Create the application directory structure with the Slim and Google OAuth libraries
Change to the web server's document root directory (typically /usr/local/apache/htdocs on Linux, or C:\Program Files\Apache\htdocs on Windows) and create a new subdirectory for the application. Name this directory tasks.
shell> cd /usr/local/apache/htdocs shell> mkdir tasks
This directory will be referenced in this article as $APP_ROOT. Assuming you have downloaded the Slim framework and the Google OAuth library described in the previous section, extract these libraries to $APP_ROOT/vendor. Also transfer the index.php and .htaccess files from the Slim download archive to your $APP_ROOT directory, and edit the index.php file to reflect the correct path to the Slim.php file. Your directory structure should now look like this:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks Page 2 of 21
ibm.com/developerWorks/
developerWorks
These lines define a new virtual host whose document root corresponds to the $APP_ROOT. In the above listing, the name of this host is tasks.melonfire.com. Remember that you will need to change this to either localhost or another domain under your control. Restart the web server to activate these new settings. Note that it might be necessary to update your network's local DNS server to let it know about the new host as well. Once you're done, point your browser to your new host. You should see the Slim framework welcome page:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 3 of 21
developerWorks
ibm.com/developerWorks/
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 4 of 21
ibm.com/developerWorks/
developerWorks
Next, register your web application to obtain an OAuth 2.0 client id and secret. Make note of these values, are you will need them for the Google PHP OAuth client.
Remember to also set the application redirect URL at this point. This is the URL to which Google will redirect the client browser after completing the OAuth authentication process. In this example, this URL is set to http://tasks.melonfire.com/login:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 5 of 21
developerWorks
ibm.com/developerWorks/
While you're logged in, you should also visit Gmail, which includes an integrated Google Tasks interface, and add a few sample task lists and tasks to it. This is useful to check that the PHP application is working correctly. The Google Tasks interface in Gmail looks something like this:
This probably seems like a lot of hoops to jump through, but the good news is that you only have to do it once.
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 6 of 21
ibm.com/developerWorks/
developerWorks
"id": "MTc3Mz", "etag": "\"zhaMOBt\"", "title": "Milk", "updated": "2013-11-11T07:46:09.000Z", "selfLink": "https://www.googleapis.com/tasks/v1/lists/MTc3Mz/tasks/MTc3MzQ1", "position": "00000000000637427684", "status": "needsAction" }, { "kind": "tasks#task", "id": "MTc3Mz", "etag": "\"zhaMOBt\"", "title": "Bread", "updated": "2013-11-11T07:46:11.000Z", "selfLink": "https://www.googleapis.com/tasks/v1/lists/MTc3Mz/tasks/MTc3MzQ6", "position": "00000000000717532232", "status": "needsAction" }, { ... } ] }
As Listing 1 shows, the Tasks API generates a JSON-encoded response containing a list of tasks. Each task entry contains some useful meta-data, such as the task title, due date, self URL, and status. It's now quite easy to decode this JSON and convert it into an HTML representation suitable for display in a web browser. Most of the time, though, you won't be issuing raw GET and POST requests to the Tasks API. The Google PHP OAuth client and its service objects provide a convenient wrapper around such requests, encapsulating all related functionality into PHP objects and methods.
Listing tasks
Listing 2 uses the Google OAuth library with the Slim framework to connect, authenticate and display a summary of task lists and tasks.
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 7 of 21
developerWorks
ibm.com/developerWorks/
$app->get('/login', function () use ($app) { if (isset($_GET['code'])) { $app->client->authenticate(); $_SESSION['access_token'] = $app->client->getAccessToken(); $app->redirect('/index'); exit; } // if token available in session, set token in client if (isset($_SESSION['access_token'])) { $app->client->setAccessToken($_SESSION['access_token']); } if ($app->client->getAccessToken()) { if (isset($_SESSION['target'])) { $app->redirect($_SESSION['target']); } else { $app->redirect('/index'); } } else { $authUrl = $app->client->createAuthUrl(); $app->redirect($authUrl); } }); $app->get('/index', 'authenticate', function () use ($app) { $lists = $app->tasksService->tasklists->listTasklists(); foreach ($lists['items'] as $list) { $id = $list['id']; $tasks[$id] = $app->tasksService->tasks->listTasks($id); } $app->render('index.php', array('lists' => $lists, 'tasks' => $tasks)); }); $app->get('/logout', function () use ($app) { unset($_SESSION['access_token']); $app->client->revokeToken(); }); $app->run(); function authenticate () { $app = \Slim\Slim::getInstance(); $_SESSION['target'] = $app->request()->getPathInfo(); if (isset($_SESSION['access_token'])) { $app->client->setAccessToken($_SESSION['access_token']); } if (!$app->client->getAccessToken()) { $app->redirect('/login'); } }
Listing 2, which should be saved as $APP_ROOT/index.php, begins by loading the Slim and Google OAuth client libraries, together with the Google Tasks service object. It initializes a new Slim application object and a new Google_Client object. Needless to say, the Google_Client object must be configured with the same client id, client secret, and redirect URL defined earlier in the Google Cloud Console. A Google_TasksService service object is also initialized; this serves as the primary control point for interacting with the Google Tasks API through PHP.
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 8 of 21
ibm.com/developerWorks/
developerWorks
Slim works by defining router callbacks for HTTP methods and endpoints. This is done simply by calling the corresponding method get() for GET requests, post() for POST requests, and so on and passing the URL route to be matched as the first argument to the method. The second argument to the method is a function, which specifies the actions to be taken when the route is matched to an incoming request. Listing 2 sets up three such router callbacks: /index, /login, and /logout. Let's look at each of these in turn: The /login callback handles the OAuth authentication flow. A complete discussion of this flow is outside the scope of this article, although you can get exhaustive details through the Google API documentation. Briefly, this callback uses the Google_Client object's createAuthUrl() method to generate a URL to the Google authentication page (see the next figure) and then redirects the client browser to this URL. Once the user authenticates the application and confirms the data it has access to, Google redirects the client back to the / login URL, which retrieves an access token and stores it in the session. This access token gives the client access to the Google Tasks API. Successful OAuth authentication redirects the client to the application's index page, located at /index. This callback uses the configured Google_TasksService object and its listTasklists() method to retrieve a list of the authenticated user's task lists. The code then iterates over this collection of task lists and for each list, it invokes the service object's listTasks() method to retrieve the individual tasks within the list. This information is then transferred to the view, which takes care of rendering it to the user. I'll show you the view script further along. The /logout method destroys the session, thereby nullifying the access token stored in it. For additional security, it also invokes the client object's revokeToken() method, which also invalidates the token on Google's servers.
You've already seen that the /index callback takes care of retrieving the user's task lists and the tasks for each list. This information is stored in PHP variables and transferred to the view, which is responsible for formatting it into a human-readable list. The view script should be located at $APP_ROOT/templates/index.php and it looks like this:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks Page 9 of 21
developerWorks
ibm.com/developerWorks/
Listing 3 sets up a listview page formatted according to standard jQuery Mobile conventions. The primary page element is a <div> element with a data-role="page" attribute. Within this are separate <div> elements for the page header, footer, and content. The page content consists of a series of collapsible <div> elements, with each such element representing one of the user's task lists. Clicking the title of a list unfolds its tasks. To see how this works, visit http://tasks.melonfire.com/index (replace the URL with that of your own virtual host) in your browser. You should see a task listing like this:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 10 of 21
ibm.com/developerWorks/
developerWorks
With this, a request to /add-list will result in the $APP_ROOT/templates/add-list.php template being rendered to the user. The next listing shows the contents of this template. The authenticate() function is a custom function that is executed before the route callback is executed; look in Listing 2 and you'll see that it checks for an access token and redirects the client to the login page if no such token is found, prompting a re-login.
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 11 of 21
developerWorks
<body> <div data-role="page"> <div data-role="header"> Add List </div> <div data-role="content"> <div data-role="collapsible-set"> <form method="post" action="/add-list"> <label for="title">Title:</label> <input name="title" id="title" data-clear-btn="true" type="text"/> <input name="submit" value="Save" type="submit" data-icon="check" data-inline="true" data-theme="a" /> <a href="/index" data-role="button" data-inline="true" data-icon="back" data-theme="a">Back</a> </form> </div> </div> </body> </html>
ibm.com/developerWorks/
Listing 4 consists of a form with a single field, for the title of the new task list. On submission, the form data will be POST-ed back to the /add-list route, which now needs to be extended to handle the form input. Here is the additional code:
Listing 5 sanitizes the title submitted through the form and then creates a new Google_TaskList object. This object represents a task list resource in the Google Tasks API. The object's setTitle() method is used to assign a title, and the service object's insert() method is then used to save the new task list to Google Tasks. Here is the form, as well as the results of submitting it:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 12 of 21
ibm.com/developerWorks/
developerWorks
If you now check the Google Tasks interface within Gmail, you should see your newly-added task list there as well. Try it for yourself and see! If you're allowing users to add lists, you also need to give them a way to delete them. The inverse of the service object's insert() method is its delete() method, which accepts a task list identifier and deletes the corresponding list from Google Tasks. Here is the route definition:
Listing 6 sets up a new route, /delete-list, which accepts a list identifier as part of the request URL. This request URL is then parsed by Slim's routing framework, the list identifier is extracted, and the service object's delete() method is used to remove the corresponding list from Google Tasks. All that's left now is to update the index page listing with additional buttons to add and remove lists. Here is the code for the revised index page:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 13 of 21
developerWorks
<?php foreach ($lists['items'] as $list): ?> <?php $id = $list['id']; ?> <div data-role="collapsible"> <h2><?php echo $list['title']; ?></h2> <ul data-role="listview"> <?php if (isset($tasks[$id]['items'])): ?> <?php foreach ($tasks[$id]['items'] as $task): ?> <li> <?php if ($task['status'] == 'needsAction'): ?> <h3><?php echo $task['title']; ?></h3> <?php else: ?> <h3 style="text-decoration:line-through" ><?php echo $task['title']; ?></h3> <?php endif; ?> <?php if (isset($task['due']) && ($task['status'] == 'needsAction')): ?> <p>Due on <?php echo date('d M Y', strtotime($task['due'])); ?></p> <?php endif; ?> <?php if (isset($task['completed']) && ($task['status'] == 'completed')): ?> <p>Completed on <?php echo date('d M Y', strtotime($task['completed'])); ?></p> <?php endif; ?> </li> <?php endforeach; ?> <?php endif; ?> </ul> <a href="/delete-list/<?php echo $id; ?>" data-inline="true" data-role="button" data-icon="delete" data-theme="a">Remove list</a> </div> <?php endforeach; ?> </div> </div> <a href="/add-list" data-inline="true" data-role="button" data-icon="plus" data-theme="b">Add new list</a> </div> </body> </html>
ibm.com/developerWorks/
In addition to new buttons to add and delete lists, this version of the view script also has some additional enhancements. Due dates are now displayed for tasks, and completed tasks have a line drawn through them, while tasks that are still due (status="needsAction") don't. Here's what it looks like.
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 14 of 21
ibm.com/developerWorks/
developerWorks
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 15 of 21
developerWorks
$task = new Google_Task(); $task->setTitle($title); $task->setDue(date(DATE_RFC3339, strtotime($due))); $result = $app->tasksService->tasks->insert($id, $task); $app->redirect('/index'); } });
ibm.com/developerWorks/
$app->get('/delete-task/:lid/:tid', 'authenticate', function ($lid, $tid) use ($app) { $app->tasksService->tasks->delete($lid, $tid); $app->redirect('/index'); });
Every task must be associated with a task list and so, the /add-task route callback is set up to receive a task list identifier as a GET request parameter. It then renders the $APP_ROOT/templates/ add-task.php template, which contains a form to add new tasks and is described in this listing:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 16 of 21
ibm.com/developerWorks/
developerWorks
Listing 9 contains a form with two visible fields, one for the task title and the other for the task due date. To simplify date entry, the date input field is configured to use the jQuery Mobile DateBox plugin, which displays a graphical date picker for point-and-click date entry. Since tasks must be associated with a task list, the task list identifier received as a GET parameter is also specified in the form as a hidden field. Once the form is submitted, the data entered into it is sanitized and used to initialize a Google_Task object. This object, together with the hidden task list identifier, is then passed to the service object's insert() method, which takes care of adding it to the Google Tasks system via a REST invocation. And finally, the /delete-task route callback, like the /add-task callback, is configured to receive both a task list identifier and a task identifier. It then uses the service object's delete() method to remove the specified task from the specified task list. With the routes and business login in place, all that's left is to update the index page with additional buttons for task addition and deletion. Since I'll soon explain how to update a task's status, this is a good time to also add a button for this functionality. Here is the revised template:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 17 of 21
developerWorks
<?php if (isset($task['due']) && ($task['status'] == 'needsAction')): ?> <p>Due on <?php echo date('d M Y', strtotime($task['due'])); ?></p> <?php endif; ?> <?php if (isset($task['completed']) && ($task['status'] == 'completed')): ?> <p>Completed on <?php echo date('d M Y', strtotime($task['completed'])); ?></p> <?php endif; ?> </div> <div class="ui-block-b"></div> <div class="ui-block-c"> <?php if ($task['status'] == 'needsAction'): ?> <a href="/update-task/<?php echo $id; ?>/ <?php echo $task['id']; ?>" data-inline="true" data-role="button" data-icon="check" data-theme="a">Done!</a> <?php endif; ?> <a href="/delete-task/ <?php echo $id; ?>/<?php echo $task['id']; ?>" data-inline="true" data-role="button" data-icon="delete" data-theme="a">Remove task</a> </div> </div> </li> <?php endforeach; ?> <?php endif; ?> </ul> <br/> <a href="/add-task/<?php echo $id; ?>" data-inline="true" data-role="button" data-icon="plus" data-theme="a">Add new task</a> <a href="/delete-list/<?php echo $id; ?>" data-inline="true" data-role="button" data-icon="delete" data-theme="a">Remove list</a> </div> <?php endforeach; ?> </div> <a href="/add-list" data-inline="true" data-role="button" data-icon="plus" data-theme="b">Add new list</a> </div> </div> </body> </html>
ibm.com/developerWorks/
As shown in Listing 10, the markup for each task list has been updated to turn each list into a two-column grid. The left column contains the task title and due date. The right column contains actions possible for that task, such as updating it or deleting it. Finally, a new button at the end makes it possible to update the list with new tasks. The process of adding a new task to a task list looks like this:
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 18 of 21
ibm.com/developerWorks/
developerWorks
The /update-task route callback receives both list and task identifiers and uses this information to retrieve task information from the Google Tasks API. This information is then used to populate a new Google_Tasks object, and the object's setStatus() method is used to change the task status to "completed." The service object's update() method is then used to push the new task entry to Google's servers. The process of marking a task as complete looks like this.
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 19 of 21
developerWorks
ibm.com/developerWorks/
Summary
You're done! You got a crash course in how to integrate data from the Google Tasks API with a PHP application using a combination of jQuery Mobile, the Google PHP OAuth library, and the Slim PHP micro-framework. The examples in this article introduced you to the Google Tasks JSON format and showed you how to retrieve task listings; add, modify and delete tasks; and build a customized interface to the task lists in a user's Google Account. As these examples illustrate, the Google Tasks API is a powerful and flexible tool when you want to build creative new applications around task management. Play with it sometime, and see what you think! RELATED TOPICS: PHP jQuery Mobile Google Tasks
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 20 of 21
ibm.com/developerWorks/
developerWorks
Create a mobile-friendly to-do list app with PHP, jQuery Mobile, and Google Tasks
Page 21 of 21