9-Gestor de Tareas con Blade y Arreglo en Laravel

 Gestor de Tareas con Blade y Arreglo en Laravel

Aquí te mostraré una versión simplificada donde las tareas se manejan con un arreglo en lugar de una base de datos. Esto es útil para aprendizaje o prototipado rápido.

1. Modificamos el controlador (app/Http/Controllers/TaskController.php)

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Session;

class TaskController extends Controller
{
    public function index()
    {
        // Obtener tareas de la sesión o inicializar arreglo vacío
        $tasks = Session::get('tasks', []);
        
        return view('tasks.index', compact('tasks'));
    }

    public function create()
    {
        return view('tasks.create');
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|max:255',
            'description' => 'nullable',
        ]);

        // Obtener tareas existentes
        $tasks = Session::get('tasks', []);
        
        // Agregar nueva tarea
        $newTask = [
            'id' => uniqid(),
            'title' => $validated['title'],
            'description' => $validated['description'] ?? '',
            'completed' => false,
            'created_at' => now()->toDateTimeString(),
        ];
        
        array_push($tasks, $newTask);
        
        // Guardar en sesión
        Session::put('tasks', $tasks);

        return redirect()->route('tasks.index')
                         ->with('success', 'Tarea creada correctamente');
    }

    public function show($id)
    {
        $tasks = Session::get('tasks', []);
        
        // Buscar tarea por ID
        $task = collect($tasks)->firstWhere('id', $id);
        
        if (!$task) {
            abort(404);
        }

        return view('tasks.show', compact('task'));
    }

    public function edit($id)
    {
        $tasks = Session::get('tasks', []);
        $task = collect($tasks)->firstWhere('id', $id);
        
        if (!$task) {
            abort(404);
        }

        return view('tasks.edit', compact('task'));
    }

    public function update(Request $request, $id)
    {
        $validated = $request->validate([
            'title' => 'required|max:255',
            'description' => 'nullable',
            'completed' => 'boolean',
        ]);

        $tasks = Session::get('tasks', []);
        
        // Actualizar tarea
        $tasks = array_map(function ($task) use ($id, $validated) {
            if ($task['id'] === $id) {
                return [
                    'id' => $id,
                    'title' => $validated['title'],
                    'description' => $validated['description'] ?? '',
                    'completed' => $validated['completed'] ?? false,
                    'created_at' => $task['created_at'],
                ];
            }
            return $task;
        }, $tasks);
        
        Session::put('tasks', $tasks);

        return redirect()->route('tasks.show', $id)
                         ->with('success', 'Tarea actualizada correctamente');
    }

    public function destroy($id)
    {
        $tasks = Session::get('tasks', []);
        
        // Filtrar para eliminar la tarea
        $tasks = array_filter($tasks, function ($task) use ($id) {
            return $task['id'] !== $id;
        });
        
        Session::put('tasks', $tasks);

        return redirect()->route('tasks.index')
                         ->with('success', 'Tarea eliminada correctamente');
    }
}

Explicación de array_filter.


2. Modificamos la vista de índice (resources/views/tasks/index.blade.php)

html
@extends('layouts.app')

@section('title', 'Lista de Tareas')

@section('content')
    <div class="d-flex justify-content-between align-items-center mb-4">
        <h1>Lista de Tareas</h1>
        <a href="{{ route('tasks.create') }}" class="btn btn-primary">Nueva Tarea</a>
    </div>

    @if(empty($tasks))
        <div class="alert alert-info">No hay tareas registradas.</div>
    @else
        <div class="table-responsive">
            <table class="table table-striped">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Título</th>
                        <th>Estado</th>
                        <th>Fecha</th>
                        <th>Acciones</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach($tasks as $task)
                        <tr>
                            <td>{{ substr($task['id'], 0, 8) }}</td>
                            <td>{{ $task['title'] }}</td>
                            <td>
                                <span class="badge {{ $task['completed'] ? 'bg-success' : 'bg-warning' }}">
                                    {{ $task['completed'] ? 'Completada' : 'Pendiente' }}
                                </span>
                            </td>
                            <td>{{ \Carbon\Carbon::parse($task['created_at'])->format('d/m/Y') }}</td>
                            <td>
                                <a href="{{ route('tasks.show', $task['id']) }}" class="btn btn-sm btn-info">Ver</a>
                                <a href="{{ route('tasks.edit', $task['id']) }}" class="btn btn-sm btn-warning">Editar</a>
                                <form action="{{ route('tasks.destroy', $task['id']) }}" method="POST" style="display: inline;">
                                    @csrf
                                    @method('DELETE')
                                    <button type="submit" class="btn btn-sm btn-danger">Eliminar</button>
                                </form>
                            </td>
                        </tr>
                    @endforeach
                </tbody>
            </table>
        </div>
    @endif
@endsection

3. Modificamos la vista de creación (resources/views/tasks/create.blade.php)

html
@extends('layouts.app')

@section('title', 'Crear Nueva Tarea')

@section('content')
    <div class="card">
        <div class="card-header">
            <h2>Nueva Tarea</h2>
        </div>
        <div class="card-body">
            <form action="{{ route('tasks.store') }}" method="POST">
                @csrf
                <div class="mb-3">
                    <label for="title" class="form-label">Título*</label>
                    <input type="text" class="form-control @error('title') is-invalid @enderror" 
                           id="title" name="title" value="{{ old('title') }}" required>
                    @error('title')
                        <div class="invalid-feedback">{{ $message }}</div>
                    @enderror
                </div>
                <div class="mb-3">
                    <label for="description" class="form-label">Descripción</label>
                    <textarea class="form-control @error('description') is-invalid @enderror" 
                              id="description" name="description" rows="3">{{ old('description') }}</textarea>
                    @error('description')
                        <div class="invalid-feedback">{{ $message }}</div>
                    @enderror
                </div>
                <button type="submit" class="btn btn-primary">Guardar</button>
                <a href="{{ route('tasks.index') }}" class="btn btn-secondary">Cancelar</a>
            </form>
        </div>
    </div>
@endsection

4. Modificamos la vista de edición (resources/views/tasks/edit.blade.php)

html
@extends('layouts.app')

@section('title', 'Editar Tarea')

@section('content')
    <div class="card">
        <div class="card-header">
            <h2>Editar Tarea: {{ $task['title'] }}</h2>
        </div>
        <div class="card-body">
            <form action="{{ route('tasks.update', $task['id']) }}" method="POST">
                @csrf
                @method('PUT')
                <div class="mb-3">
                    <label for="title" class="form-label">Título*</label>
                    <input type="text" class="form-control @error('title') is-invalid @enderror" 
                           id="title" name="title" value="{{ old('title', $task['title']) }}" required>
                    @error('title')
                        <div class="invalid-feedback">{{ $message }}</div>
                    @enderror
                </div>
                <div class="mb-3">
                    <label for="description" class="form-label">Descripción</label>
                    <textarea class="form-control @error('description') is-invalid @enderror" 
                              id="description" name="description" rows="3">{{ old('description', $task['description']) }}</textarea>
                    @error('description')
                        <div class="invalid-feedback">{{ $message }}</div>
                    @enderror
                </div>
                <div class="mb-3 form-check">
                    <input type="checkbox" class="form-check-input" id="completed" 
                           name="completed" {{ $task['completed'] ? 'checked' : '' }}>
                    <label class="form-check-label" for="completed">Completada</label>
                </div>
                <button type="submit" class="btn btn-primary">Actualizar</button>
                <a href="{{ route('tasks.index') }}" class="btn btn-secondary">Cancelar</a>
            </form>
        </div>
    </div>
@endsection

5. Vista de detalles (resources/views/tasks/show.blade.php)

html
@extends('layouts.app')

@section('title', 'Detalles de la Tarea')

@section('content')
    <div class="card">
        <div class="card-header">
            <h2>Detalles de la Tarea</h2>
        </div>
        <div class="card-body">
            <div class="mb-3">
                <h5 class="card-title">{{ $task['title'] }}</h5>
                <span class="badge {{ $task['completed'] ? 'bg-success' : 'bg-warning' }}">
                    {{ $task['completed'] ? 'Completada' : 'Pendiente' }}
                </span>
            </div>
            <p class="card-text">{{ $task['description'] }}</p>
            <div class="mt-4">
                <p><strong>Creada:</strong> {{ \Carbon\Carbon::parse($task['created_at'])->format('d/m/Y H:i') }}</p>
            </div>
            <div class="mt-4">
                <a href="{{ route('tasks.edit', $task['id']) }}" class="btn btn-warning">Editar</a>
                <form action="{{ route('tasks.destroy', $task['id']) }}" method="POST" style="display: inline;">
                    @csrf
                    @method('DELETE')
                    <button type="submit" class="btn btn-danger">Eliminar</button>
                </form>
                <a href="{{ route('tasks.index') }}" class="btn btn-secondary">Volver</a>
            </div>
        </div>
    </div>
@endsection

Características clave de esta implementación:

  1. Almacenamiento en sesión: Usamos Session de Laravel para persistir los datos entre requests

  2. Manejo de IDs: Generamos IDs únicos con uniqid()

  3. Colecciones: Usamos collect() para trabajar con métodos de colección en arreglos

  4. Validación: Mantenemos el sistema de validación de Laravel

  5. Mensajes flash: Usamos with() para mensajes de éxito/error

Notas importantes:

  • Los datos solo persisten durante la sesión actual (se pierden al cerrar el navegador)

  • Esta implementación es para propósitos educativos, no para producción

  • Para una aplicación real, deberías usar una base de datos

  • El sistema de rutas y controladores sigue el mismo patrón que con base de datos

Este ejemplo te muestra cómo trabajar con Blade y Laravel usando estructuras de datos simples, lo que puede ser muy útil para prototipado rápido o para entender los conceptos básicos antes de pasar a una implementación con base de datos.

Comentarios

Entradas más populares de este blog

0-Sistema de Tareas

13-CRUD en Laravel para Web y API con Rutas Normales (No Resource)

10-Introducción a Blade en Laravel con un Ejemplo Práctico