The plan was to 1) create a simple personal TODO application that can CRUD from multiple devices and 2) allow offline CRUD at Android and sync with the main database when the device connects to the internet.
The idea comes from the popular application "Wunderlist"
For the first part of the project (which is the easier part) I implemented two CRUDs in Laravel and Android.
Laravel:
Similar to Wunderlist, the application can be accessed from a web browser. This part was developed using Laravel. I started using the framework a week ago and I cannot believe how much I like it already. I never had an appetite for PHP before I came across Laravel.
Directory structure:
-public --images ---a.png ---b.png ---c.png ---d.png --css ---bootstrap.css ---todo.css -app
--layouts
---todo.blade.php --controllers ---TodoController.php --models ---Todo.php --views ---todos ----create.blade.php ----edit.blade.php ----delete.blade.php
TodoController.php
<?php class TodoController extends \BaseController { /** * Display a listing of the resource. * * @return Response */ public function index() { $todos = Todo::all(); return View::make('todos.index', compact('todos')); } /** * Show the form for creating a new resource. * * @return Response */ public function create() { return View::make('todos.create'); } /** * Store a newly created resource in storage. * * @return Response */ public function store() { $input = Input::all(); $validation = Validator::make($input, Todo::$rules); if ($validation->passes()) { Todo::create($input); return Redirect::route('todo.index'); } return Redirect::route('todo.create') ->withInput() ->withErrors($validation) ->with('message', 'There were validation errors.'); } /** * Display the specified resource. * * @param int $id * @return Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return Response */ public function edit($id) { $todo = Todo::find($id); if (is_null($todo)) { return Redirect::route('todo.index'); } return View::make('todos.edit', compact('todo')); } /** * Update the specified resource in storage. * * @param int $id * @return Response */ public function update($id) { $input = Input::all(); $validation = Validator::make($input, Todo::$rules); if ($validation->passes()) { $todo = Todo::find($id); $todo->update($input); return Redirect::route('todo.index'); } return Redirect::route('todo.edit', $id) ->withInput() ->withErrors($validation) ->with('message', 'There were validation errors.'); } /** * Remove the specified resource from storage. * * @param int $id * @return Response */ public function destroy($id) { Todo::find($id)->delete(); return Redirect::route('todo.index'); } }
Todo.php
<?php class Todo extends \Eloquent { protected $table = 'todo'; protected $guarded = array('id'); protected $fillable = array('task', 'description'); public static $rules = array( 'task' => 'required|min:1' ); }
create.blade.php
@extends('layouts.todo') @section('main') <center> <h3>New Task</h3> {{ Form::open(array('route' => 'todo.store')) }} <ul> <li> {{ Form::label('task', 'Task:') }} {{ Form::text('task') }} </li> <li> {{ Form::label('description', 'Description:') }} {{ Form::textarea('description') }} </li> <li> {{ Form::submit('Submit') }} </li> <li> <h3>{{ link_to_route('todo.index', 'Cancel') }} </h3> </li> </ul> {{ Form::close() }} @if ($errors->any()) <ul> {{ implode('', $errors->all('<li class="error">:message</ li>')) }} </ul> </center> @endif @stop
edit.blade.php
@extends('layouts.todo') @section('main') <center> <h3>Edit Task</h3> {{ Form::model($todo, array('method' => 'PATCH', 'route' => array('todo.update', $todo->id))) }} <ul> <li> {{ Form::label('task', 'Task:') }} {{ Form::text('task') }} </li> <li> {{ Form::label('description', 'Description:')}} {{ Form::textarea('description')}} </li> <li> {{ Form::submit('Update') }} </li> <li> <h3>{{ link_to_route('todo.index', 'Cancel') }} </h3> </li> </ul> {{ Form::close() }} @if ($errors->any()) <ul> {{ implode('', $errors->all('<li class="error">:message</ li>')) }} </ul> </center> @endif @stop
index.blade.php
@extends('layouts.todo') @section('main') @if ($todos->count()) <table class="table table-striped table-bordered"> <tbody> @foreach ($todos as $con) <tr> <td><h4>{{ $con->task }}</h4> <h2>{{ $con->description }}<h2><h5>Created: {{ $con->created_at}}<h5/><h5>Updated: {{ $con->updated_at}}</h5></td> <td> {{link_to_route('todo.edit','',array($con->id), array('class'=>'btn'))}} {{ Form::open(array('method'=> 'DELETE', 'route' => array('todo.destroy', $con->id))) }} <div class="delete"> {{ Form::submit('') }} </div> {{ Form::close() }} </td> </tr> @endforeach </tbody> </table> @else Congratulations on not being a procastinator. @endif <h4>{{ link_to_route('todo.create', 'New Task') }}</h4> @stop
todo.blade.php
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> {{ HTML::style('css/bootstrap.css') }} {{ HTML::style('css/todo.css') }} </head> <body> <div class="container-fluid"> @yield('main') </div> </body> </html>
Since it is a web app, it can be accessed from any device that is online. However the second part of the project also required creating and editing tasks while offline using an android device. Therefore, a separate CRUD application for android was developed. The database system that is native to Android is SQLite.
The database helper class:
package com.ayush.crud; import java.util.ArrayList; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DBHelper extends SQLiteOpenHelper { // public static final String DATABASE_NAME = "todo1.db"; private static final int DATABASE_VERSION = 1; public static final String TABLE_NAME = "task"; public static final String TASK = "task"; public static final String ID = "id"; public static final String DESCRIPTION = "description"; public DBHelper(Context context) { // CURSOR FACTORY : Used to allow returning sub-classes of Cursor when // calling query. // null here super(context, DATABASE_NAME, null, DATABASE_VERSION); } @Override public void onCreate(SQLiteDatabase db) { // TODO Auto-generated method stub db.execSQL("create table " + TABLE_NAME + " (id integer primary key,task text,description text)"); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // TODO Auto-generated method stub db.execSQL("DROP TABLE IF EXISTS "+TABLE_NAME); onCreate(db); } public boolean insertContact(String task, String description) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put(TASK, task); contentValues.put(DESCRIPTION, description); db.insert(TABLE_NAME, null, contentValues); return true; } public Cursor getData(int id) { SQLiteDatabase db = this.getReadableDatabase(); Cursor res = db.rawQuery("select * from "+TABLE_NAME+" where id=" + id + "", null); return res; } public int numberOfRows() { SQLiteDatabase db = this.getReadableDatabase(); int numRows = (int) DatabaseUtils.queryNumEntries(db, TABLE_NAME); return numRows; } public boolean updateTask(Integer id, String task, String description) { SQLiteDatabase db = this.getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put("task", task); contentValues.put("description", description); db.update(TABLE_NAME, contentValues, "id = ? ", new String[] { Integer.toString(id) }); return true; } public Integer deleteContact(Integer id) { SQLiteDatabase db = this.getWritableDatabase(); return db.delete(TABLE_NAME, "id = ? ", new String[] { Integer.toString(id) }); } public ArrayList<String> getAllTasks() { ArrayList<String> array_list = new ArrayList<String>(); SQLiteDatabase db = this.getReadableDatabase(); Cursor res = db.rawQuery("select * from "+TABLE_NAME, null); res.moveToFirst(); while (res.isAfterLast() == false) { array_list.add(res.getString(res.getColumnIndex(TASK))); res.moveToNext(); } return array_list; } }
The second part of the project will be to sync the SQLite Android database and the MySQL database in the server. I will have to do more research to accomplish that. Wait for Crud:2.