Thực hành xây dựng ứng dụng web PHP CRUD – 1

    0

    Qua loạt bài học PHP từ đầu đến giờ bạn đã nắm được rất nhiều kiến thức mới. Giờ là lúc chúng ta vận dụng tổng hợp để giải quyết một bài toán quản lý (hơi hơi) thực tế. Bài học này hướng tới vận dụng và củng cố những kiến thức bạn đã học trong những bài học về vận dụng PHP trong môi trường web.

    Chuẩn bị project

    Các loại ứng dụng quản lý vốn rất phổ biến. Chúng cũng được gọi chung là những ứng dụng dạng CRUD do hoạt động của chúng gắn liền với 4 thao tác với dữ liệu: Create (tạo mới) – Retrieve (trích xuất) – Update (cập nhật) – Delete (xóa bỏ).

    Trong bài học này chúng ta sẽ cùng xây dựng một ứng dụng quản lý sách điện tử đơn giản. Do kiến thức chưa đầy đủ, chúng ta sẽ chỉ xây dựng một phần chức năng của ứng dụng, bao gồm chức năng xuất (Retrieve) và xóa (Delete) dữ liệu. Hai chức năng còn lại (Update và Create) sẽ được thực hiện trong bài thực hành tổng hợp số 2.

    Để thực hiện bài thực hành này bạn cần download template dự án chúng tôi đã chuẩn bị trước. Các kỹ thuật xây dựng template này đã được trình bày trong bài học về cấu trúc page và site.

    Để tiện lợi cho bạn trong quá trình học, chúng tôi đã tạo sẵn một mẫu project mà bạn có thể tải từ link sau:
    https://1drv.ms/u/s!Ar_aj4rIJ2qGkvwwcwHs3wUOLHWcrw?e=5GidgF
    Khi sử dụng mẫu project này chú ý:
    (1) thay đổi đường dẫn của hằng APPLICATION_PATH trong file core/config.php cho phù hợp với đường dẫn từ document root.
    (2) thay đổi tên ứng dụng APPLICATION_NAME trong file core/config.php.
    (3) nếu có nhu cầu thay đổi layout, bạn có thể sửa trực tiếp vào file core/layout.php hoặc tạo file layout mới trong thư mục core rồi cập nhật hằng DEFAULT_LAYOUT.
    (4) đây cũng là một project cho PhpStorm. Chúng tôi cũng đã tạo sẵn một template file php (My PHP Template) có sẵn các lệnh cần thiết để sử dụng layout chung.
    (5) mẫu project này đã tích hợp sẵn Bootstrap và jQuery.

    Sau khi tải về và giải nén bạn sẽ thu được một thư mục Template với cấu trúc như sau:

    Khi sử dụng PhpStorm bạn có hai phương án tạo dự án: sử dụng cấu hình in-place server và sử dụng cấu hình local server. Để đơn giản, chúng ta sử dụng cấu hình in-place server. Nếu muốn bạn cũng có thể tự cấu hình local server.

    (1) Copy thư mục Template vào htdocs và đổi tên thành BookmanV1

    (2) Mở project BookmanV1 trong PhpStorm.

    (3) Cấu hình in-place server cho dự án.

    Nếu không nhớ, bạn có thể đọc lại bài học về cấu hình PhpStorm với XAMPP.

    (4) Mở file core\config.php và điều chỉnh hai hằng:

    define('APPLICATION_PATH', '/bookmanv1/');
    define('APPLICATION_NAME', 'Bookman V1');

    Giờ chạy thử nghiệm với URL localhost/bookmanv1/ bạn thu được kết quả như sau:

    Mẫu dự án trên đã tạo sẵn cho chúng ta một layout chung (file core/layout.php) và sử dụng kỹ thuật outut buffer để chèn nội dung của page vào layout. File layout.php cũng sử dụng Bootstrap css cho định dạng.

    Truy xuất dữ liệu

    Một lỗi rất thường gặp ở những người mới học lập trình là trộn lẫn code vốn có các chức năng khác biệt nhau. Thứ code trộn lẫn lộn này thường được gọi là spaghetti code (code lộn xộn như món mỳ Ý). Đối với ứng dụng PHP điều này còn gây ra những vấn đề khó lớn hơn khi file PHP có thể chứa cả mã PHP, mã HTML, CSS, thậm chí cả JavaScript.

    Thông thường với các ứng dụng đơn giản chúng ta đều có code cho giao diện, truy xuất dữ liệu, logic nghiệp vụ. Code cho giao diện cũng phân biệt việc hiện thị và xử lý dữ liệu (ví dụ, xử lý các sự kiện phát sinh trên giao diện như bấm nút).

    Trong bài thực hành này chúng ta cũng sẽ vận dụng cách phân chia code như vậy.

    Ở phần này trước hết chúng ta sẽ xây dựng thành phần truy xuất dữ liệu cho ứng dụng. Thành phần này chịu trách nhiệm: (1) làm việc với file dữ liệu json – bao gồm đọc và ghi dữ liệu, (2) thực hiện các xử lý trên dữ liệu như xóa, thêm mới, cập nhật, (3) thực hiện các thao tác quản lý trên dữ liệu như sắp xếp, tìm kiếm, phân trang.

    Trong bài thực hành này chúng ta sẽ thực hiện một phần chức năng liên quan đến đọc/ghi/xóa dữ liệu. Các chức năng khác sẽ được thực hiện trong các bài thực hành tổng hợp khác.

    Hãy cùng thực hiện.

    (1) Tạo thư mục data

    (2) Tạo file data.json trong thư mục data vừa tạo và viết code như sau:

    {
      "1": {
        "title": "PHP programming for dummy",
        "authors": "Trump D.",
        "publisher": "Washington",
        "year": 2020,
        "description": "The best programming book ever written by a US president!"
      },
      "2": {
        "title": "C# programming for dummy",
        "authors": "Trump D.",
        "publisher": "Washington",
        "year": 2020,
        "description": "The best programming book ever written by a US president!"
      },
      "3": {
        "title": "Python programming for dummy",
        "authors": "Trump D.",
        "publisher": "Washington",
        "year": 2020,
        "description": "The best programming book ever written by a US president!"
      },
      "4": {
        "title": "Java programming for dummy",
        "authors": "Trump D.",
        "publisher": "Washington",
        "year": 2020,
        "description": "The best programming book ever written by a US president!"
      },
      "5": {
        "title": "C++ programming for dummy",
        "authors": "Trump D.",
        "publisher": "Washington",
        "year": 2020,
        "description": "The best programming book ever written by a US president!"
      }
    }

    File data\data.json tạm thời đóng vai trò cơ sở dữ liệu cho ứng dụng. Về sau chúng ta sẽ học cách làm việc với cơ sử dữ liệu MySQL.

    (3) Tạo thư mục data-service

    (4) Tạo file book-service.php trong thư mục data-service và viết code như sau:

    <?php
    include_once ('../core/functions.php');
    
    $file = path('data/data.json');
    // cấu trúc của dữ liệu
    $books = [
        1 => [
            'title' => '',
            'authors' => '',
            'publisher' => '',
            'year' => 2020,
            'summary' => ''
        ]
    ];
    
    function book_load() {
        global $books, $file;
        $json = file_get_contents($file);
        $books = json_decode($json, true);
    }
    
    function book_save() {
        global $books, $file;
        $json = json_encode($books);
        file_put_contents($file, $json);
    }
    
    function book_delete($id) {
        global $books;
        if(array_key_exists($id, $books)){
            unset($books[$id]);
            book_save();
        }
    }

    File script này chứa các hàm chuyên để làm việc với dữ liệu. Tạm thời chúng ta chỉ xây dựng các hàm hỗ trợ đọc/ghi/xóa dữ liệu.

    Các hàm này đều sử dụng các kỹ thuật lập trình PHP cơ bản và dữ liệu kiểu mảng mà bạn đã học. Thực ra bạn cũng đã gặp các hàm này trong bài thực hành tổng hợp PHP CLI.

    Ở đây chỉ cần lưu ý hàm path. Đây là một hàm tự xây dựng trong core\functions.php có nhiệm vụ trả lại đường dẫn tuyệt đối từ một đường dẫn tương đối:

    function path($path) {
        return APPLICATION_ROOT.'/'.$path;
    }

    Hằng APPLICATION_ROOT định nghĩa trong core\config.php.

    Xuất bảng dữ liệu

    Chúng ta đi tiếp với chức năng xuất dữ liệu. Có hai loại xuất dữ liệu cần thực hiện: xuất dữ liệu ở dạng bảng; xuất dữ liệu chi tiết của từng đối tượng.

    Chúng ta thực hiện chức năng xuất dữ liệu bảng trước.

    (1) Tạo thư mục book

    Tất cả các code cho giao diện quản lý sách sẽ nằm trong thư mục này.

    (2) Tạo hai file index.phpindex.inc.php trong thư mục book và viết code như sau:

    <?php
    include_once '../data-service/book-service.php';
    
    function on_get() {
        book_load();
        global $books;
    
        return $books;
    }
    <?php include_once '../core/functions.php'; ?>
    
    <?php
    include_once 'index.inc.php';
    $result = on_get();
    ?>
    
    <?php start_content('Book collection'); ?>
    
    <?php if (count($result) > 0): ?>
        <table class="table">
            <thead>
            <tr>
                <th>Id</th>
                <th>Title</th>
                <th>Authors</th>
                <th>Publisher</th>
                <th>Year</th>
                <th></th>
            </tr>
            </thead>
            <tbody>
            <?php foreach ($result as $k => $b) : ?>
                <tr>
                    <td><?= $k ?></td>
                    <td><a href="detail.php?id=<?= $k ?>"><?= $b['title'] ?></a></td>
                    <td><?= $b['authors'] ?></td>
                    <td><?= $b['publisher'] ?></td>
                    <td><?= $b['year'] ?></td>
                    <td>
                        <a class="btn btn-sm btn-outline-primary" href="detail.php?id=<?= $k ?>">Detail</a>
                        <a class="btn btn-sm btn-outline-danger" href="delete.php?id=<?= $k ?>">Delete</a>
                    </td>
                </tr>
            <?php endforeach; ?>
            </tbody>
        </table>
    <?php else: ?>
        <b style='color:yellow;'>The collection is empty. Try adding some books first.</b>
    <?php endif; ?>
    
    <?php end_content(); ?>

    Ở đây chúng ta vận dụng một mô hình gần tương tự như mô hình code-behind. Theo đó, code PHP cho xử lý nằm trong một file riêng, code PHP trộn HTML cho giao diện nằm trong một file.

    Giao diện chỉ làm đúng nhiệm vụ là một template để chèn dữ liệu vào. Trong giao diện mặc dù có chứa một số logic nhưng đây thuần túy là logic của việc hiển thị.

    Chúng ta cũng sử dụng cơ chế output buffer với file layout. Hai hàm xây dựng sẵn để hỗ trợ làm việc với layout và output buffer là start_content và end_content cùng nằm trong file core\functions.php.

    Trong bài học về cấu trúc web site và web page chúng ta đã trình bày chi tiết về cách xây dựng hai hàm này.

    (3) chạy thử với link localhost/bookmanv1/book/index.php bạn sẽ thu được kết quả như sau:

    Hiển thị thông tin chi tiết

    Tương tự, để hiển thị nội dung chi tiết của mỗi dữ liệu, chúng ta cũng tạo hai file, một cho giao diện, một cho xử lý.

    (1) Tạo file detail.php trong thư mục book

    (2) Tạo file detail.inc.php trong thư mục book

    (3) Viết code cho các file này như sau:

    <?php
    include_once '../data-service/book-service.php';
    
    function on_get() {
        book_load();
        global $books;
    
        if(isset($_GET['id'])){
            $id = $_GET['id'];
            if(array_key_exists($id, $books))
            {
                @$book = $books[$id];
                return isset($book) ? $book : false;
            }
        }
        return false;
    }
    <?php include_once '../core/functions.php'; ?>
    <?php
    include_once 'detail.inc.php';
    $result = on_get();
    ?>
    
    <?php start_content('Book detail'); ?>
    
    <?php if ($result === false) : ?>
        <h3 style='color:red;'>Book not found!</h3>
    <?php else: $b = $result ?>
        <h1>Book detail</h1>
        <table class="table">
            <tr>
                <th>Title:</th>
                <td><?= $b['title'] ?></td>
            </tr>
            <tr>
                <th>Authors:</th>
                <td><?= $b['authors'] ?></td>
            </tr>
            <tr>
                <th>Publisher:</th>
                <td><?= $b['publisher'] ?></td>
            </tr>
            <tr>
                <th>Year:</th>
                <td><?= $b['year'] ?></td>
            </tr>
            <tr>
                <th>Summary:</th>
                <td><?= $b['description'] ?></td>
            </tr>
        </table>
    <?php endif ?>
        <a class="btn btn-outline-primary" href="index.php">Back to list</a>
    <?php end_content(); ?>

    Từ trang danh sách (index.php), ấn một đường link bất kỳ sẽ thu được kết quả tương ứng:

    Xóa dữ liệu

    (1) Tạo file delete.inc.php và delete.php trong thư mục book.

    (2) Viết code như sau:

    <?php
    include_once '../data-service/book-service.php';
    
    function on_get() {
        if (isset($_GET['id'])) {
            book_load();
            global $books;
            $id = $_GET['id'];
            if (array_key_exists($id, $books)) {
                if (isset($_GET['confirm'])) {
                    book_delete($id);
                   // redirect tới trang index.php
                    header("Location: index.php");
                    exit();
                } else {
                    return ['id' => $id, 'data' => $books[$id]];
                }
            }
        }
        return false;
    }
    <?php include_once '../core/functions.php'; ?>
    
    <?php
    include_once 'delete.inc.php';
    $result = on_get();
    ?>
    
    <?php start_content('Confirm deleting'); ?>
    
    <?php if ($result === false) : ?>
        <h3 style='color:red;'>Book not found!</h3>
    <?php else: $b = $result['data'] ?>
        <h1>Deletion confirm</h1>
        <table class="table">
            <tr>
                <th>Title:</th>
                <td><?= $b['title'] ?></td>
            </tr>
            <tr>
                <th>Authors:</th>
                <td><?= $b['authors'] ?></td>
            </tr>
            <tr>
                <th>Publisher:</th>
                <td><?= $b['publisher'] ?></td>
            </tr>
            <tr>
                <th>Year:</th>
                <td><?= $b['year'] ?></td>
            </tr>
            <tr>
                <th>Summary:</th>
                <td><?= $b['description'] ?></td>
            </tr>
        </table>
        <a class="btn btn-outline-danger" href="delete.php?id=<?=$result['id']?>&confirm=1">Delete</a>
    <?php endif ?>
        <a class="btn btn-outline-primary" href="index.php">Back to list</a>
    
    <?php end_content(); ?>

    Khi ấn nút Delete bên cạnh mỗi cuốn sách bạn sẽ được chuyển sang giao diện xác nhận xóa:

    Nếu bấm Delete lần nữa, dữ liệu sẽ bị xóa và bạn sẽ bị chuyển hướng (redirect) về trang book/index.php. Nếu chọn Back to list thì chuyển về trang index mà không xóa.

    Kết luận

    Trong bài thực hành này bạn đã thực hiện một ứng dụng PHP tương đối hoàn chỉnh chỉ sử dụng các kỹ thuật cơ bản đã học.

    Qua bài học này cần lưu ý về cách thức tổ chức code của ứng dụng cũng như việc sử dụng layout cho web site.

    Bạn có thể tải mã nguồn từ link sau: https://1drv.ms/u/s!Ar_aj4rIJ2qGkvtXQDGX17p_STnK9A?e=Se1l3K

    Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần Thảo luận cuối trang.
    Nếu cần trao đổi riêng với chúng tôi, hãy gửi email hoặc nhắn tin qua form liên hệ.
    Nếu bài viết hữu ích với bạn, hãy giúp chúng tôi chia sẻ tới mọi người.
    Đăng ký theo dõi trang facebook để nhận thông tin về bài viết mới.
    Tắt Adblocker hoặc whitelist trang để hỗ trợ chúng tôi.
    Cảm ơn bạn!

    * Bản quyền bài viết thuộc về Tự học ICT. Đề nghị tôn trọng bản quyền. DMCA.com Protection Status
    Subscribe
    Notify of
    guest
    0 Thảo luận
    Inline Feedbacks
    View all comments