Models & Database

The Model layer is responsible for all interaction with your database. It abstracts the data source so that your controllers don't need to know the specifics of your database schema or write raw SQL queries. In Rhapsody, all models are placed in the app/Models directory and should extend the Rhapsody\Core\BaseModel.

Database Connection

The framework uses PDO (PHP Data Objects) for database communication, which provides a secure and consistent interface. The database connection is managed by the Rhapsody\Core\Database class, which uses a Singleton pattern. This means the application only ever makes one single database connection per request, which is very efficient.

By extending BaseModel, your model automatically gets access to the database connection via $this->db.

Creating a Model

A model typically represents one database table. For example, a User model would handle all operations for the users table.

<?php

namespace App\Models;

use Rhapsody\Core\BaseModel;
use PDO;

class User extends BaseModel
{
    /**
     * Fetches a single user from the database by their ID.
     */
    public function findById(string $id): array|false
    {
        // Use prepare() for security against SQL injection
        $stmt = $this->db->prepare("SELECT * FROM users WHERE user_id = :id");
        
        // Bind the parameter
        $stmt->bindParam(':id', $id, PDO::PARAM_STR);
        
        // Execute and fetch the result
        $stmt->execute();
        return $stmt->fetch();
    }

    /**
     * Fetches all users.
     */
    public function findAll(): array
    {
        $stmt = $this->db->query("SELECT user_id, name, email FROM users ORDER BY name");
        return $stmt->fetchAll();
    }
}

Security with Prepared Statements

This is critical. Whenever you are using user-provided data (like a route parameter or form input) in a query, you must use prepared statements to prevent SQL injection.

The correct workflow is to use prepare(), then bindParam() or pass an array to execute(). Never concatenate variables directly into a SQL string.

// GOOD: Secure and correct
$stmt = $this->db->prepare("SELECT * FROM users WHERE email = :email");
$stmt->execute([':email' => $email]);
$user = $stmt->fetch();

// BAD: Insecure and will lead to vulnerabilities
$user = $this->db->query("SELECT * FROM users WHERE email = '$email'");