دیتابیس
اتصال به دیتابیس در Flare
فریمورک فلر از کتابخانه ThingEngineer/PHP-MySQLi-Database-Class برای کار با دیتابیس استفاده میکند
در فریمورک فلر، اتصال به دیتابیس از طریق شیء سراسری $db
انجام میشود. این شیء در کنترلرها به کمک متد __construct
مقداردهی میشود. برای نمونه:
namespace Controllers;
class USERS extends BaseController
{
public $db;
public function __construct()
{
global $db;
$this->db = $db;
}
}
با این روش، میتوانید در تمام متدهای کنترلر به دیتابیس دسترسی داشته باشید.
افزودن رکورد جدید (Insert ساده)
برای افزودن یک رکورد جدید به دیتابیس، به سادگی آرایهای از دادهها را به متد insert
ارسال کنید:
$data = [
"login" => "admin",
"firstName" => "John",
"lastName" => "Doe"
];
$id = $this->db->insert('users', $data);
if ($id) {
echo 'کاربر ایجاد شد. شناسه: ' . $id;
}
در این مثال، اگر عملیات درج موفق باشد، شناسه رکورد ایجاد شده برگردانده میشود.
درج با استفاده از توابع خاص
شما میتوانید از توابع داخلی مانند now()
یا func()
برای پردازش مقادیر قبل از درج استفاده کنید:
$data = [
'login' => 'admin',
'active' => true,
'firstName' => 'John',
'lastName' => 'Doe',
'password' => $this->db->func('SHA1(?)', ['secretpassword+salt']),
'createdAt' => $this->db->now(),
'expires' => $this->db->now('+1Y')
];
$id = $this->db->insert('users', $data);
if ($id) {
echo 'کاربر ایجاد شد. شناسه: ' . $id;
} else {
echo 'درج اطلاعات با خطا مواجه شد: ' . $this->db->getLastError();
}
با این روش میتوانید مقادیری مثل رمز عبور هش شده یا زمان ایجاد/انقضا را مستقیماً در لحظه درج تعیین کنید.
درج با پشتیبانی از "on duplicate key update"
در صورت نیاز به درج یا بروزرسانی خودکار در صورت وجود رکورد مشابه (بر اساس کلید یکتا)، میتوانید از متد onDuplicate
استفاده کنید:
$data = [
"login" => "admin",
"firstName" => "John",
"lastName" => "Doe",
"createdAt" => $this->db->now(),
"updatedAt" => $this->db->now()
];
$updateColumns = ["updatedAt"];
$lastInsertId = "id";
$this->db->onDuplicate($updateColumns, $lastInsertId);
$id = $this->db->insert('users', $data);
با این روش، اگر رکوردی با کلید یکتا از قبل موجود باشد، فقط فیلد updatedAt
بهروزرسانی میشود.
درج همزمان چندین رکورد (insertMulti)
اگر نیاز به درج چندین رکورد به صورت همزمان داشته باشید، میتوانید از متد insertMulti
بهره ببرید:
$data = [
[
"login" => "admin",
"firstName" => "John",
"lastName" => "Doe"
],
[
"login" => "other",
"firstName" => "Another",
"lastName" => "User",
"password" => "very_cool_hash"
]
];
$ids = $this->db->insertMulti('users', $data);
if (!$ids) {
echo 'درج گروهی با خطا مواجه شد: ' . $this->db->getLastError();
} else {
echo 'کاربران جدید با این شناسهها درج شدند: ' . implode(', ', $ids);
}
این روش بهینهتر از اجرای چندین insert
جداگانه است.
درج گروهی سادهتر با کلیدها
اگر تمام رکوردها کلیدهای یکسانی داشته باشند، میتوانید کلیدها را جداگانه مشخص کرده و آرایه دادهها را سادهتر بنویسید:
$data = [
["admin", "John", "Doe"],
["other", "Another", "User"]
];
$keys = ["login", "firstName", "lastName"];
$ids = $this->db->insertMulti('users', $data, $keys);
if (!$ids) {
echo 'درج گروهی با خطا مواجه شد: ' . $this->db->getLastError();
} else {
echo 'کاربران جدید با این شناسهها درج شدند: ' . implode(', ', $ids);
}
جایگزینی رکورد (Replace)
متد replace
در فلر همانند insert
عمل میکند، با این تفاوت که در صورت وجود رکورد با کلید یکتا، آن را جایگزین میکند:
$data = [
"id" => 1,
"login" => "admin",
"firstName" => "John",
"lastName" => "Doe"
];
$id = $this->db->replace('users', $data);
if ($id) {
echo 'رکورد جایگزین شد. شناسه: ' . $id;
} else {
echo 'جایگزینی با خطا مواجه شد: ' . $this->db->getLastError();
}
بهروزرسانی رکوردها (Update)
برای بهروزرسانی اطلاعات یک یا چند رکورد، ابتدا شرط مورد نظر را با where
مشخص کنید، سپس دادههای جدید را به update
ارسال کنید:
$data = [
'firstName' => 'Bobby',
'lastName' => 'Tables',
'editCount' => $this->db->inc(2),
'active' => $this->db->not()
];
$this->db->where('id', 1);
if ($this->db->update('users', $data)) {
echo $this->db->count . ' رکورد بهروزرسانی شد';
} else {
echo 'بهروزرسانی با خطا مواجه شد: ' . $this->db->getLastError();
}
همچنین میتوانید تعداد رکوردهای بهروزرسانی شده را با پارامتر limit
محدود کنید:
$this->db->update('users', $data, 10);
// خروجی: UPDATE users SET ... LIMIT 10
دریافت دادهها (Select)
برای دریافت دادهها از دیتابیس، میتوانید از متد get
استفاده کنید. پس از اجرا، تعداد رکوردهای بازیابی شده در متغیر $count
ذخیره میشود:
$users = $this->db->get('users'); // دریافت تمام کاربران
$users = $this->db->get('users', 10); // دریافت 10 کاربر
همچنین میتوانید فقط ستونهای خاصی را انتخاب کنید:
$cols = ["id", "name", "email"];
$users = $this->db->get('users', null, $cols);
if ($this->db->count > 0) {
foreach ($users as $user) {
print_r($user);
}
}
برای دریافت تنها یک رکورد:
$this->db->where('id', 1);
$user = $this->db->getOne('users');
echo $user['id'];
و برای دریافت نتایج محاسباتی (مثل مجموع یا شمارش):
$stats = $this->db->getOne('users', 'sum(id), count(*) as cnt');
echo "مجموع کاربران: " . $stats['cnt'];
دریافت یک مقدار خاص (مانند شمارش تعداد کل کاربران):
$count = $this->db->getValue('users', 'count(*)');
echo "{$count} کاربر ثبت شده است";
دریافت یک ستون خاص از چندین رکورد:
$logins = $this->db->getValue('users', 'login', null);
foreach ($logins as $login) {
echo $login;
}
بارگذاری داده از CSV
برای بارگذاری دادههای یک فایل CSV به جدول خاصی:
$path_to_file = "/home/john/file.csv";
$this->db->loadData("users", $path_to_file);
همچنین میتوانید تنظیمات بیشتری هنگام بارگذاری مشخص کنید:
$options = [
"fieldChar" => ';',
"lineChar" => '\r\n',
"linesToIgnore" => 1
];
$this->db->loadData("users", "/home/john/file.csv", $options);
استفاده از LOAD DATA LOCAL
نیز پشتیبانی میشود:
$options = [
"fieldChar" => ';',
"lineChar" => '\r\n',
"linesToIgnore" => 1,
"loadDataLocal" => true
];
$this->db->loadData("users", "/home/john/file.csv", $options);
بارگذاری داده از XML
برای بارگذاری دادههای یک فایل XML:
$path_to_file = "/home/john/file.xml";
$this->db->loadXML("users", $path_to_file);
با امکان تعیین تنظیمات اضافه:
$options = [
"linesToIgnore" => 0,
"rowTag" => ""
];
$this->db->loadXML("users", "/home/john/file.xml", $options);
دریافت دادهها با صفحهبندی (Pagination)
برای دریافت نتایج به صورت صفحهبندی شده، از متد paginate
استفاده کنید:
$page = 1;
$this->db->pageLimit = 2;
$products = $this->db->arraybuilder()->paginate("products", $page);
echo "نمایش صفحه $page از " . $this->db->totalPages;
تبدیل نتایج (Map)
میتوانید نتایج را بر اساس یک کلید مشخص، به صورت آرایه انجمنی (Associative Array) دریافت کنید:
$user = $this->db->map('login')->ObjectBuilder()->getOne('users', 'login, id');
print_r($user);
// خروجی نمونه:
// [
// "user1" => 1
// ]
اگر بیش از دو ستون انتخاب شود، خروجی به صورت آبجکت خواهد بود:
$user = $this->db->map('login')->ObjectBuilder()->getOne('users', 'id, login, createdAt');
print_r($user);
// خروجی نمونه:
// [
// "user1" => (object) [
// "id" => 1,
// "login" => "user1",
// "createdAt" => "2015-10-22 22:27:53"
// ]
// ]
تعریف نوع بازگشتی
در فریمورک فلر، نتایج دیتابیس میتوانند به سه فرمت مختلف بازگردند: آرایه از آرایهها، آرایه از آبجکتها، یا رشتهی JSON. برای تعیین نوع بازگشتی میتوانید از متدهای ArrayBuilder()
، ObjectBuilder()
و JsonBuilder()
استفاده کنید.
نکته: حالت پیشفرض ArrayBuilder()
است.
مثالها:
// آرایهای
$u = $this->db->getOne('users');
echo $u['login'];
// آبجکت
$u = $this->db->ObjectBuilder()->getOne('users');
echo $u->login;
// رشتهی JSON
$json = $this->db->JsonBuilder()->getOne('users');
echo $json;
اجرای کوئریهای خام
برای اجرای مستقیم کوئریهای SQL، میتوانید از متد rawQuery
استفاده کنید:
$users = $this->db->rawQuery('SELECT * FROM users WHERE id >= ?', [10]);
foreach ($users as $user) {
print_r($user);
}
متدهای کمکی برای کار با نتایج کوئری خام
گرفتن یک سطر:
$user = $this->db->rawQueryOne('SELECT * FROM users WHERE id=?', [10]);
echo $user['login'];
// به صورت آبجکت
$user = $this->db->ObjectBuilder()->rawQueryOne('SELECT * FROM users WHERE id=?', [10]);
echo $user->login;
گرفتن یک مقدار ستونی (string):
$password = $this->db->rawQueryValue('SELECT password FROM users WHERE id=? LIMIT 1', [10]);
echo "رمز عبور: {$password}";
نکته: برای بازگرداندن یک رشته به جای آرایه، باید LIMIT 1
در انتهای کوئری قرار بگیرد.
گرفتن چند مقدار ستونی:
$logins = $this->db->rawQueryValue('SELECT login FROM users LIMIT 10');
foreach ($logins as $login) {
echo $login;
}
نمونههای پیشرفتهتر:
$params = [1, 'admin'];
$users = $this->db->rawQuery('SELECT id, firstName, lastName FROM users WHERE id = ? AND login = ?', $params);
print_r($users);
// اجرای کوئریهای پیچیدهتر
$params = [10, 1, 10, 11, 2, 10];
$q = "(
SELECT a FROM t1 WHERE a = ? AND B = ? ORDER BY a LIMIT ?
) UNION (
SELECT a FROM t2 WHERE a = ? AND B = ? ORDER BY a LIMIT ?
)";
$results = $this->db->rawQuery($q, $params);
print_r($results);
استفاده از متدهای Where و Having
متدهای where()
، orWhere()
، having()
و orHaving()
به شما امکان میدهند شرطهای WHERE و HAVING را راحتتر و خواناتر ایجاد کنید.
نمونههای ساده:
// شرطهای ساده
$this->db->where('id', 1);
$this->db->where('login', 'admin');
$results = $this->db->get('users');
// یا با لود زنجیرهای
$results = $this->db->where('id', 1)
->where('login', 'admin')
->get('users');
// شرطهای Having
$this->db->where('id', 1);
$this->db->having('login', 'admin');
$results = $this->db->get('users');
مقایسه ستون به ستون:
// اشتباه
$this->db->where('lastLogin', 'createdAt');
// درست
$this->db->where('lastLogin = createdAt');
$results = $this->db->get('users');
مقایسه با عملگرها:
// بزرگتر مساوی
$this->db->where('id', 50, '>=');
$results = $this->db->get('users');
استفاده از BETWEEN:
$this->db->where('id', [4, 20], 'BETWEEN');
$results = $this->db->get('users');
استفاده از IN:
$this->db->where('id', [1, 5, 27, -1, 'd'], 'IN');
$results = $this->db->get('users');
OR CASE:
$this->db->where('firstName', 'John');
$this->db->orWhere('firstName', 'Peter');
$results = $this->db->get('users');
مقایسه با NULL:
$this->db->where('lastName', null, 'IS NOT');
$results = $this->db->get('users');
استفاده از LIKE:
$this->db->where('fullName', 'John%', 'LIKE');
$results = $this->db->get('users');
شرطهای خام:
$this->db->where('id != companyId');
$this->db->where('DATE(createdAt) = DATE(lastLogin)');
$results = $this->db->get('users');
شرط خام با مقادیر متغیر:
$this->db->where('(id = ? OR id = ?)', [6, 2]);
$this->db->where('login', 'mike');
$res = $this->db->get('users');
یافتن تعداد کل ردیفها - مثال صفحهبندی ساده
برای دریافت تعداد کل نتایج بدون نیاز به کوئری جداگانه، از withTotalCount()
استفاده کنید:
$offset = 10;
$count = 15;
$users = $this->db->withTotalCount()->get('users', [$offset, $count]);
echo "نمایش {$count} کاربر از مجموع {$this->db->totalCount} کاربر";
استفاده از Query Keywords
برای اضافه کردن کلیدواژههای MySQL مانند LOW PRIORITY
، HIGH PRIORITY
، IGNORE
و ... به متدهای insert()
، replace()
، update()
، delete()
یا get()
میتوانید از setQueryOption()
استفاده کنید.
مثالها:
// درج با LOW_PRIORITY
$this->db->setQueryOption('LOW_PRIORITY')->insert('users', $data);
// انتخاب با FOR UPDATE
$this->db->setQueryOption('FOR UPDATE')->get('users');
همچنین میتوانید چندین کلیدواژه را به صورت آرایه تعیین کنید:
$this->db->setQueryOption(['LOW_PRIORITY', 'IGNORE'])->insert('users', $data);
در SELECT هم میتوانید از این روش استفاده کنید:
$this->db->setQueryOption('SQL_NO_CACHE')->get('users');
مرتبسازی نتایج با orderBy
برای مرتبسازی نتایج میتوانید از متد orderBy()
استفاده کنید.
مثالهای مرتبسازی ساده:
$this->db->orderBy('id', 'asc');
$this->db->orderBy('login', 'desc');
$this->db->orderBy('RAND()');
$results = $this->db->get('users');
برای مرتبسازی طبق مقادیر خاص:
$this->db->orderBy('userGroup', 'ASC', ['superuser', 'admin', 'users']);
$this->db->get('users');
نکته درباره استفاده از پیشوند جداول:
اگر از setPrefix()
استفاده کردهاید، نام جداول را داخل backtick (`
) قرار دهید:
$this->db->setPrefix('t_');
$this->db->orderBy('`users`.id', 'asc');
$this->db->get('users');
گروهبندی نتایج با groupBy
برای گروهبندی نتایج از متد groupBy()
استفاده کنید.
مثال:
$this->db->groupBy('name');
$results = $this->db->get('users');
استفاده از JOIN در کوئریها
برای اتصال جداول میتوانید از متد join()
استفاده کنید.
مثال JOIN ساده:
$this->db->join('users u', 'p.tenantID = u.tenantID', 'LEFT');
$this->db->where('u.id', 6);
$products = $this->db->get('products p', null, 'u.name, p.productName');
افزودن شرط به JOIN با joinWhere:
$this->db->join('users u', 'p.tenantID = u.tenantID', 'LEFT');
$this->db->joinWhere('users u', 'u.tenantID', 5);
$products = $this->db->get('products p', null, 'u.name, p.productName');
افزودن شرط OR به JOIN با joinOrWhere:
$this->db->join('users u', 'p.tenantID = u.tenantID', 'LEFT');
$this->db->joinOrWhere('users u', 'u.tenantID', 5);
$products = $this->db->get('products p', null, 'u.productName');
اشتراکگذاری خصوصیات کوئری
با متد copy()
میتوانید خصوصیات کوئری (مثل where) را در چند عملیات جداگانه به اشتراک بگذارید.
مثال:
$this->db->where('agentId', 10);
$this->db->where('active', true);
// کپی خصوصیات
$customers = $this->db->copy();
$res = $customers->get('customers', [10, 10]); // LIMIT 10, 10
// ادامه کار با کوئری اصلی
$cnt = $this->db->getValue('customers', 'count(id)');
echo "Total customers:
Warning: Undefined variable $cnt in C:\laragon\www\sajjad\sajjadef.ir\sajjadef\Flare\View\latte\temp\page-flare-database.latte--31adab9549.php on line 647
";
استفاده از Subqueries
برای ایجاد Subquery میتوانید از متد subQuery()
استفاده کنید.
ساخت Subquery ساده:
// بدون alias
$sq = $this->db->subQuery();
$sq->get('users');
ساخت Subquery با alias برای JOIN:
// با alias
$sq = $this->db->subQuery('sq');
$sq->get('users');
استفاده از Subquery در WHERE:
$ids = $this->db->subQuery();
$ids->where('qty', 2, '>');
$ids->get('products', null, 'userId');
$this->db->where('id', $ids, 'IN');
$res = $this->db->get('users');
استفاده از Subquery در INSERT:
$userIdQ = $this->db->subQuery();
$userIdQ->where('id', 6);
$userIdQ->getOne('users', 'name');
$data = [
'productName' => 'test product',
'userId' => $userIdQ,
'lastUpdated' => $this->db->now()
];
$id = $this->db->insert('products', $data);
استفاده از Subquery در JOIN:
$usersQ = $this->db->subQuery('u');
$usersQ->where('active', 1);
$usersQ->get('users');
$this->db->join($usersQ, 'p.userId = u.id', 'LEFT');
$products = $this->db->get('products p', null, 'u.login, p.productName');
شرطهای EXISTS / NOT EXISTS
برای بررسی وجود یا عدم وجود دادهای از کوئریهای فرعی (SubQuery) میتوانید از شرط EXISTS
استفاده کنید:
$sub = $this->db->subQuery();
$sub->where("company", 'testCompany');
$sub->get("users", null, 'userId');
$this->db->where(null, $sub, 'exists');
$products = $this->db->get("products");
// خروجی SQL:
// SELECT * FROM products WHERE EXISTS (SELECT userId FROM users WHERE company='testCompany')
متد Has
متد has()
بررسی میکند که آیا حداقل یک ردیف مطابق با شرطهای مشخص شده وجود دارد یا خیر.
$this->db->where("user", $user);
$this->db->where("password", md5($password));
if ($this->db->has("users")) {
return "You are logged";
} else {
return "Wrong user/password";
}
متدهای کمکی
قطع اتصال از دیتابیس:
$this->db->disconnect();
برقراری مجدد اتصال:
if (!$this->db->ping()) {
$this->db->connect();
}
گرفتن آخرین کوئری اجرا شده:
$this->db->get('users');
echo "Last executed query was " . $this->db->getLastQuery();
توجه: این متد برای دیباگ کاربرد دارد و ممکن است کوئری تولید شده، به دلیل نبود کوتیشن دور متغیرها، مستقیم قابل اجرا نباشد.
بررسی وجود جدول:
if ($this->db->tableExists('users')) {
echo "hooray";
}
استفاده از mysqli_real_escape_string:
$escaped = $this->db->escape("' and 1=1");
مدیریت تراکنشها (Transactions)
تراکنشها فقط روی جداول InnoDB پشتیبانی میشوند.
مثال:
$this->db->startTransaction();
if (!$this->db->insert('myTable', $insertData)) {
// در صورت خطا، تغییرات اعمال شده را لغو میکنیم
$this->db->rollback();
} else {
// موفقیتآمیز
$this->db->commit();
}
مدیریت خطاها
بعد از اجرای هر کوئری میتوانید خطاها را بررسی کنید.
$this->db->where('login', 'admin')->update('users', ['firstName' => 'Jack']);
if ($this->db->getLastErrno() === 0) {
echo 'Update successful';
} else {
echo 'Update failed. Error: ' . $this->db->getLastError();
}
بررسی زمان اجرای کوئریها (Trace)
با فعال کردن setTrace(true)
میتوانید مدت زمان اجرای هر کوئری را ردیابی کنید.
$this->db->setTrace(true);
$this->db->get("users");
$this->db->get("test");
print_r($this->db->trace);
// خروجی نمونه:
[
[0] => [
'SELECT * FROM t_users ORDER BY `id` ASC',
0.0010669231414795,
'MysqliDb->get() >> file "/path/tests.php" line #151'
],
[1] => [
'SELECT * FROM t_test',
0.00069189071655273,
'MysqliDb->get() >> file "/path/tests.php" line #152'
]
]
قفل کردن جداول (Table Locking)
برای قفل کردن جداول از متد lock()
همراه با setLockMethod()
استفاده میشود.
قفل برای نوشتن:
$this->db->setLockMethod("WRITE")->lock("users");
قفل چند جدول برای خواندن:
$this->db->setLockMethod("READ")->lock(["users", "log"]);
باز کردن قفل جداول:
$this->db->unlock();