Geek Logbook

Tech sea log book

How to Implement MVC in CodeIgniter to Clean Up Your Views

When building web applications, it’s easy to end up with PHP logic mixed directly into your HTML views, especially in smaller projects. However, this can lead to messy, hard-to-maintain code. The Model-View-Controller (MVC) pattern is a great solution to separate concerns and make your application cleaner and more maintainable.

In this post, we’ll explore how you can refactor a view-heavy piece of PHP code into an MVC pattern using the CodeIgniter framework.

Problem: PHP Logic Embedded in Views

Here’s a common scenario where logic is embedded directly in the HTML view:

<h1 class="title"><?php echo $course_details['title']; ?></h1>
<p class="subtitle"><?php echo $course_details['short_description']; ?></p>
<div class="rating-row">
    <?php
    $total_rating = $this->crud_model->get_ratings('course', $course_details['id'], true)->row()->rating;
    $number_of_ratings = $this->crud_model->get_ratings('course', $course_details['id'])->num_rows();
    if ($number_of_ratings > 0) {
        $average_ceil_rating = ceil($total_rating / $number_of_ratings);
    } else {
        $average_ceil_rating = 0;
    }
    ?>

    <?php for ($i = 1; $i <= 5; $i++): ?>
        <i class="fas fa-star" style="color: <?= ($i <= $average_ceil_rating) ? '#f5c85b' : '#ccc'; ?>"></i>
    <?php endfor; ?>
    
    <span class="d-inline-block average-rating"><?= $average_ceil_rating ?></span>
    <span>(<?= $number_of_ratings . ' ' . get_phrase('ratings'); ?>)</span><br>

    <span class="enrolled-num">
        <?php
        $number_of_enrolments = $this->crud_model->enrol_history($course_details['id'])->num_rows();
        echo (300 + $number_of_enrolments) . ' ' . get_phrase('students_enrolled');
        ?>
    </span>
</div>

Here, logic for fetching course details, calculating ratings, and displaying student enrolment is mixed with HTML, which can make the code difficult to read, maintain, and test.

Solution: Refactoring to MVC

We can clean this up by applying the MVC pattern, which separates the responsibilities into three components:

  • Model: Handles data-related logic and database interaction.
  • Controller: Processes incoming requests, interacts with the model, and passes data to the view.
  • View: Displays data to the user, containing only HTML and minimal PHP for rendering.

Let’s refactor the example above into a proper MVC structure.

Step 1: Controller Logic

First, we’ll move the data-fetching and processing logic into the controller.

class CourseController extends CI_Controller {

    public function course_details($course_id) {
        // Fetch course details from the database
        $data['course_details'] = $this->crud_model->get_course_by_id($course_id)->row_array();

        // Calculate the average rating
        $total_rating = $this->crud_model->get_ratings('course', $course_id, true)->row()->rating;
        $number_of_ratings = $this->crud_model->get_ratings('course', $course_id)->num_rows();
        $data['average_ceil_rating'] = ($number_of_ratings > 0) ? ceil($total_rating / $number_of_ratings) : 0;

        // Fetch student enrollment count
        $data['number_of_enrolments'] = 300 + $this->crud_model->enrol_history($course_id)->num_rows();

        // Load the view and pass the data
        $this->load->view('course_details_view', $data);
    }
}

In this controller method, all the necessary data for the course details page is fetched and processed, and then passed to the view. This approach keeps the view clean and focused solely on presentation.

Step 2: Model Logic

Next, we move the database queries into the model. This keeps the controller lightweight and only concerned with coordinating between the model and the view.

class Crud_model extends CI_Model {

    public function get_course_by_id($course_id) {
        return $this->db->get_where('courses', array('id' => $course_id));
    }

    public function get_ratings($type, $id, $average = false) {
        if ($average) {
            $this->db->select_avg('rating');
        }
        return $this->db->get_where('ratings', array('type' => $type, 'id' => $id));
    }

    public function enrol_history($course_id) {
        return $this->db->get_where('enrolments', array('course_id' => $course_id));
    }
}

Here, we define functions for getting course details, ratings, and enrollment history. The controller can now interact with the model to retrieve this data.

Step 3: View Logic

Finally, the view is simplified to focus on rendering the data. It no longer contains business logic or database queries.

<h1 class="title"><?= $course_details['title']; ?></h1>
<p class="subtitle"><?= $course_details['short_description']; ?></p>

<div class="rating-row">
    <span class="course-badge best-seller">Destacado</span>
    
    <?php for ($i = 1; $i <= 5; $i++): ?>
        <i class="fas fa-star" style="color: <?= ($i <= $average_ceil_rating) ? '#f5c85b' : '#ccc'; ?>"></i>
    <?php endfor; ?>

    <span class="d-inline-block average-rating"><?= $average_ceil_rating ?></span>
    <span>(<?= $number_of_ratings . ' ' . get_phrase('ratings'); ?>)</span><br>

    <span class="enrolled-num">
        <?= $number_of_enrolments . ' ' . get_phrase('students_enrolled'); ?>
    </span>
</div>

The view now only handles displaying the data that has already been prepared by the controller. It uses minimal PHP for output, which improves readability and separation of concerns.

Benefits of Using MVC

  • Separation of concerns: Each component (Model, View, Controller) has a specific responsibility, making the code more organized and maintainable.
  • Reusability: By keeping business logic in models and controllers, the same data can be used across multiple views.
  • Scalability: It’s easier to expand or modify your application without introducing new bugs, as changes are isolated to specific parts of the MVC architecture.

Conclusion

Refactoring your views to follow the MVC pattern improves code maintainability, readability, and scalability. By keeping your views focused on presentation and moving business logic into the controller and model, you create a more organized and professional codebase.

Using the MVC pattern in CodeIgniter allows for a clean separation between logic and presentation, making your application easier to maintain and extend.

Tags: