I am working on a online newspaper/blogging application with CodeIgniter 3.1.8 and Bootstrap 4. I have decided to add themes to it. The application is not HMVC, only MVC.
I thought it was a good idea to use the Twig template engine to the theme(s). For this purpose, I use CodeIgniter Simple and Secure Twig.
The theme's templates, placed in application\views\themes\caminar
(caminar is the current theme's name) have the extension .twig
, not .php
.
The layout.twig file contains the "master layout code":
<!DOCTYPE html>
<html>
<head>
<title>{{site_title}} | {{tagline}}</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="{{maincss}}">
</head>
<body>
<!-- Header -->
<header id="header">
<div class="logo"><a href="/">{{site_title}}</a></div>
</header>
<section id="main">
<div class="inner">
{% if singlePost is defined %}
{{include(singlePost)}}
{% elseif pageTemplate is defined %}
{{include(pageTemplate)}}
{% elseif notFound is defined %}
{{include(notFound)}}
{% else %}
{{ include('themes/caminar/templates/posts.twig') }}
{% endif %}
</div>
</section>
<!-- Footer -->
<footer id="footer">
<div class="container">
<ul class="icons">
<li><a href="{{twitter}}" target="_blank" class="icon fa-twitter"><span class="label">Twitter</span></a></li>
<li><a href="{{facebook}}" target="_blank" class="icon fa-facebook"><span class="label">Facebook</span></a></li>
<li><a href="{{instagram}}" target="_blank" class="icon fa-instagram"><span class="label">Instagram</span></a></li>
<li><a href="mailto:{{company_email}}" class="icon fa-envelope-o"><span class="label">Email</span></a></li>
</ul>
{% if pages %}
<ul class="icons">
{% for page in pages %}
<li><a href="{{base_url}}/pages/page/{{page.id}}">{{page.title}}</a></li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="copyright">
© {{company_name}}. All rights reserved. Design by <a href="https://templated.co" target="_blank">TEMPLATED</a>
</div>
</footer>
</body>
</html>
The posts.twig file displays the posts:
<section class="wrapper style1">
{% for post in posts %}
{% if loop.first %}
<div class="image fit flush">
<a href="{{base_url}}{{post.slug}}">
<img src="{{base_url}}/assets/img/posts/{{post.post_image}}" alt="{{post.title}}" />
</a>
</div>
<header class="special">
<h2>{{post.title}}</h2>
<p>{{post.description}}</p>
</header>
<div class="content">{{post.content|raw}}</div>
{% else %}
<div class="spotlight {% if (loop.index is even) %}alt{% endif %}">
<div class="image flush">
<a href="{{base_url}}{{post.slug}}">
<img src="{{base_url}}/assets/img/posts/{{post.post_image}}" alt="{{post.title}}" />
</a>
</div>
<div class="inner">
<h3>{{post.title}}</h3>
<p>{{post.description}}</p>
<div class="{% if (loop.index is even) %}text-right{% else %}text-left{% endif %}">
<a href="{{base_url}}{{post.slug}}" class="button special small">Read More</a>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</section>
<div class="pagination-container">{{ pagination|raw }}</div>
Finally, the posts controller is the main reason for my concerns regarding the quality of the code:
class Posts extends CI_Controller {
public function __construct()
{
parent::__construct();
}
private function _initPagination($path, $totalRows, $query_string_segment = 'page') {
//load and configure pagination
$this->load->library('pagination');
$config['base_url'] = base_url($path);
$config['query_string_segment'] = $query_string_segment;
$config['enable_query_strings'] =TRUE;
$config['reuse_query_string'] =TRUE;
$config['total_rows'] = $totalRows;
$config['per_page'] = 12;
if (!isset($_GET[$config['query_string_segment']]) || $_GET[$config['query_string_segment']] < 1) {
$_GET[$config['query_string_segment']] = 1;
}
$this->pagination->initialize($config);
$limit = $config['per_page'];
$offset = ($this->input->get($config['query_string_segment']) - 1) * $limit;
return ['limit' => $limit, 'offset' => $offset];
}
public function index() {
//call initialization method
$config = $this->_initPagination("/", $this->Posts_model->get_num_rows());
$data = $this->Static_model->get_static_data();
$data['base_url'] = base_url("/");
$data['pages'] = $this->Pages_model->get_pages();
$data['categories'] = $this->Categories_model->get_categories();
//use limit and offset returned by _initPaginator method
$data['posts'] = $this->Posts_model->get_posts($config['limit'], $config['offset']);
$this->twig->addGlobal('maincss', base_url('themes/caminar/assets/css/main.css'));
$this->twig->addGlobal('pagination', $this->pagination->create_links());
$this->twig->display('themes/caminar/layout', $data);
}
public function byauthor($authorid){
//load and configure pagination
$this->load->library('pagination');
$config['base_url'] = base_url('/posts/byauthor/' . $authorid);
$config['query_string_segment'] = 'page';
$config['total_rows'] = $this->Posts_model->posts_by_author_count($authorid);
$config['per_page'] = 12;
if (!isset($_GET[$config['query_string_segment']]) || $_GET[$config['query_string_segment']] < 1) {
$_GET[$config['query_string_segment']] = 1;
}
$limit = $config['per_page'];
$offset = ($this->input->get($config['query_string_segment']) - 1) * $limit;
$this->pagination->initialize($config);
$data = $this->Static_model->get_static_data();
$data['base_url'] = base_url("/");
$data['pages'] = $this->Pages_model->get_pages();
$data['categories'] = $this->Categories_model->get_categories();
$data['posts'] = $this->Posts_model->get_posts_by_author($authorid, $limit, $offset);
$data['posts_count'] = $this->Posts_model->posts_by_author_count($authorid);
$data['posts_author'] = $this->Posts_model->posts_author($authorid);
$this->twig->addGlobal('maincss', base_url('themes/caminar/assets/css/main.css'));
$this->twig->addGlobal('pagination', $this->pagination->create_links());
$this->twig->display('themes/caminar/layout', $data);
}
public function post($slug) {
$data = $this->Static_model->get_static_data();
$data['pages'] = $this->Pages_model->get_pages();
$data['categories'] = $this->Categories_model->get_categories();
$data['authors'] = $this->Usermodel->getAuthors();
$data['posts'] = $this->Posts_model->sidebar_posts($limit=5, $offset=0);
$data['post'] = $this->Posts_model->get_post($slug);
$data['author_image'] = isset($data['post']->avatar) && $data['post']->avatar !== '' ? $data['post']->avatar : 'default-avatar.png';
//CSS, JS and other resources add to twig here, because PHP and Codeigniter functions are not available from Twig templates
$this->twig->addGlobal('maincss', base_url('themes/caminar/assets/css/main.css'));
if ($data['categories']) {
foreach ($data['categories'] as &$category) {
$category->posts_count = $this->Posts_model->count_posts_in_category($category->id);
}
}
if (!empty($data['post'])) {
// Overwrite the default tagline with the post title
$data['tagline'] = $data['post']->title;
// Get post comments
$post_id = $data['post']->id;
$data['comments'] = $this->Comments_model->get_comments($post_id);
$this->twig->addGlobal('singlePost','themes/caminar/templates/singlepost.twig');
$this->twig->display('themes/caminar/layout', $data);
} else {
$data['tagline'] = "Page not found";
$this->twig->addGlobal('notFound','themes/caminar/templates/404.twig');
$this->twig->display('themes/caminar/layout', $data);
}
}
}
Concerns:
- Is the code (too) repetitive?
- Is the code over engineered?