1. Go to this page and download the library: Download or81/eloquent library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
or81 / eloquent example snippets
use Or81\Eloquent\NDB;
NDB::table('users')->get(); // already connected to shop
Dotenv::createImmutable($directory)->safeLoad();
NDB::useEnv(__DIR__ . '/config');
NDB::envConfig(); // the config array, or null when .env says nothing
Or81\Eloquent\Env::loadedFrom(); // which file it came from
NDB::configure(['database' => 'shop_test']); // same host and credentials, different database
NDB::configure([
'driver' => 'mysql',
'host' => '127.0.0.1',
'port' => 3306,
'database' => 'shop',
'username' => 'root',
'password' => 'secret',
'charset' => 'utf8mb4',
]);
// SQLite (the file is created if it does not exist; ':memory:' also works)
NDB::configure([
'driver' => 'sqlite',
'database' => __DIR__ . '/storage/database.sqlite',
]);
NDB::configure([...], 'reporting'); // or leave it to the prefixed .env keys
NDB::connection('reporting')->select('select count(*) from events');
NDB::table('events')->getConnection();
foreach ($students as $student) {
sleep(60); // the connection times out here
NDB::table('vadana')->upsert($student, ['national_code']); // reconnects and goes on
}
NDB::configure(['reconnect' => false]); // or DB_RECONNECT=false in .env
try {
NDB::table('vadana')->upsert($rows, ['national_code']);
} catch (QueryException $e) {
if ($e->isLostConnection()) {
// the retry did not get through either: the server is down or restarting
}
}
while ($job = $queue->next()) { // may block for minutes
NDB::ping(); // reconnects if the server dropped us
NDB::table('jobs')->insert($job);
}
$connection = new \Or81\Eloquent\Connection(['driver' => 'mysql']);
$connection->setPdo($yourPdo);
NDB::setConnection($connection);
NDB::connection(); // the Connection object
NDB::getPdo(); // the underlying PDO
NDB::setDefaultConnection('reporting');
NDB::getDefaultConnection();
NDB::purge('reporting'); // drop the connection, keep its config
NDB::forget('reporting'); // drop both, so .env is read again
NDB::reconnect(); // close it and open a new one now
NDB::ping(); // is the server still there? reconnects if not
protected array $casts = [
'total' => 'int', // also: integer
'rate' => 'float', // also: double, real
'price' => 'decimal:2', // a string with two places
'code' => 'string',
'is_paid' => 'bool', // also: boolean
'meta' => 'array', // JSON in the column, an array in PHP
'payload' => 'json', // the same thing
'settings' => 'object',
'seen_at' => 'timestamp', // an int
'birthday' => 'date', // DateTimeImmutable at midnight
'created_at' => 'datetime', // DateTimeImmutable
'issued_at' => 'jalali', // Jalali
];
class Order extends Model
{
protected array $appends = ['summary'];
public function getSummaryAttribute(): string // $order->summary
{
return $this->code . ' (' . $this->status . ')';
}
public function setCodeAttribute($value): void // $order->code = 'ord-1'
{
$this->attributes['code'] = strtoupper((string) $value);
}
}
public function scopeActive(ModelBuilder $query): void
{
$query->where('is_active', 1);
}
public function scopeInCity(ModelBuilder $query, string $city): void
{
$query->where('city', $city);
}
Order::all();
Order::find(1);
Order::findOrFail(1); // ModelNotFoundException when missing
Order::findOr(1, fn () => $default);
Order::where('status', 'paid')->first();
Order::where('status', 'paid')->firstOrFail();
Order::where('status', 'paid')->firstOr(fn () => $default);
Order::query()->firstWhere('status', 'paid');
Order::where('code', 'ORD-1')->sole(); // exactly one match, or it is an error
Order::count();
Order::query()->paginate(20, $page); // 'data' holds models
Order::query()->cursor(); // streams models
Order::query()->chunkById(200, fn (array $orders) => ...);
Order::query()->toBase(); // plain arrays instead
Order::create([...]);
Order::query()->createMany([[...], [...]]); // one transaction
Order::query()->forceCreate([...]); // ignores $fillable
Order::query()->firstOrNew(['code' => 'X']); // not saved
Order::query()->firstOrCreate(['code' => 'X'], ['status' => 'pending']);
Order::query()->updateOrCreate(['code' => 'X'], ['status' => 'paid']);
Order::query()->createOrUpdate(['code' => 'X'], ['status' => 'paid']);
Order::destroy(1); // delete by key, without loading first
Order::destroy(1, 2, 3);
Order::destroy([1, 2, 3]);
$order = Order::find(1);
$order->status = 'shipped';
$order->save(); // writes only what changed
$order->update(['status' => 'shipped']);
$order->delete();
$order->refresh(); // re-read into this instance
$fresh = $order->fresh(); // re-read into a new one
$order->isDirty(); // anything changed since it was loaded?
$order->isDirty('status');
$order->getDirty(); // ['status' => 'shipped']
$order->getOriginal('status'); // what it was when loaded
$order->getAttributes(); // the raw column values
$order->wasChanged(); // did the last save() write anything?
$order->wasChanged('status');
$order->getChanges(); // what it wrote
$order->touch(); // bump updated_at and nothing else
$order->only(['code', 'total']); // a subset, cast as usual
$order->except(['meta']);
$order->is($other); // same row?
$order->isNot($other);
$copy = $order->replicate(); // an unsaved copy, without the key or timestamps
class Customer extends Model
{
public function orders(): ModelBuilder
{
return $this->hasMany(Order::class); // orders.customer_id
}
}
class Order extends Model
{
public function customer(): ModelBuilder
{
return $this->belongsTo(Customer::class); // orders.customer_id
}
}
$order->toArray(); // casts applied, $hidden removed, $appends added
$order->toJson(); // the same, JSON encoded with readable Unicode
json_encode($order); // works: the model is JsonSerializable
$order['code']; // works: the model is ArrayAccess
class BlogPost extends NDB {} // -> blog_posts
class Person extends NDB {} // -> people
class Invoice extends NDB {
protected static string $table = 'legacy_invoices';
}
BlogPost::query()->where('published', 1)->get();
NDB::table('users')->get();
NDB::table('users')->select('id', 'name')->get();
NDB::table('users')->distinct()->select('role')->get();
NDB::table('users', 'u')->select('u.name as author')->get();
NDB::table('users')->selectRaw('count(*) as total, max(votes) as top')->first();
// Correlated sub-select
NDB::table('users')->select('name')->selectSub(
NDB::table('orders')->selectRaw('count(*)')->whereColumn('orders.user_id', 'users.id'),
'orders_count'
)->get();
// Sub-query as the FROM clause
NDB::table('x')->fromSub(NDB::table('users')->where('active', 1), 'active_users')->get();
$user->toArray(); // the plain associative array
$user->toJson();
$user->get('nickname', 'none'); // with a default
$user->has('nickname'); // present, even if null
$user->only(['id', 'name']);
$user->except(['password']);
$user->keys();
$user->values();
$page = NDB::table('users')->orderBy('id')->paginate(perPage: 20, page: 3);
// ['data' => [...], 'total' => 57, 'per_page' => 20, 'current_page' => 3,
// 'last_page' => 3, 'from' => 41, 'to' => 57]
NDB::table('users')->orderBy('id')->chunk(200, function (array $rows, int $page) {
// return false to stop early
});
NDB::table('users')->orderBy('id')->each(function (Row $row) {
// one row at a time, fetched 1000 at a time
});
// Stream without buffering the whole result set
foreach (NDB::table('logs')->cursor() as $row) {
echo $row->message;
}
// 268,000 rows of one column
NDB::table('vadana')->select('student_code')->get(); // 140 MB
NDB::table('vadana')->pluck('student_code'); // 20 MB
foreach (NDB::table('vadana')->cursor() as $student) {
// one row in memory, however many the table has
}
$user = NDB::table('users')->create(['name' => 'John', 'email' => '[email protected]']);
$user->id; // 4, from the database
$user->role; // 'user', the column default
// Several at once, in one transaction: if any row fails, none of them land
$users = NDB::table('users')->createMany([
['name' => 'Alice', 'email' => '[email protected]'],
['name' => 'Bob', 'email' => '[email protected]'],
]);
// Find it or make it
NDB::table('users')->firstOrCreate(
['email' => '[email protected]'], // what to match on
['name' => 'John', 'votes' => 0] // what to add when creating
);
// Update it or make it. Either way the stored row comes back.
NDB::table('users')->updateOrCreate(
['email' => '[email protected]'],
['votes' => 42]
);
NDB::table('users')->createOrUpdate([...], [...]); // the same method, other name
NDB::table('users')->insert(['name' => 'John', 'email' => '[email protected]']);
NDB::table('users')->insert([
['name' => 'Alice', 'email' => '[email protected]'],
['name' => 'Bob', 'email' => '[email protected]'],
]);
$id = NDB::table('users')->insertGetId(['name' => 'Carol']);
// Skip rows that collide with a unique index
NDB::table('users')->insertOrIgnore([['email' => '[email protected]']]);
// Insert, or update the listed columns on collision
NDB::table('users')->upsert(
[['email' => '[email protected]', 'votes' => 42]],
['email'], // unique columns (
NDB::transaction(function () {
NDB::table('users')->where('id', 1)->decrement('balance', 100);
NDB::table('users')->where('id', 2)->increment('balance', 100);
});
// Retry up to 3 times on failure
NDB::transaction($callback, attempts: 3);
// Manual control
NDB::beginTransaction();
NDB::commit();
NDB::rollBack();
NDB::select('select * from users where votes > ?', [100]);
NDB::selectOne('select * from users where id = ?', [1]);
NDB::insert('insert into users (name) values (?)', ['John']);
NDB::update('update users set votes = ? where id = ?', [10, 1]);
NDB::delete('delete from users where id = ?', [1]);
NDB::statement('alter table users add column age integer');
NDB::unprepared('create table t (id integer)'); // DDL, no bindings
NDB::table('users')->select(NDB::raw('count(*) as total'))->first();
$query = NDB::table('users')->where('votes', '>', 100);
$query->toSql(); // select * from "users" where "votes" > ?
$query->getBindings(); // [100]
$query->toRawSql(); // bindings interpolated — for reading only
$query->dump(); // print and continue
$query->dd(); // print and exit
NDB::enableQueryLog();
NDB::table('users')->get();
NDB::getQueryLog(); // [['query' => ..., 'bindings' => [...], 'time' => 0.42]]
use Or81\Eloquent\QueryException;
try {
NDB::table('users')->insert(['nope' => 1]);
} catch (QueryException $e) {
$e->getSql();
$e->getBindings();
$e->getPrevious(); // the underlying PDOException
}
try {
NDB::table('students')->insert($student);
} catch (QueryException $e) {
if ($e->isUniqueViolation()) {
// this row is already there
} elseif ($e->isForeignKeyViolation()) {
// it points at something that does not exist
} else {
throw $e;
}
}
$e->getSqlState(); // '23000'
$e->getDriverCode(); // 1062 on MySQL, 19 on SQLite
$e->getErrorInfo(); // ['23000', 1062, 'Duplicate entry ...']
// Cancel everything still pending from before Mehr
NDB::table('orders')
->where('status', 'pending')
->whereJalali('created_at', '<', '1403/07/01')
->update(['status' => 'cancelled', 'archived_at' => Jalali::now()->toGregorianDateTimeString()]);
// Adjust a counter without reading it first
NDB::table('orders')->where('code', 'ORD-1001')->increment('total', 5000);
// Insert a daily rollup, or update it if the day is already there
NDB::table('daily_totals')->upsert(
[['day' => '1403/05/26', 'total' => 250]],
['day'],
['total']
);