This tutorial guides you through the installation, configuration, and use of the Todo application built with Laravel.
By the end of this tutorial, you will know how to:
Before starting, make sure you have:
# Navigate to the project folder
cd projects/todo-app
# Verify you're in the right folder
ls -la
# Install PHP dependencies
composer install
# Copy environment file
cp .env.example .env
# Generate application key
php artisan key:generate
Edit the .env
file:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=todo_app
DB_USERNAME=root
DB_PASSWORD=your_password
# Create database
mysql -u root -p -e "CREATE DATABASE todo_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
# Or with SQLite (simpler for testing)
# DB_CONNECTION=sqlite
# DB_DATABASE=/path/to/database.sqlite
# Run migrations
php artisan migrate
# Verify tables are created
php artisan migrate:status
php artisan storage:link
php artisan serve
Open your browser and go to: http://localhost:8000
You should see the Todo application homepage!
todo-app/
βββ app/
β βββ Http/Controllers/
β β βββ TodoController.php # Business logic
β βββ Models/
β βββ Todo.php # Eloquent model
βββ database/
β βββ migrations/
β βββ xxxx_create_todos_table.php
βββ resources/
β βββ views/
β βββ todos/
β β βββ index.blade.php # Todo list
β β βββ create.blade.php # Creation form
β β βββ edit.blade.php # Edit form
β βββ layouts/
β βββ app.blade.php # Main layout
βββ routes/
βββ web.php # Route definitions
class Todo extends Model
{
protected $fillable = [
'title', 'description', 'completed', 'due_date', 'priority'
];
// Scopes for filtering
public function scopeCompleted($query) {
return $query->where('completed', true);
}
public function scopePending($query) {
return $query->where('completed', false);
}
// Accessors
public function getStatusColorAttribute() {
return $this->completed ? 'success' : 'warning';
}
}
class TodoController extends Controller
{
public function index(Request $request)
{
$query = Todo::query();
// Filtering
if ($request->has('status')) {
switch ($request->status) {
case 'completed':
$query->completed();
break;
case 'pending':
$query->pending();
break;
}
}
$todos = $query->orderBy('created_at', 'desc')->paginate(10);
return view('todos.index', compact('todos'));
}
}
Route::get('/', function () {
return redirect()->route('todos.index');
});
Route::resource('todos', TodoController::class);
Route::patch('todos/{todo}/toggle', [TodoController::class, 'toggle'])->name('todos.toggle');
php artisan make:migration add_category_to_todos_table
public function up()
{
Schema::table('todos', function (Blueprint $table) {
$table->string('category')->nullable();
$table->integer('estimated_hours')->nullable();
});
}
protected $fillable = [
'title', 'description', 'completed', 'due_date',
'priority', 'category', 'estimated_hours'
];
// Create Category model
php artisan make:model Category -m
// Add relationship in Todo.php
public function category()
{
return $this->belongsTo(Category::class);
}
// Create Tag model
php artisan make:model Tag -m
// Create pivot table
php artisan make:migration create_todo_tag_table
resources/css/app.css
# Optimize autoloader
composer install --optimize-autoloader --no-dev
# Cache configuration
php artisan config:cache
# Cache routes
php artisan route:cache
# Cache views
php artisan view:cache
# Create Heroku app
heroku create todo-app-laravel
# Configure environment variables
heroku config:set APP_KEY=base64:your-key
heroku config:set DB_CONNECTION=postgresql
heroku config:set DB_DATABASE=your-database-url
# Deploy
git push heroku main
# Run migrations
heroku run php artisan migrate
# Clone on server
git clone <repository-url>
cd todo-app
# Install dependencies
composer install --optimize-autoloader --no-dev
# Configure environment
cp .env.example .env
php artisan key:generate
# Run migrations
php artisan migrate
# Configure web server (Apache/Nginx)
# Run tests
php artisan test
# Specific tests
php artisan test --filter=TodoTest
class TodoTest extends TestCase
{
public function test_can_create_todo()
{
$response = $this->post('/todos', [
'title' => 'Test Todo',
'description' => 'Test Description',
'priority' => 'high',
'due_date' => now()->addDay(),
]);
$response->assertRedirect();
$this->assertDatabaseHas('todos', ['title' => 'Test Todo']);
}
public function test_can_toggle_todo()
{
$todo = Todo::factory()->create(['completed' => false]);
$response = $this->patch("/todos/{$todo->id}/toggle");
$response->assertRedirect();
$this->assertTrue($todo->fresh()->completed);
}
}
# Check connection
php artisan tinker
DB::connection()->getPdo();
# Reset migrations
php artisan migrate:fresh
# Give permissions to storage folder
chmod -R 775 storage
chmod -R 775 bootstrap/cache
# Clear all caches
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
# View logs
tail -f storage/logs/laravel.log
# Debug mode
APP_DEBUG=true in .env
# Install Laravel Breeze
composer require laravel/breeze
php artisan breeze:install
# Create API controllers
php artisan make:controller Api/TodoController --api
# Create notifications
php artisan make:notification TodoReminder
# Create jobs
php artisan make:job ProcessTodoReminder
Congratulations! You now have:
Todo Application - Your first complete Laravel application! π―