2017 © Pedro Pelรกez
 

library php-mvc

Implementation of the MVC (Model-View-Controller) architectural pattern in PHP.

image

php-mvc-project/php-mvc

Implementation of the MVC (Model-View-Controller) architectural pattern in PHP.

  • Tuesday, May 29, 2018
  • by meet-aleksey
  • Repository
  • 0 Watchers
  • 1 Stars
  • 13 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 1 Forks
  • 3 Open issues
  • 3 Versions
  • 18 % Grown

The README.md

PHP MVC

PHP from Packagist License GitHub release Packagist, (*1)

The best implementation of the Model-View-Controller architectural pattern in PHP!, (*2)

Features

  • Templates
  • Routing
  • Filters
  • Cache
  • Validation
  • Data annotation
  • Security

Requirements

  • PHP 7.x

Installation

$ composer require php-mvc-project/php-mvc

Server Configuration

The server must send the entire request to the ./index.php file., (*3)

Apache

<IfModule mod_rewrite.c>
  RewriteEngine On

  # redirect /index.php to /
  RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /.*index\.php
  RewriteRule ^index.php/?(.*)$ $1 [R=301,L]

  # process all requests through index.php, except for actually existing files
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php/$1?%{QUERY_STRING} [QSA,L]
</IfModule>

nginx

location / {
  try_files $uri $uri/ /index.php?$args;
}

Basic Usage

Create the following structure in the project root directory:, (*4)

.
โ”œโ”€โ”€ controllers           # controllers folder
โ”œโ”€โ”€โ”€ HomeController.php   # class of the home controller
โ”œโ”€โ”€โ”€ *Controller.php      # classes of others controllers
โ”œโ”€โ”€ models                # models folder
โ”œโ”€โ”€ views                 # views folder
โ”œโ”€โ”€โ”€ home                 # views folder of the home controller
โ”œโ”€โ”€โ”€ ...                  # folders for other controllers
โ”œโ”€โ”€โ”€ shared               # shared views
โ””โ”€โ”€ index.php             # index file

./index.php

ignore('content/{*file}');

    // default route
    $routes->add('default', '{controller=Home}/{action=index}/{id?}');
});

// build
AppBuilder::build();
```

> **IMPORTANT**: You must use namespaces in your application.
> Be sure to specify the root namespace of your application using the `AppBuilder::useNamespace(string)` function.

### ./controllers/HomeController.php

```php
content('Hello, world!');

        // create to the ./view/home/index.php
        // and use view function to return this view:
        // return $this->view();
    }

}
```

> **IMPORTANT**: The names of all controller classes must end with the `Controller` suffix.
> For example: `HomeController`, `AccountController`, `TestController` etc.

## Structure

Your projects must implements the strict structure:

```shell
.
โ”œโ”€โ”€ content               # static content (images, css, scripts, etc)
โ”œโ”€โ”€โ”€ ...                  # any files and folders
โ”œโ”€โ”€ controllers           # controllers folder
โ”œโ”€โ”€โ”€ HomeController.php   # class of the home controller
โ”œโ”€โ”€โ”€ *Controller.php      # classes of others controllers
โ”œโ”€โ”€ filters               # filters folder
โ”œโ”€โ”€โ”€ *.php                # classes of models
โ”œโ”€โ”€ models                # models folder
โ”œโ”€โ”€โ”€ *.php                # classes of models
โ”œโ”€โ”€ views                 # views folder
โ”œโ”€โ”€โ”€ ...                  # views for specific controllers
โ”œโ”€โ”€โ”€ shared               # shared views
โ”œโ”€โ”€โ”€ ...                  # common view files that are not associated with specific controllers
โ”œโ”€โ”€ index.php             # index file
โ””โ”€โ”€ ...                   # any of your files and folders
```

And adhere to the following rules:

1. Folder names must be in lowercase.

2. The views filenames must be in lowercase.

3. The file names of the controllers must be specified in the camel style, with a capital letter.
   The names must end with the `Controller` suffix. For example: `HomeController.php`.

## Models

The model is just classes. You can create any classes, with any structure.

It is recommended to adhere to the rule: the simpler, the better.

Using the static class `Model`, you can add metadata to a model in the constructor of the controller.

```php
view($model);
    }

}
```

## Views

The views files contain markup.
Markup can be complete or partial.

Using the `PhpMvc\Html` class, you can create markup for HTML elements or output some views within other views.

For example:

```php

<html>
<head>
  <title>=Html::getTitle('Hello, world!')?></title>
</head>
<body>


Hello, world!

=Html::actionLink('Go to second view', 'second'))?><br /> =Html::textBox('anyname')?><br /> =Html::checkbox('rememberMe')?><br /><br /> </body> </html>

Use the helper class PhpMvc\View to customize the behavior of the view:, (*5)





=isset($model) ? $model->anyProperty : 'empty'?>

Controllers

The controller classes names must match the controllers filenames. For example: file name is TestController.php, class name is TestController., (*6)

Each controller class must inherit from the PhpMvc\Controller class., (*7)

The controller classes must contain action methods., (*8)

The action names must match filenames of views. For example: view file is index.php, action name is index., (*9)

All methods of actions must have the modifier public., (*10)

The names of the action methods must not start with the underscore (_)., (*11)

class HomeController extends PhpMvc\Controller {

  public function index() {
    return $this->view();
  }

  public function hello() {
    return $this->view();
  }

  public function other() {
    return $this->view();
  }

}

Each action can take any number of parameters., (*12)

The parameters can be received from the query string, or from the POST data., (*13)

The following example shows the output of parameters retrieved from the query string:, (*14)

class TestController extends PhpMvc\Controller {

  public function get($search = '', $page = 1, $limit = 10) {
    return $this->content(
      'search: ' . $search . chr(10) .
      'page: ' . $page . chr(10) .
      'limit: ' . $limit
    );
  }

}
Request:
GET /test/get?search=hello&page=123&limit=100

Response:
search: hello
page: 123
limit: 100

Below is an example of obtaining a model sent by the POST method:, (*15)

class AnyNameModelClass {

  public $search;

  public $page;

  public $limit;

}
class TestController extends PhpMvc\Controller {

  public function post($anyName) {
    return $this->content(
      'search: ' . $anyName->search . chr(10) .
      'page: ' . $anyName->page . chr(10) .
      'limit: ' . $anyName->limit
    );
  }

}
Request:
POST /test/post

search=hello&page=123&limit=100

Response:
search: hello
page: 123
limit: 100

Methods of action can return different results, in addition to views., (*16)

You can use the ready-made methods of the base class of the controller to output the data in the required format:, (*17)

  • $this->view([string $viewOrModel = null[, object $model = null[, string $layout = null]]])
  • $this->json(mixed $data[, int $options = 0[, int $depth = 512]])
  • $this->file(string $path[, string $contentType = null[, string|bool $downloadName = null]])
  • $this->content(string $content[, string $contentType = 'text/plain'])
  • $this->statusCode(int $statusCode[, string $statusDescription = null])
  • $this->notFound([string $statusDescription = null])
  • $this->unauthorized([string $statusDescription = null])
  • $this->redirect(string $url)
  • $this->redirectPermanent(string $url)
  • $this->redirectPreserveMethod(string $url)
  • $this->redirectPermanentPreserveMethod(string $url)
  • $this->redirectToAction(string $actionName[, string $controllerName = null[, array $routeValues = null[, string $fragment = null]]])

Instead of the presented methods, you can independently create instances of the desired results and return them:, (*18)

class AnyController extends PhpMvc\Controller {

  public function example() {
    $view = new ViewResult();

    // set the name of an existing view file
    $view->viewFile = '~/view/abc/filename.php';
    // set the title
    $view->title = 'The view is created programmatically';
    // set the layout file name
    $view->layout = 'layout.php';

    // create model for view
    $model = new Example();

    $model->title = 'Hello, world!';
    $model->text = 'The model contains text.';
    $model->number = 42;

    // set model to the view
    $view->model = $model;

    // return view
    return $view;
  }

}

All result classes implement the ActionResult interface. You can create your own result classes!, (*19)

Filters

Filters allow you to add handlers before and after the action. And also handle errors of the action execution., (*20)

The filters must be in the ./Filters folder., (*21)

Each filter must be inherited from the PhpMvc\ActionFilter class., (*22)

Filters can be global, or work at the level of an individual controller, or action., (*23)

Filters for specific controller or action can be set in the controller's constructor:, (*24)

./controllers/TestController.php

class TestController extends Controller {

  public function __construct() {
    // add filter TestFilter to all actions of the controller
    Filter::add('TestFilter');

    // add filter ExceptionToJson to error action
    Filter::add('error', 'ExceptionToJson');
  }

  public function index() {
      return $this->content('Hello, world!');
  }

  public function other() {
      return $this->view('~/views/home/other.php');
  }

  public function anyname() {
      return $this->view();
  }

  public function error() {
      throw new \Exception('Any error here!');
  }

}

./filters/TestFilter.php

<?php
namespace RootNamespaceOfYourApp\Filters;

use PhpMvc\ActionFilter;
use PhpMvc\ContentResult;

class TestFilter extends ActionFilter {

  // action executed handler
  public function actionExecuted($actionExecutedContext) {
    // check exception result
    if (($ex = $actionExecutedContext->getException()) === null) {
      // no exception, replace result
      $actionExecutedContext->setResult(new ContentResult('test'));
    }
    else {
      // set exception error message to result
      $actionExecutedContext->setResult(new ContentResult($ex->getMessage()));
    }
  }

}

./filters/ExceptionToJson.php

<?php
namespace RootNamespaceOfYourApp\Filters;

use PhpMvc\ActionFilter;
use PhpMvc\JsonResult;

class ExceptionToJson extends ActionFilter {

  // error handler
  public function exception($exceptionContext) {
    // set JsonResult to action result
    $exceptionContext->setResult(
      new JsonResult(
        array('message' => $exceptionContext->getException()->getMessage())
      )
    );
    // exception is handled
    $exceptionContext->setExceptionHandled(true);
  }

}

Routing

You can set routing rules using the AppBuilder::routes() function, which expects the function as a parameter. When called, an instance of RouteProvider will be passed to the function., (*25)

The add(string $name, string $template[, array $defaults = null[, array $constraints = null]]) method allows you to add a routing rule., (*26)

The ignore(string $template[, $constraints = null]) method allows you to add an ignore rule., (*27)

AppBuilder::routes(function(RouteProvider $routes) {
  $routes->add('default', '{controller=Home}/{action=index}/{id?}');
});

The names of the routing rules must be unique., (*28)

The higher the rule in the list (the earlier the rule was added), the higher the priority in the search for a match., (*29)

In templates you can use any valid characters in the URL., (*30)

Use curly braces to denote the elements of the route., (*31)

Each element must contain a name., (*32)

A name can point to a controller, action, or any parameter expected by the action method., (*33)

For example, template is: {controller}/{action}/{yyyy}-{mm}-{dd}., (*34)

Action is:, (*35)

public function index($yyyy, $mm, $dd) {
  return $this->content('Date: ' . $yyyy . '-' . $mm . '-' . $dd);
}
Request:
GET /home/index/2018-05-26

Response:
Date: 2018-05-26

After the element name, you can specify a default value in the template. The default value is specified using the equals sign., (*36)

For example: {controller=home}/{action=index} - default controller is HomeController, default action is index(). The default values will be used if the address does not have values for the specified path elements. Simply put, for requests /home/index, /home and / will produce the same result with this template., (*37)

If the path element is optional, then the question (?) symbol is followed by the name. For example: {controller=home}/{action=index}/{id?} - id is optional, {controller=home}/{action=index}/{id} - id is required., (*38)

Route providers must implement the RouteProvider interface. The default is DefaultRouteProvider. If necessary, you can create your own route provider. Use the AppBuilder::useRouter(RouteProvider $routeProvider) method to change the route provider., (*39)

Caching

To use caching, you must call the AppBuilder::useCache(CacheProvider $cacheProvider) method, which should be passed to the cache provider instance., (*40)

The cache provider must implement the CacheProvider interface., (*41)

You can use the ready-made FileCacheProvider, which performs caching in the file system., (*42)

AppBuilder::useCache(new FileCacheProvider());

You can access the cache via an instance of HttpContextBase., (*43)

For example, in the controller:, (*44)

$cache = $this->getHttpContext()->getCache();
$cache->add('test', 'hello, world!');
var_dump($cache->get('test'));

In the view:, (*45)

$cache = View::getHttpContext()->getCache();
$cache->add('test', 'hello, world!');
var_dump($cache->get('test'));

For output caching, you can use the static OutputCache class., (*46)

Caching rules can be specified for both the controller and for an each action., (*47)

Cache rules should be specified in the constructor of the controller., (*48)

<?php
namespace RootNamespaceOfYourApp\Controllers;

use PhpMvc\OutputCache;
use PhpMvc\OutputCacheLocation;
use PhpMvc\Controller;

class OutputCacheController extends Controller {

    public function __construct() {
        // caching for 10 seconds of the results of all actions of this controller
        OutputCache::setDuration('.', 10);

        // caching for 30 seconds of the results of the action of thirty
        OutputCache::setDuration('thirty', 30);
    }

    public function index($time) {
        return $this->content('time => ' . $time);
    }

    public function thirty($time) {
        return $this->content('time => ' . $time);
    }

}

License

The MIT License (MIT), (*49)

Copyright ยฉ 2018, @meet-aleksey, (*50)

The Versions

29/05 2018

dev-master

9999999-dev

Implementation of the MVC (Model-View-Controller) architectural pattern in PHP.

  Sources   Download

MIT

The Requires

  • php >=7.0

 

The Development Requires

mvc

29/05 2018

v1.2.0

1.2.0.0

Implementation of the MVC (Model-View-Controller) architectural pattern in PHP.

  Sources   Download

MIT

The Requires

  • php >=7.0

 

The Development Requires

mvc

29/05 2018

v1.1.1

1.1.1.0

Implementation of the MVC (Model-View-Controller) architectural pattern in PHP.

  Sources   Download

MIT

The Requires

  • php >=7.0

 

The Development Requires

mvc