Documentation

Requirements

EasyMVC has been tested on Apache2 and Microsft's IIS.

Because EasyMVC uses clean URLs, the server has to be able to use .htaccess files. So make sure mod_rewrite is enabled. If you always want to use HTTPS for your website, you need to edit the .htaccess file in the root folder. The editing instructions have been added to the file.

The web.config file that is provided for IIS servers will always redirect the requests to HTTPS.

If you want to use Nginx, you need to add the following directive to your site's configuration:

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

This will direct all request to index.php.

EasyMVC is written in the latest standard of PHP. Because of this, PHP version 7.1.3 or later has to be installed on the server.

Make sure that the following PHP extensions are also installed on the server:

  • PDO
  • Mbstring
  • JSON
  • XML
  • Ctype

Installing EasyMVC

EasyMVC uses Composer and NPM to maintain all its packages. So, before you try to install it, test your system first to see if Composer and NPM are installed. You can do this by typing 'composer --version' and 'npm -v' in powershell.

Composer can be downloaded here..
For installing NPM, you need to download Node.js. I always use 'Node.js 10'. You can download it here.

When you are sure that both Composer and NPM are installed on your system, you can install a new project with following command:

composer create-project easymvc/easymvc <project name>

This will create a new folder which will contain the EasyMVC framework. You should find following folders and files in it:

<project name>
config
.htaccess
config.sample.php
database.sample.php
emvc_router.php
router.php
server.php
version.php
db-backup
.htaccess
m
.htaccess
<Mobile App Files>
node_modules
<Packages installed by NPM>
private
language
.gitkeep
latte
.gitkeep
public
css
emvc.css
emvc_filetree.css
img
.gitkeep
js
.gitkeep
src
Controllers
emvchelp
EmvcHelpController.php
version
VersionController.php
Helpers
.gitkeep
Models
emvchelp
EmvcHelpUser.php
Repositories
emvchelp
EmvcHelpUserRepository.php
Views
version
version.twig
base.twig
.htaccess
Tests
.htaccess
vendor
<Packages installed by Composer>
.gitignore
.htaccess
composer.json
composer.lock
index.php
LICENSE
package.json
package-lock.json
README.md
web.config
<project name>
config
.htaccess
config.sample.php
database.sample.php
emvc_router.php
router.php
server.php
version.php
db-backup
.htaccess
m
.htaccess
<Mobile App Files>
node_modules
<Packages installed by NPM>
private
language
.gitkeep
latte
.gitkeep
public
css
emvc.css
emvc_filetree.css
img
.gitkeep
js
.gitkeep
src
Controllers
emvchelp
EmvcHelpController.php
version
VersionController.php
Helpers
.gitkeep
Models
emvchelp
EmvcHelpUser.php
Repositories
emvchelp
EmvcHelpUserRepository.php
Views
version
version.twig
base.twig
.htaccess
Tests
.htaccess
vendor
<Packages installed by Composer>
.gitignore
.htaccess
composer.json
composer.lock
index.php
LICENSE
package.json
package-lock.json
README.md
web.config
General Files

All the .htaccess files in the subfolders of the project are there to protect those folders from being accessed through the browser. The only exception to this, is the .htaccess file in the folder 'm' (Mobile Folder).

All .gitkeep files are needed for GitHub. Without these files, the folders wouldn't be added to the repository and wouldn't be created at the initialisation of a new project.

'config'-folder

This folder holds all the configuration-files for the framework

config.sample.php

This is the sample file of the configuration-file for the Core module.

Copy this file to 'config.php' and/or 'config.local.php'.

The local file will be used on the test-server, the other one on the production-server.

The file is self-explanatory!

'config.php' and 'config.local.php' won't be uploaded to GitHub!

database.sample.php

This is the sample file of the database-file.

Copy this file to 'database.php' and/or 'database.local.php'.

The local file will be used on the test-server, the other one on the production-server.

The file is self-explanatory!

'database.php' and 'database.local.php' won't be uploaded to GitHub!

emvc_router.php

This file contains the routing information for the build-in help pages.

The only page available at the moment is the /version page.
The extra documentation will be added at a later stage!

router.php

This file contains the routing information of the website.

More information about the content of this file can be found here.

server.php

This file contains the configuration of your development and production servers.

These settings are needed by the framework to determine which config and database file it needs to load.

version.php

With this file, you can keep track of the versions of the website. The version-page also uses this information.

VERSION_ALPHA → Version of the website in the Alpha repository.

VERSION_BETA → Version of the website in the Beta repository & on the test server.

VERSION → Version of the website in the master repository & on the production server.

This is how I work with EasyMVC. It's only a suggestion but nothing more!

'db-backup'-folder

For the time being, this folder isn't used yet by the framework. It's a module I have on my ToDo list for the framework. I'm planning to story backup files of the database in this folder, but for now; it can be used for to store your own manually created database backup files.

'm'-folder

This folder is for storing the Single-Page Application (Angular, REACT, ...). When the mobile device detection is activated in the configuration (config.php), the framework will use the mobile app it finds in this folder.

The .htaccess file inside this folder is needed to override the one inside the root folder of the website. Never delete this file, or your mobile app won't work!

'node_modules'-folder

This folder holds all packages that are being loaded by NPM.

Initially, it will have the latest version of 'Bootstrap 4', 'jQuery 3' and 'Popper.js 1' installed in it.

'private'-folder

In this folder, you can place documents and other files that can't be accessed directly. The only way to serve these documents are through the website.

As an example, there are two folders already created.

The 'language'-folder can be used to store the language-files for the website in. This can be used for providing a multi-lingual website, and if you don't want to store all text in your database.

The 'latte'-folder can hold the template-files for the Latte package. Latte has many uses, but I mostly use it for the my e-mail plug-in. Extra information can be found here.

'public'-folder

This folder will hold all files for which public access is needed, like images, CSS- and JavaScript-files.

Make sure you never add any files to this folder and its subfolders that contain passwords or any other internal documents that aren't allowed to be shared with the outside world.

  • 'css'-folder
    emvc.css This css-file contains a few quick css styles that you can apply to HTML-elements. More information can be found here.
    emvc_filetree.css This css-file contains the css for creating the above folder structure. More information can be found here.
'src'-folder

This folder is used to hold all the code for your project. At the creation of a new project, five folders are created in which you can store specific classes of code.

These are the folders to hold 'Controllers', 'Helpers', 'Models', 'Repositories' and 'Views'. This doesn't mean that other folders can't be created, but if new folders are created, don't forget to add those to the 'composer.json'-file in the 'autoload' part, and then you need to run 'composer update' or 'composer dump-autoload -o'. With the first command, you will also update the installed packages, with the last one, only update the autoload files which are needed by PHP to find all classed during runtime.

Most of these folders are self-explanatory, only the 'Helpers'-folder can be puzzling. The way how I write code, is that I try to avoid putting a lot of code in my controllers. For me, controllers need to gather data and provide this to some kind of output. (Mostly rendering to a view.)

All the logic, I put in separate classes, and those go into the 'Helpers'-folder. This way, code can easily be reused by multiple controllers. However, this is just a suggestion and not a rule.

  • Pre-installed files
    Controllers/emvchelp/EmvcHelpController.php
    Models/emvchelp/EmvcHelpDummyData.php
    Repositories/emvchelp/EmvcHelpDummyDataRepository.php
    These files provide the quick help tutorial that you can use by surfing to <your url>/help. It will provide an overview of all the pre-made classes for EasyMVC that you can use.
    If not needed, you can just delete these files.
    Controllers/version/VersionController.php
    Views/version/version.twig
    These files provide you with the version page of your website. You can reach it by surfing to <>your url>/version.
    While these files can also be deleted, I would encourage you to keep them. It's a nice way to keep track of what version of the website is online at the moment and on which version you are working on. I often make this page public for my visitors, because I know how much they love to see the numbers go up. And it's also a good way to keep track of which version of the framework you have installed and which Core version you are using. This can be helpful when you need to report a problem with me.
    Views/base.twig This file is very important, because with this file, you will build all your other views. It holds some logic that is needed within the framework to work.
    It contains some logic where other parts within the framework relay on.
    Editing the meta tags won't be a problem, as well as removing some of the script- or link-tags. (Although, keep in mind, I develop some EasyMVC modules that depend on those jQuery and Bootstrap libraries.)
    At the top of this page, you will find a version number. If I change this file, a new version of this file will be available on the website.
    So, if you change this file, you will need to download the new version, then add your changes to it, before you can use it in your project.
'Tests'-folder

Within this folder, you can place all your test classes.

'vendor'-folder

This folder holds all packages that are being loaded by Composer.

Initially, it will have all the packages installed that EasyMVC needs. Those are mostly the EasyMVC modules and the packages they depend on.

'root'-folder
.htaccess
web.config
These two files are respectively used to provide clean URL functionality for apache2 and IIS.
Initially, the '.htaccess'-file is set to use HTTP or HTTPS. If you want to force the use of HTTPS, you need to edit this file. The 'web.config'-file is made so it will always redirect to HTTPS.
.gitignore This file is used to control which files aren't sent to the GitHub repository.
At the moment, the '.gitignore'-file has been set up for the following configuration:
  • Angular
  • Composer
  • Node
  • PhpStorm (+all)
  • WebStorm (+all)
If you use another IDE, or you want other restrictions, a good place to create this file automatically, is at gitignore.io. However, make sure that you never delete the part "EasyMVC specific restrictions" for security reasons. Those four files can hold usernames and passwords which you don't want to fall into unauthorized hands.
composer.json
composer.lock
These two files are used by Composer to install the packages that are needed for your website.
If the 'lock'-file is present, then this file will be used when you issue the command 'composer install'.
Issuing the command 'composer update' will circumvent this and install the newest versions of the packages.
Edit the '.gitignore'-file is you don't want this file to be sent to your GitHub repository.
index.php This is the starting page of all pages viewed on the website. All traffic goes through this file, and I urge you not to alter anything in this file. With every revision within the framework, this file will be updated. (It contains the version numbering.)
If you alter this file, for your website, please do it by including a require_once statement and direct it to the code you want to add. This way, when you update the framework, your code can be attached once more by just including those require_once lines again.
LICENSE Just your standard 'GNU GENERAL PUBLIC LICENSE' document, if you want to publish your own website/application under another license, simply replace this file with yours. (This file will never be included in an update file.)
package.json
package-lock.json
These two files are used by NPM to install the packages that are needed for your website.
If the 'lock'-file is present, then this file will be used when you issue the command 'npm install'.
Issuing the command 'npm update' will circumvent this and install the newest versions of the packages.
Edit the '.gitignore'-file is you don't want this file to be sent to your GitHub repository.
README.md Your typical 'README.md'-file that you can replace with your own version.

The Core module is the glue of the EasyMVC framework. At this point, it is used to load other frequently used modules, which can be activated by editing the config-files. (config.php & config.local.php.)

As soon a module is set active in the configuration file, those modules will be available inside the controllers.

Following modules (classes) are presently available:

DBconnect This is one of my oldest classes that I have been using since I started programming in PHP. It provides the connection between the database and the website. Over the years, it of course has changed. For example, it has gone through the migration from 'mysql' to 'mysqli' and it now uses the PDO class of PHP.
Because of this, it has been rewritten a few times, but this incarnation is in use since 2014. Although, most of the code is written to use it in the old-fashioned way of querying the database, you can also use prepared statements. I urge you to use this, because eventually, the old way will disappear out of my code... probably.
Email This module is used to sent e-mails.
It is dependent on following packages:
'nette/mail': This package does the real heavy lifting and provides a way to send your e-mails.
'latte/latte': With this package, it's easy to create HTML-templates for your e-mails. More information about how to create these templates can be found here.
HttpRequest This module is used to make RESTful API requests.
It is dependent on following package:
'guzzlehttp/guzzle': This is the package; I build my module around.
Login This module is used to provide an easy login system for your website.
It is dependent on following packages:
'rudymas/pdo-ext': To provide the database connection.
'rudymas/manipulator': To generate a random salt for the password security.
Menu This module will provide an easy way to create your website's menu. (Up to 10 levels!)
At this point, it can create two different menus. One is of my own creation, while the other one will produce a Bootstrap 4 navbar.

Configuring the Core module

Initially, all modules are deactivated through the configuration system of the website. By editing the following files, the Core module will now which extra modules to load, and which to ignore.

Because all files contain the necessary information, I will only give a short explanation which files are used for what.

config.php
config.local.php
With these two files you can activate, or deactivate, the modules the Core will use.
database.php
database.local.php
If you activate the database module, you can add your database configuration to these two files. You can set up multiple database connections; however, one of the databases needs to have as objectName 'DBconnect'. This database is always considered as the main database and will be used automatically by other EasyMVC modules.
server.php With this file, you define which URL is used for the test server and which one is the production server. The Core will use this information to load the 'local'-version of a configuration file or not.

The different modules

As said before, the Core module loads the modules you want to use in your website. These modules can then by used inside the Controllers of the website.

You can load these modules by using following code in your controllers:

  •                                                         
    <?php
    class SomeNameController extends Controller
    {
        // Loading Core Classes
        private $DBconnect;
        private $SecondDB;
        private $Email;
        private $HttpRequest;
        private $Login;
        private $Menu;
    
    	public function __construct(array $args)
    	{
    		$Core = $args['Core'];
    		$this->DBconnect = $Core->DB['DBconnect'];
    		$this->SecondDB = $Core->DB['SecondDB'];
    		$this->Email = $Core->Email;
    		$this->HttpRequest = $Core->HttpRequest;
    		$this->Login = $Core->Login;
    		$this->Menu = $Core->Menu;
    	}
    
    	// Rest of the code which uses those modules, or loads them into Helper classes.
    
    }
                                                        

Of course, you only need to provide the code for those modules that you want to use or need in a specific controller.

In the example, two databases are loaded. The DBconnect is the most important one, because this one will be used in many of the other EasyMVC modules.

In practice, it almost never needs to be loaded in a controller, because, in most cases, this database connection will be automatically injected into the Repository or other classes that need it. It's merely when you have a second database, that this one will be loaded through the Controller. For now, the Repositories can only use the DBconnect connection when loaded through the Router. (See Router Module for more information about this.)

In most cases, this module doesn't need to be loaded into the controller when you use the Repository injection option of the router. It's only when you use more than one database, that the second database, and so on, need to be loaded into the controller. So, you can pass the connection to the Repository.

Because of this, the functions from the DBconnect class will be used inside the Repository- or Helper-classes.

For the following examples you can presume that $DBconnect stores the DBconnect class.

DBconnect functions (The old way).
query(string $query)

This function executes a query to the database.

Code example:

  •                                                         
    $query = 'SELECT * FROM user ORDER BY id';
    $DBconnect->query($query);
                                                        

With this, all the users will be retrieved from the database and stored internally in the DBconnect object.

You can retrieve the number of rows affected by '$DBconnect->rows'. (See further for more information.)

If you want to get a certain user, you can use following code:

  •                                                         
    $query = 'SELECT * FROM user WHERE id = ' . $DBconnect->cleanSQL($id);
    $DBconnect->query($query);
                                                        
fetchAll()

This will load the internal data into the publicly available $DBconnect-data variable.

Code example:

  •                                                         
    $DBconnect->fetchAll();
    $name = $DBconnect->data[2]['name'];
    print('name: ' . $name);
                                                        

With this, the internal data is copied to the public data variable, and in the second line, the name of the third user is retrieved.

By using a for loop (in combination with $DBconnect-rows), or with a foreach loop, you could go through the whole dataset and print all the names. (Or add them to a separate array.)

fetchRow(int $id) (previous fetch(int $id)

This function can be used to retrieve a certain row of the internally stored data.

For loading the name of the third user, like in the previous example, following code can be used:

  •                                                         
    $DBconnect->fetchRow(2);
    $name = $DBconnect->data['name'];
    print('name: ' . $name);
                                                        
queryRow(string $query) / Returns a Boolean

This function will perform a query against the database and store the first row in the public data variable. It will also return false if nothing was found, or true when data is present.

If you want to retrieve the third user from the database, you could use following code:

  •                                                         
    $id = 2;
    $query = 'SELECT * FROM user WHERE id = ' . $DBconnect->cleanSQL($id);
    if ($DBconnect->queryRow($query)) {
        $name = $DBconnect->data['name'];
        print('name: ' . $name);
    }
                                                        
queryItem(string $query, string $field) / Returns a String

This function will perform a query against the database and return the value of a certain field.

If you want to retrieve just one field, like in our previous examples, you could even use following code:

  •                                                         
    $id = 2;
    $query = 'SELECT * FROM user WHERE id = ' . $DBconnect->cleanSQL($id);
    $name = $DBconnect->queryItem($query, 'name');
    print('name: ' . $name);}
                                                        
insert(string $query) | update(string $query) | delete(string $query)

These functions can be used for an INSERT, UPDATE or DELETE SQL-query.

These could have been replaced by just one function, but for code clarity, it's good practice to make the function's name state what it is going to do!

lastInsertId($name = null)

This will return the id of the last inserted record into the database.

This can be very useful when you need to know the id when auto increment is active on the table.

cleanSQL(string $content = null) / Returns a String

To prevent SQL-injection from user inputs or manipulations, it is a good practice to use this function before adding the data to the query string.

This will use PDO's quote() function, but in the past, I had written a more complex code to make sure there was no SQL-injection possible, because of this, the cleanSQL() still exists in the DBconnect class.

DBconnect functions (Prepared Statement)

If you are using the prepared statement method, you don't need to learn any new syntax. DBconnect will use the same functions as PHP's PDO class. In this case, the DBconnect class is only used to make the connection with the database.

The code used above, would then look something like this:

  •                                                         
    $id = 2;
    $statement = $DBconnect->prepare('SELECT * FROM user WHERE id = :id');
    $statement->bindValue(':id', $id, \PDO::PARAM_INT);
    $data = $statement->execute();
    $name = $data[0]['name'];
    print('name: ' . $name);}
                                                        

As it is obvious by its name, this module is used to send e-mails.

While it has been written to work within the EasyMVC framework, it can also be used as a standalone package.

At the initialization, the module will be loaded with the EMAIL_FROM address you have set in the config.php file. This can always be overridden by the function 'setFrom(string)'.

Email functions
setup(string $host, string $username, string $password, string $security)

You can use this function to override the settings of the SMTP-server you have set in the 'config.php'-file. This can be useful when you want to sent certain messages through another server.

Parameters

  • $host: Name of your server
  • $username / $password: Your credentials
  • $security: ssl / tls / (empty)
emvc_config()

With this function, you can reset your SMTP-server settings to those you have set in your 'config.php'-file.

setFrom(string $from)

Setting your from-field of the e-mail.

Use '$...->setFrom()' if you want to reset is back to the default e-mail address you have set in your 'config.php'-file.

setTextMessage(array $to, string $subject, string $body, array $attachment, array $cc, array $bcc)

Use this function to prepare a plain text-message to be sent.

Parameters

  • $to: e-mail address of the recipient
  • $subject: Subject of the message
  • $body: The message to be sent
  • $attachment: File(s) you want to attach to the message
  • $cc: e-mail address of the other recipients
  • $bcc: e-mail address of the other recipients (hidden)

Code example:

  •                                                         
    $mail = new Email('from@easymvc.be');
    $text = "Hello,\n\nThis is a test message.\n\nRegards,\nEasyMVC";
    $mail->setTextMessage('to@somewhere.com', 'Test Message', $text);
                                                        
setHtmlMessage(array $to, string $subject, string $body, array $attachment, array $cc, array $bcc)

Use this function to prepare a HTML-message to be sent.

Parameters

  • $to: e-mail address of the recipient
  • $subject: Subject of the message
  • $body: The message to be sent
  • $attachment: File(s) you want to attach to the message
  • $cc: e-mail address of the other recipients
  • $bcc: e-mail address of the other recipients (hidden)

Code example:

  •                                                         
    $mail = new Email('from@easymvc.be');
    $html = "<p>Hello,</p><br><p>This is a test message.</p><br><p>Regards,<br>EasyMVC</p>";
    $mail->setTextMessage('to@somewhere.com', 'Test Message', $html);
                                                        

For more complex HTML-messages, I would suggest to use the Latte engine which is included with this module.

sendMail()

After you have prepared your message, you just need to use this function to sent it.

Depending on previous settings, it will use the SMTP-server you have set up, or else it will use the PHP internal mail() function.

emvcRenderHtml(string $latteFile, array $data) / Returns a string

With this function, you can create HTML-message by using the Latte template engine.

Parameters

  • $latteFile: The name of the template-file to use
  • $data: The data you want to use inside the latte file

The Latte template-files need to be stored inside the folder /private/latte.

For more information about Latte, check out latte.nette.org

This module is used to sent HttpRequests to APIs. It uses Guzzle, a famous PHP HTTP client library for which this module is a wrapper to make it easier to use it with EasyMVC.

HttpRequest functions
setBaseUel(string $baseUrl)

With this function, you can set a url's base address.

For example: $HttpRequest->setBaseUrl('http://api.website.be');

If you now want to do some request, you can use as url by those requests: '/api/users'.

This will translate to 'http://api.website.be/api/users'.

This is the preferred way of doing things, because if the url should change, you only have to edit one line in your code and not all lines where you do a HTTP-request.

getBaseUrl() / Returns a string

If you should need to url somewhere else in you code, you can retrieve it by this function.

Again, this will make it easier when the website's address would change.

get(string $url, string $username, string $password) / Returns a Response-object

With this you can sent a GET-request.

Parameters

  • $url: The url of the API
  • $username: The username to use with a secure API (optional)
  • $password: The password to use with a secure API (optional)

These days, most of the time the response will be a JSON-string. You can retrieve this with: $response->getBody().

Other useful options are:

  • ->getHeaders(): This will retrieve an array of all header information.
  • ->getHeader('Content-Type'): This will retrieve the value of the header's Content-Type
  • ->getStatusCode(): If everything went alright, it should have the value '200'
  • ->getReasonPhrase(): For status code 200, it returns 'OK'
  • ->getProtocolVersion(): The version of the protocol used, most cases this will be '1.1'

These can also be used on the other HTTP-requests.

post(string $url, string $body, string $username, string $password, string $contentType) / Returns a Response-object
put(string $url, string $body, string $username, string $password, string $contentType) / Returns a Response-object
patch(string $url, string $body, string $username, string $password, string $contentType) / Returns a Response-object

These functions look mostly the same for these three. It is, because all of them is to sent data to the API. Although, there are little differences!

A POST is used to send a new record to the API. If everything went right, the API's response should be '201' and in the body a reference for the resource location.

A PUT is used to update an existing record, and should include all fields for the record. The response should be '200'.

A PATCH is used to update an existing record, but only the fields that need to be updated are included. The response should be '200'.

Extra parameter

  • $contentType: In most cases, you don't need to set this parameter. Its default value is 'application/json', which is used in most API calls these days. It's only here for the rare occasion that the API expects something else.
delete(string $url, string $username, string $password) / Returns a Response-object

This function is used to request the deletion of a record. No body is sent with this HTTP-requests!

The API normally will respond with a '200' (OK), but some APIs can also respond with a '202' (Accepted) or '204' (No Content). This is something that needs to be checked, or you could include all three options as a successful deletion of the record.


These are the HTTP-requests included in this module. If needed, other options can be added, but for now, these were all the requests I ever needed.

With this module, it's easy to implement a simple but secure authorization system for the website.

While the password is already salted by PHP itself, this module will add an extra salt-string to the password for increased security.

Preparing your database

The first thing you need to do, is to create the emvc_users table inside your database. This is the hard coded table that EasyMVC uses for the Login Module.

The easiest way to do this, is to run following SQL-queries with your preferred SQL-client. (This script was made with phpMyAdmin.)

  •                                                         
    SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
    SET AUTOCOMMIT = 0;
    START TRANSACTION;
    SET time_zone = "+00:00";
    CREATE TABLE `emvc_users` (
      `id` int(11) NOT NULL,
      `username` varchar(40) NOT NULL,
      `email` varchar(70) NOT NULL,
      `password` varchar(255) NOT NULL,
      `salt` varchar(32) NOT NULL,
      `remember_me` varchar(40) NOT NULL,
      `remember_me_ip` varchar(45) NOT NULL,
      `access_level` int(2) NOT NULL
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    ALTER TABLE `emvc_users`
      ADD PRIMARY KEY (`id`),
      ADD UNIQUE KEY `username` (`username`),
      ADD UNIQUE KEY `email` (`email`);
    ALTER TABLE `emvc_users`
      MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;
    COMMIT;
                                                        

!! Don't forget to mention to your visitors that the login system of your website will register their IP-address. This is needed for extra security, but the GDPR demands that you inform your visitors about this !!

Login functions
Getters & Setters

To access the user's data, you can use following getters:

  • getId()
  • getUsername()
  • getEmail()
  • getIP()
    • Will return the current IP-address of the user
  • getData(string $key)
    • This getter is used to access extra fields that have been added to the table. However, the fields 'password', 'sald' and 'remember_me' can't be accessed with this.

To change any of the user's information use following setters:

  • setUsername(string $username)
  • setEmail(string $email)
  • setPassword(string $password)
    • You only need this one to set the password for a new user! If you want to change the password of an existing user, use the function updatePassword(...)
  • setData(string $key, mixed $value)
    • Again, this one is used to set the extra fields that have been added to the table. The 'password'-, 'salt'- and 'remember_me'-field can't be changed.
insertUser() / Returns a Boolean

This function will create a new user inside the emvc_users table and then sign in the user.

However, before you can use this function, you need to use all the setters to register the user's information.

The function will return 'true' if the account is created, and 'false' when something went wrong.

With $Login->errorCode you can check what went wrong.
If it returns '9', the username/email already exists.
If it returns '2', the account was created but the user couldn't be logged in.

loginUser(string $userLogin, string $password, bool $remember) / Returns a Boolean

To log in a user which already has an account.

Parameters

  • $userLogin: username or e-mail depending on which log in is used
  • $password: password that was provided at the log in
  • $remember: If the user has to be remembered so he doesn't need to give his credentials at his next visit (Default = false)

Returns 'true' when successful, 'false' when credentials didn't match.

logoutUser(bool $cookie)

With this function the user is logged out of the system.

If $cookie is set to 'true', the user needs to provide his credentials the next time he visits the website.

checkUser() / Returns a Boolean

This function can be used to check if the user is logged in the system.

Returns 'true' if everything checks out, 'false' when something is wrong.

At the same time, the user data is loaded and can be accessed.

By adding a 'level'-field to the table, you could check the access level of the user and grant him access to a certain page or not.

updateUser(string $user) / Returns a Boolean

With this function the data of a user can be updated.

If you use $Login->updateUser(); the data of the logged in user is updated.

If you use $Login->updateUser('username'); the data of the user 'username' is updated.

Be careful when you update the data of another user!

Don't forget to update the user data with the setters before using this function.

Returns 'false' when the user to be updated can't be determined, 'true' when the user has been updated.

updatePassword(string $oldPassword, string $newPassword) / Returns a Boolean

This function will update the password of the user that is logged in.

It returns 'false' if the old password isn't right, 'true' when the update has been done.

resetPassword(string $login) / Returns a String or Boolean

Use this function to reset the password of a user. $login is the username or e-mail of the account.

Returns 'false' when the user couldn't be found, returns a random text which is needed by the next function.

createNewPassword(string $remember_me, string $password)

This function will set the new password for a certain user.

$remember_me is the random text from the previous function.

$password is the new password the user has provided.

While the Core module is the glue that binds everything together, the Router module is the heart of the framework.

Every request that the webserver receives will be handled by the router and depending on the setup of the routing table, created inside the 'router.php'-file, it will load external Classes, Repositories and then redirect the requests to the corresponding Controllers and its Functions. Only when mobile detection is active, it will relinquish control to the router of the mobile app when the use of a smarthphone and/or tablet is detected. This app may be written in Angular, REACT or any other application that is installed in the mobile directory.

The Router Module doesn't load any configuration files, this is provided by EasyMVC itself. Because of this, the configuration file is loaded in the framework's index.php. If you create a separate router-file, then don't load it inside the index.php file, but just do it like I did for emvc_router.php and use a require_once('...'); inside the 'router.php'-file. (This way, you can be ensured that your router-file isn't going to be overwritten when you install a newer version of the framework. However, don't forget to re-add your require_once statement.)

Configuring the Router

For starters, take a look at the 'router.php'-file, it already has all the information you need in it.

Configuring the router is rather easy, the only function you need to call is $Router->addRoute(...); to configure your routes. Keep in mind that the Router goes through them from top to bottom and the first instance that matches the URL will be executed.

At the moment, the Router has no internal detection if a variable is an integer or a string. For the Router, the next two rules are the same:

Code example:

  •                                         
    $Router->addRoute('GET', '/show/user/{id}', 'Fake:showId');
    $Router->addRoute('GET', '/show/user/{name}', 'Fake:showName');
                                        

If you now would use following urls in your browser. Presuming the controller would just output the variable, you would get:

  •                                         
    http://example.org/show/user/15
    output:
    ID = 15
    
    http://example.org/show/user/Nico
    output:
    ID = Nico
                                        

The Router sees both as an input of a variable for the 3 parameter, and as such, it will execute both time the first route.

To produce the right output, the routes should be changed to:

  •                                         
    $Router->addRoute('GET', '/show/user/id/{id}', 'Fake:showId');
    $Router->addRoute('GET', '/show/user/name/{name}', 'Fake:showName');
                                        

And this will produce:

  •                                         
    http://example.org/show/user/id/15
    output:
    ID = 15
    
    http://example.org/show/user/name/Nico
    output:
    Name = Nico
                                        

At the moment, there are no plans to add variable type detection to the Router. Although, if future versions of the Router would include it, the old routes will still be valid to use.

Router functions
addRouter(string $method, string $route, string $action, array $args, array $repositories, string $device) / Returns a Boolean

As mentioned before, this is the function to use to set the routes for the router. And remember, the Router executes them top-down.

Parameters

  • $method: The HTTP-request method to respond to. (GET, POST, PUT, ...)
  • $route: The route to respond to
        → '/main/{version}'
    • /main: The route to follow.
    • /{version}: Will add the value into the variable $var['version']
  • $action: The controller and/or function to call
        → 'Main:index'
    • Controller MainController() will be loaded
    • Function indexAction() will be executed
  • Following parameters are optional:
  • $args: A collection of variables or objects that you want to load
        → ['website' => 'http://someWebsite.org/', 'SomeClass' => new SomeClass()]
    • This will be sent to the controller and can be loaded by using:
      function __contructor(array $args);
      • $args['website'] will hold the value 'http://someWebiste.org/'
      • $args['SomeClass'] will hold the class SomeClass()
  • $repositories: A collection of repositories that you want to load
        → ['User', 'Topic']
    • This will load the 'UserRepository' and 'TopicRepository' into the function of the controller. In our example, this will translate to:
      function indexAction(UserRepository $userRepository, TopicRepository $topicRepository, array $var);
      If this had been a POST request, the function would be:
      function indexAction(UserRepository $userRepository, TopicRepository $topicRepository, array $var, string $body);
      • $userRepository will hold the Repository Class UserRepository in which the Model User can be used
      • $topicRepository will hold the Repository Class TopicRepository in which the Model Topic can be used
      • $var['version'] will hold the value set through the url. (See $route for this.)
      • $body will hold the body of the request. JSON-string in case of a POST for example
  • $device: How the router should handle the request. You have the options:
    • auto: The Router will check if the user is using a mobile device and if so, redirect the call to the Mobile App.
    • web: If this is set, the Router will always use the PHP version of the website.
    • api: Always set this if the request is for an API you have created on your website.
    • mobile: The Router will always redirect to the Mobile App, and supply the route to the App.
  •  
  • With the above information in mind, the complete route to add would look like:
  • $Router->addRoute('GET', '/main/{version}', 'Main:index', ['website' => 'http://someWebsite.org/', 'SomeClass' => new SomeClass()], ['User', 'Topic'], 'web');
  •  
  • The $action parameter could also be set to 'Main'. In this case, the MainController will be loaded but no function will be executed. In this case, the constructor would look like:
  • function __constructor(array $arg, array $var, string $body);
  • As you can see, if you don't provide a function (action) to execute, the Repositories won't be loaded and you will need to load them yourself inside the constructor.
setDefault(string $page)

This function is used to set the default route of the website. Default route is '/'.

In most cases, you don't have to set this because the home-page of a website is often the root, which is '/', of course.

However, if you set it, make sure that you use an existing route, or else you could create an infinite route. (Most browsers stop this at a certain number, but for just a second, you create a little DoS attack on your own server. If many users do this at the same time, you could crash your server! Although, the numbers should be very high to do this.

setMobileDetection(bool $status)

With this, you can enable or disable the mobile detection of the router. (Default = false) ← this means disabled.

setDefaultMobileApp(string $linkMobileApp)

Normally, the router will call the Mobile App by redirecting to http://<your website's url>/m/, if you have installed your mobile app in a different space or even server, you can use this function to redirect to it.

In my case, I use 'http://m.rmsoft.be/' as the url for my Mobile App.

For debugging purposes, following functions are also provided:
getParameters() / Returns an array

This will return the parameters of the clean url used in the browser. This can be helpful if you don't understand why the Router doesn't execute the Controller/Action you specified in your routing table.

getBody()

This will return the body of the request received. Can be useful to see what the server receives from the user. I use it sometimes to check the JSON-string received from the user when doing an API call and something unexpected happens.

The Controller module is always loaded as an extension of the Controllers you create for your project.

At the moment, the only thing this module is doing is rendering the output and sending it to the browser of the user. While this is very important, of course, no extra functionality has been added to it yet. Except for a debugging function that I can quickly check what is in an array or object.

Controller functions
render(string $page, array $data, string $type, int $httpResponseCode, bool $debug)

This function is used to render and send an output page to the browser of the user.

This function is written in such a way, that after rendering, the output is immediately sent to the user. Inside the controller though, you are still able to add and execute extra code afterwards. I needed to do this, because I sometimes send a page to indicate that the server is working on something. If I didn't do it like this, the page wouldn't be received by the user until PHP was done executing all code.

Parameters

  • $page: The template-page to load
  • $data: An array of data to be used by the template.
  • $type: The type of page to render, this can be:
    • HTML: A plain HTML page. With these kind of pages you can't use $data with it.
    • JSON: The $data (array) will be transformed into a JSON-string and sent to the user. $page needs to be set to 'null'.
    • XML The $data (array) will be transformed into XML and sent to the user. $page needs to be set to 'null'.
    • PHP A special PHP class will be loaded to create a HTML-page. (Packagist 'rudymas/html5')
    • TWIG This will use the Twig-engine to render the HTML-page. Check the documentation at Twig
  • $httpResponseCode: The response code that is sent to the user's browser. (Default = 200)
  • $debug: Activate or deactivate debugging mode. (Default = false)

For the $data parameter, when using 'TWIG', there is also a special key you can set. Add following code if you want to enable auto redirect for the page you are going to show:

  •                                         
    $redirect = [
        'sleep' => 5,
        'page' => '/page'
    ];
    
    $this->render('somePage.twig', ['redirect' => $redirect], 'TWIG');
                                        

This will output the page 'somePage.twig' and after 5 seconds redirect you to the route '/page' of the website.

redirect(string $page)

This function can be used to redirect the user to a certain page.

I sometimes use this in a Controller where the Action has to process a form, put the data into the database, and then redirect the user back to a certain page that he was on before needing to fill in a form.

checkArray($array, bool $stop)

This will output an array, object or even just a variable to the screen.

I sometimes use this to quickly check if a variable has the value I think it has while debugging a problem.

If you set the second parameter ($stop) to true, the output will stop after outputting the variable.

The Repository Module has two functions. Firstly, to keep track of the data of its Model, and secondly, to act as the go-between for the database.

This module is loaded as an extension to a Repository used by the project.

Repository functions
add($object)

This function will add an object of its associated Model to the collected data.

For example: The UserRepository is used to collect the User Models.

  •                                         
    $userRepository = new UserRepository();
    $user = new User('Name', 'Email@email.org', '+3211234567');
    $userRepository->add($user);
                                        
getAll() / Returns an array of Models

With this function, you retrieve all records stored in the Repository.

This will return an array of Models (objects).

getByIndex(int $id) / Returns a Model

With this function, you retrieve a certain Model by its index.

This doesn't retrieve the data by the Repository's index, but by the 'id'-key of the Model. This is why every table in the database needs an 'id'-field.

getBy(string $field, string $search) / Returns an array of Models

This function will retrieve all records where a certain field's data equals a certain search string.

For example, $this->getBy('name', 'Williams'), will return an array of Models for which the name-field has the name 'Williams' in it.

clearData()

This will delete all Models present in the Repository.


You can also build an iteration with the following functions:.
hasNext() / Returns a Boolean

Checks if there exists a next object

Returns 'true' if there is a next object, 'false' if not.

hasPrevious() / Returns a Boolean

Checks if there exists a previous object.

Returns 'true' if there is a previous object, 'false' if not.

next() / Returns a Model

This function will go to the next Model and retrieve it.

previous() / Returns a Model

This function will go to the previous Model and retrieve it.

current() / Return a Model

This function will retrieve the current Model.

reset()

Will return the pointer to the first Model.


The Module also contains 2 functions to quickly perform database queries.
loadAllFromTable(string $table, string $model)

This will load all records from the 'table' and use a certain 'model' to import it into the Repository.

  •                                         
    $userRepository = new UserRepository();
    $userRepository->loadAllFromTable('user', 'User');
                                        

The code above will load all records from the 'user'-table in the repository using the Model class User.

loadAllFromTableByQuery(string $model, string $preparedStatement, array $keyBindings = [])

This will use a certain 'model', execute a 'prepared statement' while using the supplied 'binding keys and values'.

  •                                         
    $userRepository = new UserRepository();
    $statement = "SELECT * FROM user WHERE name LIKE :name";
    $bindingKeys = [
    	':name' => 'Williams'
    ];
    $userRepository->loadAllFromTableByQuery('User', $statement, $bindingKeys);
                                        

The code above will retrieve all users with the name 'Williams' from the database and store it in the Repository.

If you want to use these two functions to retrieve data from the database, the Model needs to have a special function 'new' in it.

Look at the following code for the user Model.

  •                                         
    <?php
    namespace Models;
    
    class User
    {
    	private $id;
    	private $name;
    	private $email;
    	private $phone;
    
    	public function __construct(int $id, string $name, string $email, string $phone)
    	{
    		$this->id = $id;
    		$this->name = $name;
    		$this->email = $email;
    		$this->phone = $phone;
    	}
    
    	public static function new(array $data): User
    	{
    		return new User($data['id'], $data['name'], $data['email'], $data['phone']);
    	}
    
    	/* The getters and setters for the Model User class */
    }
                                        

Inside the Repository Module, the data will be retrieved from the database and use a foreach loop to create new User Models and add it to the existing data list.

The UserRepository could look like this:

  •                                         
    <?php
    namespace Repositories;
    
    use EasyMVC\Repository\Repository;
    use Models\User;
    use RudyMas\PDOExt\DBconnect;
    
    class UserRepository extends Repository
    {
    	public function __construct(DBconnect $DBconnect, User $user = null)
    	{
    		parent::__construct($DBconnect, $user);
    	}
    
    	public function loadAllUsers(): void
    	{
    		parent::loadAllFromTable('user', 'User');
    	}
    
    	public function loadUserByName(string $name): void
    	{
    		$sql = 'SELECT * FROM user WHERE name LIKE :name ORDER BY name';
    		parent::loadAllFromTableByQuery('User', $sql, [':name' => $name]);
    	}
    }
                                        

And inside the controller, following code could be used to display all users.

  •                                         
    ...
    public function showUsersAction(UserRepository $userRepository): void
    {
    	$userRepository->loadAllUsers();
    	$users = $userRepository->getAll();
    	$this-render('usersOverview.twig', ['users' => $users], 'TWIG');
    }
    ...