PHP / PDO CRUD үйлдлүүд

PDO CRUD үйлдлүүд

Өгөгдлийн сантай ажиллах дөрвөн үндсэн үйлдлийг CRUD гэж нэрлэдэг: Create (үүсгэх), Read (унших), Update (шинэчлэх), Delete (устгах). Энэ хичээлд PDO ашиглан бүрэн CRUD хэрэгжүүлж, бодит Repository загварт хэрхэн зохион байгуулахыг сурна. Мөн алдааны нөхцөлд хэд хэдэн SQL үйлдлийг нэгэн зэрэг цуцлах transaction-ийг судална.

Create — өгөгдөл нэмэх

php
<?php
$pdo = new PDO('sqlite:сургалт.db');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

// Нэг мөр нэмэх
function хэрэглэгч_нэмэх(PDO $pdo, string $нэр, string $имэйл, int $нас): int {
    $stmt = $pdo->prepare("
        INSERT INTO хэрэглэгчид (нэр, имэйл, нас)
        VALUES (:нэр, :имэйл, :нас)
    ");

    $stmt->execute([
        ':нэр'   => $нэр,
        ':имэйл' => $имэйл,
        ':нас'   => $нас,
    ]);

    // Шинээр үүсгэгдсэн мөрийн ID-г буцаана
    return (int)$pdo->lastInsertId();
}

$id = хэрэглэгч_нэмэх($pdo, "Болд", "bold@example.mn", 25);
echo "Шинэ хэрэглэгчийн ID: {$id}\n"; // Шинэ хэрэглэгчийн ID: 1

// Олон мөр нэгэн зэрэг нэмэх
function олон_хэрэглэгч_нэмэх(PDO $pdo, array $хэрэглэгчид): void {
    $stmt = $pdo->prepare("INSERT INTO хэрэглэгчид (нэр, имэйл, нас) VALUES (?, ?, ?)");

    foreach ($хэрэглэгчид as $х) {
        $stmt->execute([$х['нэр'], $х['имэйл'], $х['нас']]);
    }
}

олон_хэрэглэгч_нэмэх($pdo, [
    ['нэр' => 'Сарнай', 'имэйл' => 'sarnai@example.mn', 'нас' => 22],
    ['нэр' => 'Тамир',  'имэйл' => 'tamir@example.mn',  'нас' => 30],
]);
?>

lastInsertId() нь AUTO_INCREMENT / AUTOINCREMENT баганатай хүснэгтэд сүүлийн нэмэгдсэн мөрийн ID-г буцаадаг.

Read — өгөгдөл унших

php
<?php
// Бүгдийг унших
function бүх_хэрэглэгч(PDO $pdo): array {
    return $pdo->query("SELECT * FROM хэрэглэгчид ORDER BY нэр")->fetchAll();
}

// ID-гаар нэгийг олох
function хэрэглэгч_олох(PDO $pdo, int $id): ?array {
    $stmt = $pdo->prepare("SELECT * FROM хэрэглэгчид WHERE id = ?");
    $stmt->execute([$id]);
    $үр_дүн = $stmt->fetch();
    return $үр_дүн ?: null; // Олдохгүй бол null
}

// Хайлт хийх
function хэрэглэгч_хайх(PDO $pdo, string $хайлт): array {
    $stmt = $pdo->prepare("
        SELECT * FROM хэрэглэгчид
        WHERE нэр LIKE :хайлт OR имэйл LIKE :хайлт
        ORDER BY нэр
    ");
    $stmt->execute([':хайлт' => "%{$хайлт}%"]);
    return $stmt->fetchAll();
}

// Хуудасчлал — pagination
function хэрэглэгч_хуудас(PDO $pdo, int $хуудас = 1, int $хэмжээ = 10): array {
    $орхих = ($хуудас - 1) * $хэмжээ;
    $stmt   = $pdo->prepare("SELECT * FROM хэрэглэгчид LIMIT ? OFFSET ?");
    $stmt->execute([$хэмжээ, $орхих]);
    return $stmt->fetchAll();
}

// Ашиглах жишээ
$бүгд = бүх_хэрэглэгч($pdo);
foreach ($бүгд as $х) {
    echo "{$х['id']}. {$х['нэр']} ({$х['нас']} нас)\n";
}

$нэг = хэрэглэгч_олох($pdo, 1);
echo $нэг ? $нэг['нэр'] : "Олдсонгүй";

$хайлт = хэрэглэгч_хайх($pdo, "Бо");
echo count($хайлт) . " хэрэглэгч олдлоо.\n";
?>

LIKE :хайлт болон "%{$хайлт}%" хослол нь prepared statement-н аюулгүй байдлыг хадгалж, хэсэгчилсэн хайлт хийдэг.

Update — өгөгдөл шинэчлэх

php
<?php
// Бүхэл мөр шинэчлэх
function хэрэглэгч_шинэчлэх(PDO $pdo, int $id, string $нэр, string $имэйл, int $нас): bool {
    $stmt = $pdo->prepare("
        UPDATE хэрэглэгчид
        SET нэр = :нэр, имэйл = :имэйл, нас = :нас
        WHERE id = :id
    ");

    $stmt->execute([
        ':нэр'   => $нэр,
        ':имэйл' => $имэйл,
        ':нас'   => $нас,
        ':id'    => $id,
    ]);

    // Шинэчлэгдсэн мөрийн тоо — 0 бол ID байхгүй байсан
    return $stmt->rowCount() > 0;
}

// Зөвхөн өөрчлөгдсөн талбаруудыг шинэчлэх
function хэрэглэгч_хэсэгчлэн_шинэчлэх(PDO $pdo, int $id, array $утгууд): bool {
    if (empty($утгууд)) return false;

    $зөвшөөрөгдсөн = ['нэр', 'имэйл', 'нас'];
    $тохируулалтууд = [];
    $параметрүүд    = [':id' => $id];

    foreach ($утгууд as $талбар => $утга) {
        if (in_array($талбар, $зөвшөөрөгдсөн, true)) {
            $тохируулалтууд[] = "{$талбар} = :{$талбар}";
            $параметрүүд[":{$талбар}"] = $утга;
        }
    }

    $stmt = $pdo->prepare("UPDATE хэрэглэгчид SET " . implode(', ', $тохируулалтууд) . " WHERE id = :id");
    $stmt->execute($параметрүүд);
    return $stmt->rowCount() > 0;
}

$амжилт = хэрэглэгч_шинэчлэх($pdo, 1, "Болд-Эрдэнэ", "bold2@example.mn", 26);
echo $амжилт ? "Шинэчлэгдлээ.\n" : "Олдсонгүй.\n";

хэрэглэгч_хэсэгчлэн_шинэчлэх($pdo, 1, ['нас' => 27]);
?>

rowCount() нь INSERT / UPDATE / DELETE хийсний дараа нөлөөлөгдсөн мөрийн тоог буцаадаг — 0 бол ямар ч мөр өөрчлөгдөөгүй.

Delete ба Transaction

php
<?php
// Устгах
function хэрэглэгч_устгах(PDO $pdo, int $id): bool {
    $stmt = $pdo->prepare("DELETE FROM хэрэглэгчид WHERE id = ?");
    $stmt->execute([$id]);
    return $stmt->rowCount() > 0;
}

// Transaction — хэд хэдэн үйлдлийг нэгэн зэрэг хийх буюу бүгдийг цуцлах
function мөнгө_шилжүүлэх(PDO $pdo, int $хариулагч, int $хүлээн_авагч, float $дүн): void {
    // Transaction эхэлнэ
    $pdo->beginTransaction();

    try {
        // Хариулагчаас хасна
        $stmt = $pdo->prepare("UPDATE дансны_мэдээлэл SET үлдэгдэл = үлдэгдэл - ? WHERE хэрэглэгч_id = ?");
        $stmt->execute([$дүн, $хариулагч]);

        // Хэрвээ үлдэгдэл хүрэлцэхгүй бол Exception шидэнэ
        $stmt = $pdo->prepare("SELECT үлдэгдэл FROM дансны_мэдээлэл WHERE хэрэглэгч_id = ?");
        $stmt->execute([$хариулагч]);
        $үлдэгдэл = $stmt->fetchColumn();

        if ($үлдэгдэл < 0) {
            throw new RuntimeException("Үлдэгдэл хүрэлцэхгүй байна.");
        }

        // Хүлээн авагчид нэмнэ
        $stmt = $pdo->prepare("UPDATE дансны_мэдээлэл SET үлдэгдэл = үлдэгдэл + ? WHERE хэрэглэгч_id = ?");
        $stmt->execute([$дүн, $хүлээн_авагч]);

        // Бүгд амжилттай — баталгаажуулна
        $pdo->commit();
        echo "Шилжүүлэг амжилттай.\n";

    } catch (Exception $e) {
        // Алдаа гарвал бүх үйлдлийг цуцална
        $pdo->rollBack();
        echo "Шилжүүлэг цуцлагдлаа: " . $e->getMessage() . "\n";
    }
}
?>

Transaction нь "бүгдийг хий эсвэл юуг ч битгий хий" гэсэн зарчмаар ажилладаг. Банкны шилжүүлэгт нэг тал хасагдаж нөгөөд нэмэгдэхгүй байхаас сэргийлэхэд зайлшгүй шаардлагатай.

Дараагийн хичээлд:

Session үндэслэлийг судална. Хэрэглэгч нэвтэрсний дараа мэдээллийг хуудсуудын хооронд хэрхэн дамжуулдаг, session_start(), $_SESSION, session-ийг хэрхэн устгадгийг жишээгээр үзнэ.