centamiv / concrete
A simple and solid ORM for PHP applications.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 1
Watchers: 0
Forks: 0
Open Issues: 3
pkg:composer/centamiv/concrete
Requires
- php: >=7.4
- ext-pdo: *
Requires (Dev)
- phpunit/phpunit: ^12.4
This package is auto-updated.
Last update: 2025-12-26 09:17:13 UTC
README
Concrete is a simple and solid ORM for PHP applications. It provides an elegant Active Record implementation and a fluent Query Builder to interact with your database.
Installation
You can install the package via composer:
composer require centamiv/concrete
Configuration
To start using Concrete, you need to initialize the database connection. Typically, you would do this in your application's bootstrap file (e.g., index.php).
MySQL
use Concrete\Database; use Concrete\Connection\MysqlDriver; require 'vendor/autoload.php'; // Initialize the database connection Database::init( new MysqlDriver(), '127.0.0.1', // Host 'my_database', // Database Name 'root', // User 'password' // Password );
SQLite
use Concrete\Database; use Concrete\Connection\SqliteDriver; require 'vendor/autoload.php'; // Initialize the database connection // For SQLite, the second parameter is the database file path Database::init( new SqliteDriver(), '/path/to/database.sqlite', // Database file path (or ':memory:' for in-memory) );
PostgreSQL
use Concrete\Database; use Concrete\Connection\PostgresDriver; require 'vendor/autoload.php'; // Initialize the database connection Database::init( new PostgresDriver(), '127.0.0.1', // Host 'my_database', // Database Name 'postgres', // User 'password' // Password );
SQL Server
use Concrete\Database; use Concrete\Connection\SqlServerDriver; require 'vendor/autoload.php'; // Initialize the database connection Database::init( new SqlServerDriver(), 'localhost', // Host (Server) 'my_database', // Database Name 'sa', // User 'password' // Password );
Usage
Defining Models
Create a model class that extends Concrete\Model. You need to define the TABLE constant. By default, the primary key is assumed to be id.
namespace App\Models; use Concrete\Model; class User extends Model { public const TABLE = 'users'; public const COL_ID = 'id'; public const COL_NAME = 'name'; public const COL_EMAIL = 'email'; public const COL_AGE = 'age'; public const COL_ACTIVE = 'active'; public const COL_ROLE_ID = 'role_id'; public const COL_CREATED_AT = 'created_at'; }
Custom Primary Keys
If your table uses a primary key other than id, you can override the PRIMARY_KEY constant. Concrete also supports composite primary keys.
class Order extends Model { public const TABLE = 'orders'; // Simple Primary Key public const PRIMARY_KEY = 'id'; } class OrderItem extends Model { public const TABLE = 'order_items'; // Composite Primary Key public const PRIMARY_KEY = ['order_id', 'product_id']; }
Basic CRUD
Creating Records
To create a new record, instantiate your model, set attributes, and call save().
$user = new User(); $user->set(User::COL_NAME, 'Mario Rossi') ->set(User::COL_EMAIL, 'mario@example.com') ->save(); // Access the auto-incremented ID (if applicable) echo $user->get(User::COL_ID);
Retrieving Records
Use the find() static method to retrieve a record by its primary key.
// Find by single primary key $user = User::find(1); if ($user) { echo $user->get(User::COL_NAME); } // Find by composite primary key $item = OrderItem::find(['order_id' => 10, 'product_id' => 5]);
Updating Records
Retrieve a record, modify its attributes, and call save() again.
$user = User::find(1); $user->set(User::COL_EMAIL, 'new_email@example.com'); $user->save();
Deleting Records
Retrieve a record and call delete().
$user = User::find(1); if ($user) { $user->delete(); }
Query Builder
Concrete provides a fluent Query Builder for more complex queries. You can access it via the query() static method on your models.
Filtering (where)
$users = User::query() ->where(User::col(User::COL_ACTIVE), '=', 1) ->where(User::col(User::COL_AGE), '>', 18) ->get(); foreach ($users as $user) { echo $user->get(User::COL_NAME); }
Ordering (orderBy)
$users = User::query() ->where(User::col(User::COL_ACTIVE), '=', 1) ->orderBy(User::col(User::COL_CREATED_AT), 'DESC') ->get();
Joins (join, leftJoin)
You can join other tables using the join or leftJoin methods.
// Assuming Role model exists with constants $users = User::query() ->select(User::col('*'), Role::colAs(Role::COL_NAME, 'role_name')) ->join(Role::TABLE, User::col(User::COL_ROLE_ID), '=', Role::col(Role::COL_ID)) ->get();
You can also use rightJoin:
$users = User::query() ->rightJoin(Role::TABLE, User::col(User::COL_ROLE_ID), '=', Role::col(Role::COL_ID)) ->get();
Updating Records (update)
$affected = User::query() ->where(User::col(User::COL_ACTIVE), '=', 0) ->update([User::col(User::COL_ACTIVE) => 1]);
Deleting Records (delete)
$deleted = User::query() ->where(User::col(User::COL_AGE), '<', 18) ->delete();
Limiting Results (take, skip)
$users = User::query() ->take(10) // LIMIT 10 ->skip(5) // OFFSET 5 ->get();
Aggregates & Helpers
count(): Returns the number of records matching the query.first(): Returns the first model instance ornull.exists(): Returnstrueif any records match the query.
$count = User::query()->where(User::col(User::COL_ACTIVE), '=', 1)->count(); $user = User::query()->where(User::col(User::COL_EMAIL), '=', 'test@example.com')->first(); if (User::query()->where(User::col(User::COL_AGE), '<', 18)->exists()) { // ... }
Fetching Arrays
If you prefer to work with raw associative arrays instead of Model instances, you can use getRows() or firstRow().
// Returns an array of associative arrays $users = User::query()->where('active', '=', 1)->getRows(); foreach ($users as $user) { echo $user['name']; // Access as array } // Returns a single associative array or null $user = User::query()->find(1)->firstRow(); if ($user) { echo $user['email']; }
Helper Methods
exists(): Checks if the model instance exists in the database (based on primary key presence).fill(array $data): Mass assign attributes from an array.col(string $column, ?string $alias = null): Helper to get fully qualified column names (e.g.,users.name).colAs(string $column, string $columnAs, ?string $tableAlias = null): Helper to get fully qualified column names with an alias (e.g.,users.name as user_name).
Advanced Usage
Debugging Queries
You can inspect the generated SQL query using the sql() method on the builder.
$query = User::query() ->where(User::col(User::COL_ACTIVE), '=', 1); echo $query->sql(); // Outputs: SELECT users.* FROM users WHERE users.active = :users_active0
Raw Queries
For complex operations not supported by the Query Builder, you can access the underlying PDO connection.
use Concrete\Database; $db = Database::getConnection(); // Complex Raw Query $stmt = $db->query("SELECT count(*) as count FROM users GROUP BY age"); $stats = $stmt->fetchAll();
Standalone Query Builder
While Model::query() is the preferred way, you can use the Builder directly.
use Concrete\Query\Builder; use App\Models\User; $builder = new Builder(); $users = $builder->table(User::class) ->where('active', '=', 1) ->get();
Requirements
- PHP >= 7.4
ext-pdoextension- For MySQL:
ext-pdo_mysql - For SQLite:
ext-pdo_sqlite - For PostgreSQL:
ext-pdo_pgsql - For SQL Server:
ext-pdo_sqlsrv
Appendix: Laravel Integration
If you want to use Concrete within a Laravel application and reuse the existing Laravel database connection, you can use the initFromPDO method.
1. Initialize in AppServiceProvider
In your app/Providers/AppServiceProvider.php, initialize Concrete in the boot method.
use Concrete\Database; use Concrete\Connection\MysqlDriver; // Or use: PostgresDriver, SqliteDriver, SqlServerDriver use Illuminate\Support\Facades\DB; public function boot() { // Initialize using the existing Laravel PDO connection // Choose the appropriate driver based on your Laravel database configuration Database::initFromPDO( DB::connection()->getPdo(), new MysqlDriver() // Use PostgresDriver, SqliteDriver, or SqlServerDriver as needed ); }
2. Usage Example
Now you can use Concrete models alongside Eloquent models.
namespace App\Http\Controllers; use App\Models\Concrete\User; // Your Concrete Model class UserController extends Controller { public function index() { // Use Concrete to fetch users using Laravel's connection $users = User::query() ->where(User::col(User::COL_ACTIVE), '=', 1) ->get(); return view('users.index', ['users' => $users]); } }
License
This library is open-sourced software licensed under the MIT license.