Home » Php » how to implement mvc in core php

how to implement mvc in core php

Posted by: admin July 12, 2020 Leave a comment

Questions:

how is mvc architecture used in php without any framework?

How to&Answers:

Updated 2020-02-11: Refactoring the answer to include a few best practices and being closer to PHP 7.4.

Simplest PHP MVC approach

Thousands words does not compete with a clean example, so here is a simple use case:

Imagine you want to display a page describing a “car” (given a “car id”) from an imaginary car vendor: http://example.com/car.php?id=42 (will be http://example.com/car/42 later).

Very basically, you can structure your code with an hierarchy like:

A configuration directory (this isn’t part of the MVC architectural pattern):

+ config/
  - database.php
        <?php
        return new PDO(getenv("DB_DSN"), getenv("DB_USER"), getenv("DB_PASSWORD"));

A folder for your document root (scripts acting like Controllers):

+ htdocs/
  - car.php
        <?php
        $carService = new CarService(require "config/database.php");
        $car = $carService->getById($_GET["id"]);
        require "car.php";

A folder encapsulating your Model/business logic (hint: “Thin Controllers, Fat model”):

+ src/
  - CarService.php
        <?php
        class CarService {
            private PDO $database;

            public function __construct(PDO $database) {
                $this->database = $database;
            }

            public function getById(int $id): CarEntity {
                return $this->database->query(
                    "SELECT model, year, price " .
                    "FROM car " .
                    "WHERE id = $id"
                )->fetch(PDO::FETCH_CLASS, CarEntity::class);
            }
        }

A last folder containing all your Views(/templates):

+ views/
  - car.php
        <!DOCTYPE html>
        <html>
        <head>
            <title>Car - <?= htmlspecialchars($car->model) ?></title>
        </head>
        <body>
        <h1><?= htmlspecialchars($car->model) ?></h1>
        Year: <?= htmlspecialchars($car->year) ?>
        Price: <?= htmlspecialchars($car->price) ?>
        </body>
        </html>

For the code above to work, you will need PHP to be configured with:

include_path="/the/path/to/src:/the/path/to/views"

To go further

Nice URLs

You might want nice URLs, if using Apache you can achieve this with:

RewriteEngine On
RewriteRule ^/car/(\d+)$ /car.php?id=$1 [L]

This enables writing URLs like http://example.com/car/42 which will be internally converted to http://example.com/car.php?id=42

Views as classes

In the above solution, car.php is included from the global scope, that is why $car is directly available, but $carService too!

One way to restrict what the templates may access is to transform it as a class:

views/CarView.php:

<?php
class CarView {
    private CarEntity $car;

    public function __construct(CarEntity $car) {
        $this->car = $car;
    }

    public function __invoke(): void {
?>
<!DOCTYPE html>
<html>
    <head>
        <title>Car - <?= htmlspecialchars($this->car->model) ?></title>
    </head>
    <body>
        <h1><?= htmlspecialchars($this->car->model) ?></h1>
        Year: <?= htmlspecialchars($this->car->year) ?>
        Price: <?= htmlspecialchars($this->car->price) ?>
    </body>
</html>
<?php
    }
}

and then adapting the controller:

htdocs/car.php:

<?php
$carService = new CarService(require "config/database.php");
$view = new CarView($carService->getById($_GET["id"]));
$view();

Reusing views

Using plain PHP files as templates, nothing prevents you from creating headers.php, footers.php, menu.php,… which you can reuse with include()/require() to avoid duplicated HTML.

Using classes, re-usability can be obtained by combining them, for example, a LayoutView can be responsible for the global layout, and, in turn, calls another View component:

<?php

class LayoutView {
    protected string $lang;

    public function __construct(string $lang) {
        $this->lang = $lang;
    }

    // __invoke(): for embracing the "Single Responsibility" principle
    public function __invoke(View $view): void {
        ?>
<!DOCTYPE html>
<html lang="<?= $this->lang ?>">
<head>
    <meta charset="utf-8" />
    <title><?= htmlentities($view->getTitle()) ?></title>
</head>

<body>
    <?php ($view)(); ?>
</body>
</html>
        <?php
    }
}

and CarView could be implemented like:

views/CarView.php:

<?php
class CarView implements View {
    private CarEntity $car;

    public function __construct(CarEntity $car) {
        $this->car = $car;
    }

    public function getTitle(): string {
        return $this->car->model;
    }

    // __invoke(): for embracing the "Single Responsibility" principle
    public function __invoke(): void {
?>

<h1><?= htmlspecialchars($this->car->model) ?></h1>
Year: <?= htmlspecialchars($this->car->year) ?>
Price: <?= htmlspecialchars($this->car->price) ?>
<?php
    }
}

In turns, the controller would use it like this:

htdocs/car.php:

<?php
$carService = new CarService(require "config/database.php");

(new LayoutView("en"))(
    new CarView($carService->getById($_GET["id"]))
);

Conclusion

This is far from being production-ready code, as other aspects aren’t addressed by those examples: dependency injection/inversion of control (IoC), input filtering, class autoloading, namespaces,… The goal of this answer is to focus as much as possible on the main aspect of MVC.

This is very much in the same spirit as Rasmus Lerdorf mentioned on: https://toys.lerdorf.com/the-no-framework-php-mvc-framework.

One should not forget that MVC remains a pattern. Software Patterns are reusable principles to solve common problems, if they would be reusable code, they would have been named “libraries” instead.

Frameworks like Zend Framework, Symfony, Laravel, CakePHP and the likes proposes a structure to adopt an MVC approach but can’t enforce it, MVC, as a special case of Separation of concerns needs to be learned and understood to be achieved.

Answer:

I think generally using one of the common frameworks is probably the way to go. The reason is that many good developers have spent a long time writing, bug-fixing, tweaking and polishing to create something solid for basing your site on. The best thing to do is to find one you like, learn it and stick with it (unless you find a reason not to). When I work with PHP, my choice is generally Zend Framework, but there are also CodeIgniter, Symfony, CakePHP and a bunch of others.

If you still want to use the MVC pattern without an existing framework, you either have the choice of putting your own together or just logically separating each concern out from each other – this is the core tenet of MVC, the frameworks just help you achieve it.

Rasmus Lerdorf wrote about his minimal approach to the MVC pattern in PHP in 2006. Might be worth a read. You may also be interested in a mini-framework such as F3::PHP (PHP 5.3+ only) – looks pretty promising.

Answer:

You can check the PHP MVC Tutorial to find out how to use simple MVC pattern from scratch, not in an existing framework.

Answer:

It’s not. Core PHP is a “start in global namespace statement and expression oriented language”. You need extra code (and an optional URL Rewriter) to implement any kind of MVC architecture. That extra code is your framework.

Answer:

This is how you can use MVC in php without any framework

Answer:

To achieve a MVC pattern you just have to separate your data persistence code (“model”, mostly database stuff), the main application logic (“controller”) and your presentation to the outside world (“view”, like HTML pages or RSS feeds).

IF you just don’t mix these three parts in your code, you already have a really basic MVC architecture. Just build distinct classes for your model, view, and controller layers, come up with a well structured way how they talk to each other and then stick to it!

For the sake of code maintainability you should ALWAYS try to work that way.

Answer:

Try integrating Pear DB Layer, Smarty, PHP GACL in your core code to achieve an MVC architecture.

Answer:

By writing your own MVC framework that fallows MVC pattern and OOP principles 🙂

  1. You need to have Front Controller so every HTTP Request goes through one file, index.php, app.php or what ever you want. This way you can configure application in one place.

  2. From there you need Routing mechanism that will analyze HTTP Request, current URL, HTTP Header verb / method, and based on that you will invoke appropriate Controller Method / Action Controller.

  3. From Controller, you can access your Models that will deal with “heavy lifting”, deal with database and domain / business logic etc. And from Controller you can render Views.

So you need at least Front Controller, Router / Dispatcher, Controller, Models and Views to have simple MVC arhitecture.

You would do that joust as other MVC web frameworks do, with slight variations depending on your preferences.

Take a look at some simple frameworks like Codeigniter, and read their source code to get idea how they are doing MVC.

And have fun building your MVC! Its all about the fun after all 😀