Building CRUD for User Management

In this section, we'll look at having the following output displayed on our screen:

Building CRUD for User Management

Note

When reading a user, know that in this table it is possible to control what is displayed. Not all information about that user needs to be displayed.

In this section, we will build our users section to Create, Read, Update, and Delete users.

Follow these steps to build CRUD for user management:

  1. First, we need a few more queries. Open app/Models/User.php.
  2. Create the following methods:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    get_users() – returns all users ordered by username
        $data = $this->db->select('username from users where username = :username', [':username' => $username]);
        return (isset($data[0]->username) ? $data[0]->username : null);
    }
  3. Now, create a Users Controller in app/Controllers. Create Users.php.
  4. Set the namespace and import the helpers and User Model:
    use SystemBaseController;
    use AppHelpersSession;
    use AppHelpersUrl;
    use AppModelsUser;
    class Users extends BaseController
    {
  5. Next, create a class property called $user and a __construct method. Then, check if the user is logged in, and if not, redirect them to the login page.
  6. Create a new user instance:
    $this->user = new User()

    Note

    Doing this check in a construct means all the methods of this class will be protected from unauthorized users.

    protected $user;
    
    public function __construct()
    {
        parent::__construct();
    
        if (! Session::get('logged_in')) {
            Url::redirect('/admin/login');
        }
    
        $this->user = new User();
    }
  7. Next, create an index method. This will call get_users() and load a view and pass in the users object:
    public function index()
    {
        $users = $this->user->get_users();
        $title = 'Users';
    
        $this->view->render('admin/users/index', compact('users', 'title'));
    }
  8. For the view, create app/views/admin/users/index.php.
  9. Include the layout files and create a table to display a list of users:
    foreach($users as $user)
  10. Loop through all the user records. As a security measure, when printing data from a database, we'll make use of htmlentities(). This converts all tags into their HTML counterparts, meaning if any code had been injected into the database, it would simply be printed as text, making it useless:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    <?php
    include(APPDIR.'views/layouts/header.php');
    include(APPDIR.'views/layouts/nav.php');
    ……
        </table>
    </div>
    
    <?php include(APPDIR.'views/layouts/footer.php');?>
  11. Inside the loop, we have two action links for editing and deleting. Note that the user's ID is being passed to the end of the href value. This is to pass the ID to the URL.
  12. Also, we have an Add User button that points to /users/add. Let's create this. In your Users Controller, create a new method called add():
    public function add()
        {
            $errors = [];
    
            $title = 'Add User';
            $this->view->render('admin/users/add', compact('errors', 'title'));
        }
  13. Now, create a view in app/views/admin/users called add.php.
  14. Include the layout files and set the page title. Next, create a form with a method set to post.
  15. You need four inputs for username, email, password, and confirm password. Make sure each input has a name.

    Note

    Sticky forms is useful in the event of errors.

    Sticky forms are forms that retain their data in the event of an error. The inputs will still show the values entered into them.

  16. To implement sticky forms on the username and email, use a ternary:
    (isset($_POST['username']) ? $_POST['username'] : '')

    This says if the $_POST['username'] is set, then print it, otherwise print an empty string:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    <?php
    include(APPDIR.'views/layouts/header.php');
    include(APPDIR.'views/layouts/nav.php');
    include(APPDIR.'views/layouts/errors.php');
    ……..
    </form>
    
    <?php include(APPDIR.'views/layouts/footer.php');?>
  17. When submitted, the form data will be posted to /users/add. This needs handling in the add method of the Users Controller.
  18. Check for the form submission:
    if (isset($_POST['submit'])) {
  19. Next, collect the form data:
    $username            = (isset($_POST['username']) ? $_POST['username'] : null);
    $email                    = (isset($_POST['email']) ? $_POST['email'] : null);
    $password            = (isset($_POST['password']) ? $_POST['password'] : null);
    $password_confirm    = (isset($_POST['password_confirm']) ? $_POST['password_confirm'] : null);
  20. Then, start the validation process.
  21. Check that the username is more than 3 characters in length:
    if (strlen($username) < 3) {
        $errors[] = 'Username is too short';
    }
  22. Next, check if the $username exists already in the database by passing $username to a get_user_username($username) method on the Model. If the results are the same as $username, then it already exists, so create an error:
    else {
        if ($username == $this->user->get_user_username($username)){
            $errors[] = 'Username address is already in use';
        }
    }
  23. For email validation, check that the email is in a valid format by using filter_var and FILTER_VALIDATE_EMAIL. If this does not return true, create an error.
  24. Like with the username, check if the $email exists in the database already:
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        $errors[] = 'Please enter a valid email address';
    } else {
        if ($email == $this->user->get_user_email($email)){
            $errors[] = 'Email address is already in use';
        }
    }
  25. For the passwords, check that $password matches $password_confirm or creates an error. Otherwise, check that the password is more than 3 characters in length:
    if ($password != $password_confirm) {
        $errors[] = 'Passwords do not match';
    } elseif (strlen($password) < 3) {
        $errors[] = 'Password is too short';
    }
  26. If there are no errors, carry on and set a $data array containing the data to be inserted into the database.

    Note

    Note the password using a password_hash() function. This is using PHP's built-in password function that, by default, will use bcrypt, which at the time of writing is the most secure hashing technique.

  27. Create the user by calling $this->insert($data) and set a message before redirecting back to /users:
    if (count($errors) == 0) {
    
        $data = [
            'username' => $username,
            'email' => $email,
            'password' => password_hash($password, PASSWORD_BCRYPT)
        ];
    
        $this->user->insert($data);
    
        Session::set('success', 'User created');
        Url::redirect('/users');
    
    }

    The full method looks like this:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    public function add()
        {
            $errors = [];
    …….
            $title = 'Add User';
            $this->view->render('admin/users/add', compact('errors', 'title'));
        }
  28. To edit users, the URL structure is /users/edit/1. The number at the end is the ID of the user.
  29. Create a method called edit($id) that accepts a parameter called $id.
  30. First, check that $id is a number, otherwise redirect back to /users.
  31. Get the user's data by calling $this>user->get_user($id) and pass in the ID to the users Model method. This will return a user object or null if the record is not found.
  32. If the $user is equal to null, redirect to a 404 page. Otherwise, set up an $errors array, $title, and load the view, passing in user, errors, and title to compact():
    public function edit($id)
    {
        if (! is_numeric($id)) {
     Url::redirect('/users');
        }
        $user = $this->user->get_user($id);
        if ($user == null) {
            Url::redirect('/404');
        }
    
        $errors = [];
    
        $title = 'Edit User';
        $this->view->render('admin/users/edit', compact('user', 'errors', 'title'));
    }
  33. Now, create a view in app/views/admin/users called edit.php:

    Note

    This is almost identical to the add.php view. The main difference is in the username and email inputs. They are pre-populated with the user object:

    <input class="form-control" id="username" type="text" name="username" value="<?=$user->username;?>" required />

    The <?=$user->username;?> is the user object in action using -> after $user. You specify what column you want out of it.

    It's important that you do not pre-populate the password fields; they should only be filled in when the user wants to change the password. As such, put a message to inform the user that they should enter the password only if they want to change their existing password:

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    <?php
    include(APPDIR.'views/layouts/header.php');
    include(APPDIR.'views/layouts/nav.php');
    include(APPDIR.'views/layouts/errors.php');
    ……
    </form>
    
    <?php include(APPDIR.'views/layouts/footer.php');?>

    Note

    When this is submitted, the edit($id) method will process the request.

  34. Just like the add() method, check for the form submission, collect the form data, and perfect the form validation.
  35. This time, we won't check if the username or email exists in the database, only that they are provided and are valid:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    if (isset($_POST['submit'])) {
        $username            = (isset($_POST['username']) ? $_POST['username'] : null);
    ……
                $errors[] = 'Password is too short';
            }
        }
  36. Next, check that there are no errors:
    if (count($errors) == 0) {
  37. Set the $data array to update the user's record. This time, only the username and email are provided:
    $data = [
        'username' => $username,
        'email' => $email
    ];
  38. If the password has been updated, then add the password to the $data array:
    if ($password != null) {
        $data['password'] = password_hash($password, PASSWORD_BCRYPT);
    }
  39. The where statement says where the ID matches $id. Run the update() and set a message and redirect to the users page:
    $where = ['id' => $id];
    
    $this->user->update($data, $where);
    
    Session::set('success', 'User updated');
    
    Url::redirect('/users');

    The full update method looks like this:

    Note

    For full code snippet, refer to Lesson 7.php file in the code files folder.

    public function edit($id)
    {
        if (! is_numeric($id)) {
    ……
        }
        $title = 'Edit User';
        $this->view->render('admin/users/edit', compact('user', 'errors', 'title'));
    }
  40. The last step to complete the users Controller is adding the ability to delete users.
  41. Like the edit, the URL structure will pass in an $id as part of the URL in the format of /users/delete/2.
  42. Create a method called delete($id).
  43. Check if the $id is numeric and check if the $id matches the session $_SESSION['user_id'], otherwise kill the page. You don't want to allow a user to delete their own record.
  44. Next, get the user by calling $this->user->get_user($id) and check if the $user object is not equal to null. Otherwise, redirect to a 404 page.
  45. Next, create a $where array that says where the $id matches the ID in the database. Note we do not use a $data array. In this case, we only pass a $where. This is because you cannot select columns, only a row, so the $data would be pointless.
  46. Lastly, set a message and redirect back to /users:
    public function delete($id)
        {
            if (! is_numeric($id)) {
                Url::redirect('/users');
            }
            if (Session::get('user_id') == $id) {
                die('You cannot delete yourself.');
            }
            $user = $this->user->get_user($id);
            if ($user == null) {
                Url::redirect('/404');
            }
            $where = ['id' => $user->id];
            $this->user->delete($where);
            Session::set('success', 'User deleted');
            Url::redirect('/users');
        }
  47. Now, run the application:
    php –S localhost:8000 –t webroot
  48. Go to http://localhost:8000/users, click on Add User, and fill in the form.
  49. First, if you try to submit the form without any data, you will see the HTML client validation that comes from putting a required attribute on the inputs.
  50. Try filling in a user with the same username as one you've already created, and you'll see the server validation rules up and running.
  51. Finally, fill in the form completely with new user details and you will be redirected to /users and see the new user, along with a confirmation message.
  52. Click on Edit next to the user you want to edit. You will then be presented with the edit form with the username and email filled in. Pressing submit will take you back to the users page.
  53. Pressing delete will delete the user right away (providing the user is not you) with no confirmation. Let's fix that!
  54. Our requirement states that when the user presses delete, a confirmation window should be displayed. If OK is clicked, then the delete URL will be called, and if cancel is clicked, nothing will happen.
  55. Open app/views/admin/users/index.php and place this JavaScript before the footer.php code block:
    <script language="JavaScript" type="text/javascript">
    function del(id, title) {
        if (confirm("Are you sure you want to delete '" + title + "'?")) {
            window.location.href = '/users/delete/' + id;
        }
    }
    </script>
  56. This defines a JavaScript function which accepts an ID and a username. When the confirm() passes a window.location.href, it will run, redirecting the page to the delete URL before passing in the ID var to the end of the URL.
  57. In the loop where you see the delete link:
    <a href="/users/delete/<?=$row->id;?>" class="btn btn-xs btn-danger">Delete</a>

    Replace it with:

    <a href="javascript:del('<?=$row->id;?>','<?=$row->username;?>')" class="btn btn-xs btn-danger">Delete</a>

    This calls javascript:del(), which triggers the confirmation popup and passes in the user's ID and username.

  58. Save the file and run the page. When you click on delete, you will now see a confirmation prompt. Clicking OK will allow the delete to go ahead, while pressing cancel will stop the redirect from running.

Optional Activity

  1. Add additional fields about a user, perhaps their address, age, hobbies, eye color, or anything of your, choosing.
  2. Ensure these are processed in the Method and Controller and ensure that the database table is ready to accept them.
  3. Ensure that these are included in the view.
  4. In the index view, the student can select information of their choosing to help identify the user in the table.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset