steevedroz / ci4-base
Provides a very useful set of components to inherit from
Requires
- php: >=7.4
- codeigniter4/framework: ^4.0
Requires (Dev)
- codeigniter/coding-standard: ^1.8
- phpunit/phpunit: ^11.4.1
- squizlabs/php_codesniffer: ^3.6
Suggests
- steevedroz/ci4-auth: Allows memorizing a connected user in the session
- steevedroz/ci4-flash: Works well with ci4-base by displaying flash messages in the template
- steevedroz/ci4-slug: Allows the use of slugs in URIs
- steevedroz/ci4-uploads: Allows fetching files in WRITEPATH/uploads with ease
README
This library offers a very easy way to set up the base of a CodeIgniter project.
Installation
In order to install this package, call composer require steevedroz/ci4-base
from your CodeIgniter root folder.
You must then run composer update
from your repository.
Set up
Automatic script
By running vendor/bin/ci4-generate
, the files template.html
and BaseController.php
described lower will be generated automatically.
Minimal configuration
The base controller requires a minimal configuration in order to work as intended.
First, you must create a template file at the location app/Views/template.html
. The content of this file will be described hereafter.
Then, you should add a new property Config\App::siteName
by editing app/Config/App.php
like this:
<?php namespace Config;
use CodeIgniter\Config\BaseConfig;
class App extends BaseConfig
{
public $siteName = '<your site name>';
// the rest of the class
}
Folders should be created to contain CSS and JavaScript, they are namely: public/css
and public/js
. All .css and .js files must be placed in thoses files.
No further set up is required.
Content of template.html
The template file must contain a valid HTML, including a doctype and the standard <html>
basic canvas, as specified by the W3C.
In this file, a few placeholders can be put:
{template_page_title}
will display the page title.Config\App::siteName
will be used there and must therefore be created if you choose to use that placeholder.{template_css}
will display all CSS<link>
code that you need. This should be placed in the<head>
section of the HTML page.{template_js}
will do the same with JavaScript<script>
code. This should be placed in the<head>
section of the HTML page.{template_content}
will include the part of the page that is different on each call.
Exemple template.html
file could look like this:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>{template_page_title}</title>
{template_css}
{template_js}
</head>
<body>
<header></header>
<main>{template_content}</main>
<footer></footer>
</body>
</html>
BaseController
In order to use the base controller, first make a controller that extends SteeveDroz\CiBase\BaseController
. Then, this controller has several new options described below.
Display the page
The very basic use of the BaseController
is the following:
- Create an HTML page with a name corresponding to the controller method. For example, for the method
User::show
, create the fileapp/Views/user/show.html
. In there, only put the fragment of page that is supposed to be inserted in the template. - From the controller, call
$this->render();
to display the template file, with the given fragment page.
Example:
<!-- app/Views/user/show.html -->
<h1>User page</h1>
<p>Welcome on the user page!</p>
<?php namespace App\Controllers;
use SteeveDroz\CiBase\BaseController;
class User extends BaseController
{
public function show()
{
$this->render();
}
}
Specific template
You can specify a different template page by calling $this->setTemplate('some-template.html')
from the current controller or from the init()
in BaseController
.
Specific page
Instead of creating a page with a matching name, it is possible to create any page in app/Views
and specify its name as a parameter: $this->render('some-page.html');
. The .html
can be ommited.
Inserting data
The BaseController
library uses CodeIgniter4 parser to display pages. In order to use it, you can insert data in 2 steps:
- Add the desired placeholder in your page fragment (for instance, in
app/Views/user/show.html
). This placeholder must be placed in braces (for example:{username}
). - In the controller, set the value of the placeholder with the
data
property like this:$this->data['username'] = 'john-doe';
.
If the data is an array, the braces placeholder can be replaced by opening and closing braces, as described in the CodeIgniter user guide.
Raw data
In order to insert raw data (i.e. data with HTML that should be interpreted instead of escaped), you can set use $this->rawData
instead of $this->data
from the controller.
Example: $this->rawData['description'] = 'This is the <em>best</em> description!';
NOTE: this must be used with caution and never with user content! It could be the source of major security holes in your code.
Adding CSS
For this to work, {template_css}
must be placed in the <head>
tag of app/Views/template.html
.
From the controller, you can call the $this->css()
method and specify the file you want to include and optionnally the media type.
These options are all compatible:
- The
.css
extension can be ommited:$this->css('style')
or$this->css('style.css')
. - The resource can be local (relative to
public/css
) or remote (starting withhttp(s)://
). - The second parameter is the media type of the spritesheet (
screen
,print
,speech
, etc.). By default, the value isall
.
Adding JavaScript
For this to work, {template_js}
must be placed in the <head>
tag of app/Views/template.html
.
From the controller, you can call the $this->js()
method and specify the file you want to include and optionnally if the script bust be called before the DOM is ready.
These options are all compatible:
- The
.js
extension can be ommited:$this->js('script')
or$this->js('script.js')
. - The resource can be local (relative to
public/js
) or remote (starting withhttp(s)://
). - The second parameter (facultative) is if the resource must be loaded after the DOM is ready (
true
by default). - The third parameter (facultative) is an array containing additional parameters, for example
['integrity' => 'sha256-yadaYadaYadaSha256IntegrityHash=', 'crossorigin' => 'anonymous']
.
Example controller
<?php namespace App\Controllers;
use SteeveDroz\CiBase\BaseController;
class Article extends BaseController
{
public function index()
{
// Set page title
$this->data['page_title'] = 'Articles';
// Set a normal placeholder
$this->data['articles'] = $someModel->findAll();
// Set a raw placeholder
$this->rawData['hint'] = 'Press the <strong>?</strong> icon for help';
// Set CSS files
$this->css('menu'); // without .css
$this->css('table.css'); // with .css
$this->css('pages', 'print'); // with media type
$this->css('https://example.com/layout.min.css'); // remote location
// Set JS files
$this->js('script'); //without .js
$this->js('game.js'); // with .js (both work)
$this->js('User', false); //without defer
$this->js('https://code.jquery.com/jquery-3.5.1.min.js', false, ['integrity' => 'sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=', 'crossorigin' => 'anonymous']); // remote location
// Display a page with the same name as the current controller
// (app/Views/article/index.html)
$this->render();
// ALTERNATIVELY, display a specific page
// (app/Views/example.html)
$this->render('example');
}
}
Note about Auto Routing Improved (since CodeIgniter 4.2.0)
Since the version 4.2.0, it is no longer possible to auto-route methods such as User::login
. Instead, one must define User::getLogin
and User::postLogin
to access it either in GET
or POST
.
ci4-base 1.5.0 detects the name of such methods and can link to views having the same name without the prefix.
Exemple:
class User extends BaseController
{
public function getLogin()
{
// code
$this->render();
}
public function postLogin()
{
// code
$this->render();
}
}
Both methods display the content of app/Views/user/login.html
.
Warning: only the methods
GET
andPOST
work this way, as this library isn't meant to be used to deal withPUT
orDELETE
requests.
BaseModel
The base model est way more minimal, although the options provided will save you a lot of time.
To use it, simply make your model extends SteeveDroz\CiBase\BaseModel
.
Working with events
When working with CodeIgniter Model events, it can rapidly get a bit confusing about what is the content of afterFind
parameters. By working with the applyOnFind()
method, the base model will detect if you are working with one or many entries and perform the desired operation accordingly.
In order to harness the power of this method, one must first use the afterFind
event.
The method takes two arguments: the $data
attribute and a callback to apply to each entry.
The callback takes one parameter reprensenting a single element. If the data are retrieved from the database with find()
or first()
, the callback will be applied to the found entry. If they retrieved with findAll()
, it will be applied to each found entries individually.
Example model
<?php namespace App\Models;
use SteeveDroz\CiBase\BaseModel;
class User extends BaseModel {
protected $table = 'users';
protected $allowedFileds = ['first_name', 'last_name', 'email'];
protected $afterFind = ['addFullName'];
/* Adds a `full_name` field to each user.
* [
* 'first_name' => 'John',
* 'last_name' => 'Doe',
* 'email' => 'john.doe@example.com'
* ]
*
* becomes
*
* [
* 'first_name' => 'John',
* 'last_name' => 'Doe',
* 'email' => 'john.doe@example.com',
* 'full_name' => 'John Doe'
* ]
*/
public function addFullName($data)
{
return $this->applyOnFind($data, function($user)
{
$user['full_name'] = $user['first_name'].' '.$user['last_name'];
return $user;
});
}
}
// ---
$user = $model->find(1); // $user will have a `full_name`
$user = $model->where('email', 'contact@example.com')->first(); // $user will have a `full_name`
$users = $model->findAll(); // each user in $users will have a `full_name`
Contribute
Contributions in the form of issues or merge request are more than welcome!
If you are new to programming, to CodeIgniter 4, or feel unsure about your aptitude to take part in this project, please consider contributing anyway! As a CS teacher, I am willing to take a look at your code and help you improve it. Seriously, I mean it! After all, it's Git, you can't break anything…