PHPackages                             piotrpolak/pepiscms - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. piotrpolak/pepiscms

ActiveLibrary[Framework](/categories/framework)

piotrpolak/pepiscms
===================

Content management system

1.0.4(3y ago)5485MITPHPPHP &gt;=5.6.0

Since Dec 30Pushed 1y ago2 watchersCompare

[ Source](https://github.com/piotrpolak/pepiscms)[ Packagist](https://packagist.org/packages/piotrpolak/pepiscms)[ RSS](/packages/piotrpolak-pepiscms/feed)WikiDiscussions master Synced today

READMEChangelog (5)Dependencies (9)Versions (7)Used By (0)

PepisCMS
========

[](#pepiscms)

[![PHP Build](https://github.com/piotrpolak/pepiscms/actions/workflows/on_master.yaml/badge.svg)](https://github.com/piotrpolak/pepiscms/actions/workflows/on_master.yaml)[![Maintainability](https://camo.githubusercontent.com/5a7458566dbeaa7f302aa36fee02e96fc19c14c05f97e881c6887b7b6a8a2bba/68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f36336664333339343665326364333535613536312f6d61696e7461696e6162696c697479)](https://codeclimate.com/github/piotrpolak/pepiscms/maintainability)

PepisCMS is a content management system. Its main feature consists in the [CRUD module generator](#generating-a-crud-module)which makes it easy to set up an entire administration panel based on the database schema definition within minutes. The generated administration panel consists of [modules](#modules) that can be further customized (or just left as they are if you don't care about the presentation details).

The application is designed as a core library on top of the [CodeIgniter framework](https://codeigniter.com/) and it allows to be swapped/upgraded with no, or minimal changes in the project code.

- [Live-demo](#live-demo)
- [Setting up a local development environment](#setting-up-a-local-development-environment)
- [Requirements](#requirements)
- [Features](#features)
- [Installation](#installation)
- [Command line interface](#command-line-interface)
- [Modules](#modules)
- [Generating a CRUD module](#generating-a-crud-module)
- [Built-in utilities](#built-in-utilities)
- [Security policy](#security-policy)
- [Deployment configurations](#deployment-configurations)
- [Simplified domain model](#simplified-domain-model)
- [Architecture overview](#architecture-overview)
- Core libraries:
    - [Generic model](#generic-model)
    - [FormBuilder](#formbuilder-library)
    - [DataGrid](#datagrid-library)
    - [CrudDefinitionBuilder](#cruddefinitionbuilder)
    - [ContainerAware](#containeraware)
- [Application helpers](#application-helpers)
- [Changelog](CHANGELOG.md)
- [Benchmarking](#benchmarking)
- [Naming convention inconsistency](docs/NAMING_CONVENTION_INCONSISTENCY.md)
- [Changes comparing to CodeIgniter](#changes-comparing-to-codeigniter)
- [Enabling library and models autocomplete predictions](#enabling-library-and-models-autocomplete-prediction)
- [Optional Libraries](#optional-libraries)

[![PepisCMS Dashboard](docs/screens/DASHBOARD.png)](docs/screens/DASHBOARD.png)

Live demo
---------

[](#live-demo)

The demo application is automatically deployed to [Heroku](https://www.heroku.com/) and can be reached at:

-

The sources for the demo application are available at .

*Please note that the contents of the demo deployment are automatically cleaned up each time a new version is deployed.*

Setting up a local development environment
------------------------------------------

[](#setting-up-a-local-development-environment)

PepisCMS is meant to be used as a library. A local development environment with a sample project can be initialized as a Docker Compose environment:

```
docker-compose up
```

Once a Docker Compose setup is started, all the PepisCMS instance project files will be stored in the `tmp/` directory.

To restart the environment, first remove the instance files and then recreate the Docker Compose setup:

```
sudo rm -rf ./tmp/ && docker-compose up --force-recreate --build
```

The default admin credentials are `demo@example.com` / `demodemo`.

See other [useful development commands](docs/USEFUL_DEVELOPMENT_COMMANDS.md).

Some history
------------

[](#some-history)

PepisCMS was started in 2007 as a coursework project. Shortly after its first release the system was implemented to serve a couple of production websites and CRM systems.

[CodeIgniter](https://codeigniter.com/) was picked as the application framework. At the time there were few serious PHP frameworks available and CodeIgniter seemed to be a reasonable choice.

During project's lifespan, PepisCMS has been fluently ported from CodeIgniter version CI 1.5.4 to 3.1+. One should be aware that using a *pre-PSR* framework implies that all the implementation is tightly coupled to the framework libraries.

Due to the minimal footprint and literally no overhead of the framework, project built on top of PepisCMS are really fast.

*There are no plans to migrate PepisCMS to use CodeIgniter 4 as the framework introduced backward incompatible changes.*

Development philosophy
----------------------

[](#development-philosophy)

The project has been developed using a very conservative approach and manually tested on multiple deployments prior to releasing a stable version. Together with Behat and PHPUnit tests it made it possible to keep the regression to minimum.

### Becoming an open source project

[](#becoming-an-open-source-project)

On the "10th birthday" the project was released as open source under the [MIT license](LICENSE.txt).

Prior to pushing the project to [GitHub](https://github.com/piotrpolak/pepiscms) its code has been slightly refactored, cleaned up from any proprietary code, described by some tests and released as a [composer dependency](https://packagist.org/packages/piotrpolak/pepiscms).

Together with the first open-source release, PepisCMS 1.0.0 got support for the [Composer dependency management](https://getcomposer.org/) and core features got described by Behat functional tests.

Some code has been rewritten in the PSR style and benefits from PSR class autoloading. Being a composer module PepisCMS now benefits from the component management. Upgrading any of its dependencies is now simplified to incrementing composer versions. Version 1.0.\* plays well both with PHP5 and PHP. As 2021, the project is **fully functional** and \**well tested*.

Features
--------

[](#features)

- **Modularity**

    Modularity and consistency. An external modules can be written independent on the system core. System core can be upgraded without any modification in the current application at any time.

    There are two kinds of modules - builtin (available in all projects) and user-space modules. Modules can be enabled or disabled from the administration console. A typical module consists from both admin and public controllers + the support code.

    Read more about [modules](#modules).
- **Advanced user and user rights management**

    The user is granted a certain right above a business entity. Every single controller method has associated a minimal right above a certain entity.

    All violations of security policy are reported in system audit logs.

    You can create as many users as you want, you can assign a user to several groups, the security policy can be modified at runtime.

    Read more about [security policy](#security-policy).
- **Audit logs**

    All user actions and unexpected application behaviors can be tracked down using an advanced log utility. PepisCMS provides a logging API and a console for analyzing system logs.
- **User session security**

    User session will expire after one hour of inactivity (configurable). The session is protected against session spoofing attack by validating the IP each time the system validates the user rights.
- **Web based file manager**

    The user can manage files on the server using an AJAX file manager. You can restrict the allowed upload extension list from configuration.
- **Enhanced SMTP Email sender**

    A utility for sending emails in a reliable way reliable. When the system is unable to connect to the remote SMTP server, an alternative `mail` gateway is used and the fallback action is reported in audit logs.
- **Multi language native support**

    The application supports internationalization and multi language support by default, both for front-end and backend. An integrated [translator](#translator) speeds up multi language application development.
- **Rich Text Editor**

    [CKEditor](https://ckeditor.com/) makes you you feel you are using MS Word while editing web site contents. You can change text formatting and attach pictures.
- **Configuration tests on startup**

    Basic configuration tests ensure system cohesion and proper operation on any environment.
- **Two level cache mechanism**

    Makes your web site bulletproof. The HTML output cache mechanism is run before the framework is initialized and serves static contents at the speed of serving static pages.
- **Backup utility**

    Allows to create and download MySQL SQL dumps.
- **Intranet options**

    You can restrict access to public contents and uploaded files for unauthenticated users.
- **SEO Friendly**

    PepisCMS generates SEO friendly links and optimized meta tags. It also automatically generates sitemap (both txt and xml) for the website.
- **Build-in components for generating grids and forms.**

    Using these components you have 90% of requested features implemented from the start. The [data grid](#datagrid-library) supports ordering table by any column and implements multiple filters. The [form generator](#formbuilder-library) implements validation, data retrieval and data save, file upload and many others by default.

    You can extend or overwrite behavior of these components using [advanced callbacks](#lifecycle-callbacks).
- **Build-in helpers for generating Excel files and PDF files.**

    You can easily export application data into XLS file or print any HTML to PDF.
- **Content journaling**

    Makes it simple to track down changes upon entities and to restore specific values.
- **CRUD module generator**

    Generate database CRUD admin panel in minutes.

    Read more about [CRUD module generator](#generating-a-crud-module).
- **Builtin UI translator**

    Localize your application with no effort.

    Read more about [Translator module](#translator).
- **Builtin SQL console**

    Makes maintenance and upgrade tasks a piece of cake.

    Read more about [SQL Console module](#sql-console).
- **Seamless Symfony2 integration**

    Consume Symfony2 encapsulated business logic inside CMS panel. Benefit from the powerful dependency injection engine.
- **Admin panel customization**

    Makes it possible to customize the look of administration panel by offering the possibility of injecting HTML/JS/CSS code in selected sections of the view.
- **Backward compatibility**

    Any instance of PepisCMS can be easily upgraded to a newer version with minimal effort. All versions within the same branch are 100% backward compatible.
- **Cache and admin panel speed**

    Critical components of administration panel are cached thus improving overall performance of CMS.
- **Twig integration**
- **SSH and Array models**

    Makes it possible to operate on models that provide data out of any source.
- **Google Chart integration**
- **phpCAS/native authentication drivers**

    *phpCAS authentication driver is disabled by default.*

Requirements
============

[](#requirements)

- PHP 5.6+/7.0+/8.0 with mysqli, gd (recommended), mbstring (recommended)
- Apache 2 with mod\_rewrite
- MySQL or MariaDB database
- composer

Installation
------------

[](#installation)

PepisCMS is installed as a composer dependency and then instantiated in the user directory.

Once the composer dependency has been configured and downloaded (see below) there are two ways of bootstrapping PepisCMS instance:

- [attended](#attended-user-installation) (user)
- [unattended](#unattended-installation) (manual)

### Configuring composer

[](#configuring-composer)

#### Adding composer dependency from command line ()

[](#adding-composer-dependency-from-command-line-)

```
composer require piotrpolak/pepiscms --prefer-dist
```

#### Configuring composer from command line (using dev-master from Github repository)

[](#configuring-composer-from-command-line-using-dev-master-from-github-repository)

```
composer init --type "project" --stability "dev" \
    --repository '{"type": "vcs", "url": "https://github.com/piotrpolak/pepiscms.git"}' && \
    composer require piotrpolak/pepiscms dev-master --prefer-dist
```

#### Creating composer.json by hand (using dev-master from Github repository)

[](#creating-composerjson-by-hand-using-dev-master-from-github-repository)

```
{
    "name": "yourvendorname/yourprojectname",
    "minimum-stability": "dev",
    "repositories": [
        {
            "type": "vcs",
            "url": "https://github.com/piotrpolak/pepiscms.git"
        }
    ],
    "require": {
        "piotrpolak/pepiscms": "dev-master"
    }
}
```

### Attended (user) installation

[](#attended-user-installation)

1. Install composer dependencies

    ```
    composer install --prefer-dist
    ```
2. Copy `install.php` file to root directory

    ```
    cp ./vendor/piotrpolak/pepiscms/install.php ./
    ```
3. Open `install.php` in your browser

    This will create a basic framework structure. Please follow the installation guide.

    - Directory view [![Directory view](docs/screens/INSTALLATION_1.png)](docs/screens/INSTALLATION_1.png)
    - Copy files and create framework structure [![Copy files](docs/screens/INSTALLATION_2.png)](docs/screens/INSTALLATION_2.png)
    - Database connection setup

        There are two options: **native** and **Symfony import**.

        When selecting **native** you will be asked for database host, name, user and password.

        If selecting **Symfony import** then PepisCMS tries to automatically parses Symfony `parameters.yml` configuration.

        [![Database connection](docs/screens/INSTALLATION_3.png)](docs/screens/INSTALLATION_3.png)
    - Selecting authorization driver. You can choose from **native** (users are managed locally) or **CAS**

        When selecting **CAS** then user passwords **will not be managed by PepisCMS**. The local users having minimal access rights will be created upon the first user authentication (use of the system).

        [![Authorization driver](docs/screens/INSTALLATION_4.png)](docs/screens/INSTALLATION_4.png)
    - Configuring administrator account [![Administrator account](docs/screens/INSTALLATION_5.png)](docs/screens/INSTALLATION_5.png)
    - Configuring site options [![Site confguration](docs/screens/INSTALLATION_6.png)](docs/screens/INSTALLATION_6.png)
    - Configuring installed modules

        You can choose which modules to be installed and add specified modules to menu and/or utilities.

        [![Installed modules](docs/screens/INSTALLATION_7.png)](docs/screens/INSTALLATION_7.png)
    - Success message [![Success](docs/screens/INSTALLATION_8.png)](docs/screens/INSTALLATION_8.png)
    - Dashboard [![Dashboard](docs/screens/INSTALLATION_9.png)](docs/screens/INSTALLATION_9.png)

### Unattended installation

[](#unattended-installation)

PepisCMS can be installed and configured in an unattended way.

The following BASH variables can be used to control the installation parameters:

```
# The variable values are empty by default. The below values are taken from docker-compose.yml file
PEPIS_CMS_DATABASE_CONFIG_TYPE: native
PEPIS_CMS_DATABASE_HOSTNAME: db
PEPIS_CMS_DATABASE_USERNAME: pepiscms
PEPIS_CMS_DATABASE_PASSWORD: pepiscms
PEPIS_CMS_DATABASE_DATABASE: pepiscms
PEPIS_CMS_AUTH_DRIVER: native
PEPIS_CMS_AUTH_EMAIL: demo@example.com
PEPIS_CMS_AUTH_PASSWORD: demodemo
PEPIS_CMS_SITE_EMAIL: demo@example.com
PEPIS_CMS_SITE_NAME: Demonstration
PEPIS_CMS_OBJECT_CACHE_OBJECT_IS_ENABLED: true # Set false for cloud deployment
PEPIS_CMS_IS_UNATTENDED_INSTALL: true # Set false for manual installer
PEPIS_CMS_EMAIL_USE_SMTP: true
PEPIS_CMS_EMAIL_SMTP_HOST: fake-smtp
PEPIS_CMS_EMAIL_SMTP_USER: fake-smtp
PEPIS_CMS_EMAIL_SMTP_PASS: fake-smtp
PEPIS_CMS_EMAIL_SMTP_PORT: 25
```

Email console is available under

The command line for unattended installation:

```
composer install --prefer-dist && \
    cp vendor/piotrpolak/pepiscms/pepiscms/resources/config_template/template_index.php ./index.php && \
    sed -i -e 's/TEMPLATE_VENDOR_PATH/\.\/vendor\//g' ./index.php && \
    cp vendor/piotrpolak/pepiscms/pepiscms/resources/config_template/template_.htaccess ./.htaccess && \
    php index.php tools install && \
    php index.php tools register_admin $PEPIS_CMS_AUTH_EMAIL $PEPIS_CMS_AUTH_PASSWORD
```

See [demo application setup scripts](https://github.com/piotrpolak/pepiscms-demo/blob/master/bin/setup.sh) to see PepisCMS unattended installation in action.

Command line interface
----------------------

[](#command-line-interface)

Available command line utilities:

- `php index.php tools install []`
- `php index.php tools register_admin  `
- `php index.php tools passwd  `
- `php index.php tools inactivate `
- `php index.php tools activate `
- `php index.php tools set_config  `
- `php index.php tools get_config `
- `php index.php tools index` - lists all the commands

Modules
-------

[](#modules)

PepisCMS distinguishes between two types of modules, based on where the modules code is placed:

- **system modules** - these modules are bundled in the system and are upgraded each time PepisCMS is upgraded, those modules are available for all PepisCMS applications. See the list of [built-in modules](#built-in-modules) or check the [modules source](./pepiscms/modules).
- **user modules** - user space modules, those are specific to instance of your application.

By default all modules are disabled and must be manually enabled (installed) (during PepisCMS installation or at any later point).

### Module installation

[](#module-installation)

Module installation consists in enabling the module and configuring its parameters (if available). Modules that do have administration interface can be attached to an admin panel menu and/or utilities dashboard. Most modules come with predefined configuration and presentation defaults. Configuration options and presentation details are defined in a module descriptor (a class that implements [ModuleDescriptableInterface](./pepiscms/application/classes/ModuleDescriptableInterface.php)).

An SQL code can be executed upon module installation/uninstallation. A file containing SQL code can be optionally specified in module descriptor.

To view installed modules please navigate to `Start > Utilities > Installed modules`.

### Accessing modules in the browser

[](#accessing-modules-in-the-browser)

#### Admin module actions

[](#admin-module-actions)

```
http://localhost/admin//
```

#### Public module actions

[](#public-module-actions)

```
http://localhost//
```

Where `` is the module name (directory name) and `` is the method name (the method must have public classifier).

If no action is specified, the default action is `index`, i.e. `http://localhost/` is equal to `http://localhost//index`

Please note that the module must be installed and the `Frontend support (pages and modules)` must be enabled in order to access public controllers. This can be enabled from `Start > Utilities > Site's configuration`.

### Module structure

[](#module-structure)

- Module descriptor (optional, when specified must implement [ModuleDescriptableInterface](./pepiscms/application/classes/ModuleDescriptableInterface.php))
- Admin controller (optional)
- Public controller (optional)
- Admin views (optional)
- Public views (optional)
- Models (optional)
- Libraries (optional)
- Language files
- Security policy (`security_policy.xml`)
- Additional resources (like default icons: `/resources/icon_16.png` and `/resources/icon_32.png`)

#### Sample module structure

[](#sample-module-structure)

Below the structure of sample `labels` module:

[![Module structure - new](docs/screens/MODULE_STRUCTURE_NEW.png)](docs/screens/MODULE_STRUCTURE_NEW.png)

There is also a legacy module structure layout. The legacy layout is no longer supported by default, however it can be enabled from configuration in case you already have modules generated with a past version of PepisCMS and do not want to upgrade:

[![Module structure - legacy](docs/screens/MODULE_STRUCTURE_LEGACY.png)](docs/screens/MODULE_STRUCTURE_LEGACY.png)

### Built-in modules

[](#built-in-modules)

#### Groups

[](#groups)

A utility for managing user groups and groups access rights.

Read more about [security policy](#security-policy).

[![Groups](docs/screens/MODULES_GROUPS.png)](docs/screens/MODULES_GROUPS.png)

#### User accounts

[](#user-accounts)

A utility for managing and registering new users.

[![User accounts](docs/screens/MODULES_USER_ACCOUNTS.png)](docs/screens/MODULES_USER_ACCOUNTS.png)

#### Development tools

[](#development-tools)

[![Development tools](docs/screens/MODULES_DEVELOPMENT_TOOLS.png)](docs/screens/MODULES_DEVELOPMENT_TOOLS.png)

#### System logs

[](#system-logs)

All user actions and unexpected application behaviors can be tracked using an advanced log utility.

PepisCMS provides a logging API and a console for analyzing system logs.

Every single log consists of the following entry:

- **Timestamp** of the event
- **User ID/email** generating the event
- **IP address** of the user creating the entry
- **Module name** (if case)
- **Collection name** – abstract label used for grouping the events and drawing statistics
- **Debug message**
- **URL** where the event occurred
- **Severity** of the event –info, notice, warning, error

[![System logs](docs/screens/MODULES_SYSTEM_LOGS.png)](docs/screens/MODULES_SYSTEM_LOGS.png)

#### SQL console

[](#sql-console)

[![SQL console](docs/screens/MODULES_SQL_CONSOLE.png)](docs/screens/MODULES_SQL_CONSOLE.png)

#### System information

[](#system-information)

Displays system information, paths, versions, storage occupied.

[![System information](docs/screens/MODULES_SYSTEM_INFORMATION.png)](docs/screens/MODULES_SYSTEM_INFORMATION.png)

#### Translator

[](#translator)

A utility for translating user interface.

[![Translator](docs/screens/MODULES_TRANSLATOR.png)](docs/screens/MODULES_TRANSLATOR.png)

#### Symfony2 bridge

[](#symfony2-bridge)

Allows to invalidate Symfony cache and to view Symfony logs.

Symfony2 bridge must be first enabled by [adding an piotrpolak/codeigniter-symfony2-bridge library](#enabling-symfony-bridge). See the [codeigniter-symfony2-bridge project](https://github.com/piotrpolak/codeigniter-symfony2-bridge).

#### Backup

[](#backup)

Allows to create and download MySQL SQL dumps.

#### CRUD

[](#crud)

This module is a base for any other CRUD module. It is not installable.

#### HTML customization for admin panel

[](#html-customization-for-admin-panel)

Allows to inject HTML snippets to admin panel header and footer.

#### Configuration values

[](#configuration-values)

Allows editing database stored configuration values.

Generating a CRUD module
------------------------

[](#generating-a-crud-module)

CRUD stands for *Create Read Update and Delete*. PepisCMS aims to ease creating typical CRUD modules for managing data saved in a database table.

To generate a CRUD module for a given database table:

1. Execute SQL DDL against the database. You can use the bundled [SQL console module](#sql-console).
2. Make sure [development tools module](#development-tools) is installed.
3. Navigate to `Start > Utilities > Development tools > Build a new module`.
4. Provide mandatory `database table name` and optional module details:

    [![Generating a CRUD module](docs/screens/GENERATING_A_CRUD_MODULE_1.png)](docs/screens/GENERATING_A_CRUD_MODULE_1.png)

    - Module name - leave empty to keep default name equal to the database table name
    - Whether to parse database schema
    - Whether to generate implicit security policy
    - Module type (CRUD or Default/basic)
    - Database connection (if you have multiple databases configured)
    - Languages for generating translation files
    - Whether to generate a public controller
5. Proceed
6. Customize translations (optionally)
7. Customize generated controller code (optionally)
8. Upload custom icons (optionally)

You can find a sample SQL file to play with at [sql/sample.sql](sql/sample.sql).

Built-in utilities
------------------

[](#built-in-utilities)

- Site's configuration
- Modules management
- Cache management/flush
- Reload (own) privileges
- Security policy builder
- Check own access rights utility
- Configuration tests

Security policy
---------------

[](#security-policy)

A security policy is a set of required user rights above certain entities required to access a controller's method. The user is granted one of the four access rights above above the defined entities.

When a security policy is created, the administrator first defines desired entities (such as `page`, `user`, `group`, `configuration` etc.) and assigns the entities to methods of controllers.

How access check works:

1. User accesses a controller method
2. If the user is marked as root, the access is immediately granted
3. SecurityManager parses appropriate `security_policy.xml` and reads the entity and minimum access level for a given controller method
4. SecurityManager checks groups for the authenticated user and computes associated entity-granted access map
5. SecurityManager checks if the computed user entity-granted access map contains an entry related to the entity
6. SecurityManager checks the user access level against the minimum required access level, if it is satisfied or if the required access level is `NONE` the user is granted access to the controller method. Otherwise the user is denied access.

**All violations of security policy are reported using system logs.**

### Possible access levels

[](#possible-access-levels)

There are four access levels:

- `NONE`
- `READ`
- `WRITE`
- `ALL`

### Entities

[](#entities)

An entity is just a string representing the core business object.

**Example**: Managing, rearranging, managing, and running modules is realised by different method of the `module` controller. Each method has different minimal access levels for `module` entity:

```

```

Security policy management console view: [![Security policy](docs/screens/SECURITY_POLICY.png)](docs/screens/SECURITY_POLICY.png)

Also see [groups module](#groups).

### Controllers, methods and reflection

[](#controllers-methods-and-reflection)

Every controller method for which a security policy is defined has associated a minimal required access right above an entity.

The reflection mechanism is used to scan for the controller methods.

### Changing security policy at runtime

[](#changing-security-policy-at-runtime)

Security policy can be changed at any time without need to change code or recompile anything. `AdminControllers` initializes `SecurityManager` that handles security transparently to the programmer or user of the system.

### Marshaling a security policy and caching

[](#marshaling-a-security-policy-and-caching)

Security policy is serialized onto XML file (`security_policy.xml`) that is platform independent and can be manually edited. In order to reduce time needed for parsing XML file with each request, the security policy is storied in a processed and serialized cached format on the permanent storage or directly in the memory.

### Types of security policies

[](#types-of-security-policies)

There are two types of security policy:

- System core security policy ([core security\_policy.xml](./pepiscms/application/security_policy.xml))
- Module security policy (example, [user accounts module security\_policy.xml](./pepiscms/modules/cms_users/security_policy.xml).)

### User groups

[](#user-groups)

Once the security policy is created for both core and modules the administrator can create user groups. Creating a group is process similar to building security policy - the administrator picks an access level for every single entity that is granted to anyone who belongs to the group.

A single user can belong to any number of user groups. This offers high flexibility because you can manage the groups separately.

Deployment configurations
-------------------------

[](#deployment-configurations)

A project can be deployed in several configurations. The following options will be presented in the small-to-enerprise order.

### Small website (Content Management System, Web)

[](#small-website-content-management-system-web)

The framework is installed as the core only and provides basic functions for building a website that can use multiple template; there is a SEO friendly frontend and simple administration panel for managing pages, menu, files and administrators.

### Administration panel for a database (Intranet Application)

[](#administration-panel-for-a-database-intranet-application)

In this option the framework acts as a basic database application that can be accessed from various locations.

The framework can manage several databases of different types at the same time. There is no public frontend available.

*Example*: Invoicing application

### Portal/eCommerce application (Content Management System, Web)

[](#portalecommerce-application-content-management-system-web)

Portal combines the features of a small website and an intranet application. Some pages of the portal are generated dynamically; there can be some kind of interaction between the platform and the visitor (comments, user login, order processing etc.). Administrator of such applications has some extra features and dedicated modules available.

All of the components including business logic are placed on the same machine.

*Advantages*: simple to implement, low cost

*Disadvantages*: any failure can be deadly, can have scalability issues

*Example*: blog, online shop.

Architecture overview
---------------------

[](#architecture-overview)

### Core of the system

[](#core-of-the-system)

Core implements most of the base features and it is supposed to be stable over the time. The core takes advantage of [CodeIgniter framework](https://codeigniter.com/) that provides basic architecture, input security and database ActiveRecord access method.

Specifically for the core of PepisCMS some of the classes were overloaded or rewritten (see [overwritten core libraries](./pepiscms/application/core/).

PepisCMS distinguishes between 4 types of controllers:

- **Basic controller** (same as for CodeIgniter)
- **[ModuleController](./pepiscms/application/classes/ModuleController.php)** - public module controller
- **[AdminController](./pepiscms/application/classes/AdminController.php)** - for core administration panel, handles security check transparently
- **[ModuleAdminController](./pepiscms/application/classes/ModuleAdminController.php)** - module administration panel controller that supports "hotplug" and a kind of visualization where the original AdminController acts as a host and maps all accessible resources (translates) to ModuleAdminController instance without duplicating them in memory

### Modules

[](#modules-1)

Modules implement business specific features that are not generic and should not be distributed for all the instances of the application. Modules can be easily transferred from a project to project and should not create dependency conflicts. Every single module can be enabled/disabled at any time.

System and user modules they work exactly the same. If an user space module of the same name as an existing system module is installed, the system module will be completely ignored – you can overwrite the default users and logs modules.

Read more about [Modules](#modules).

### Model-View-Presenter architectural pattern

[](#model-view-presenter-architectural-pattern)

The application is built around [Model View Presenter pattern](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter)).

A request triggers a presenter (controller) method that uses logic encapsulated in models (and libraries) to prepare data for the view layer.

#### Model

[](#model)

Model encapsulates data access using the [Data Access Object](https://en.wikipedia.org/wiki/Data_access_object) pattern.

Models provide methods that read, update and delete entities. CodeIgniter uses instances of stdClass to represent entities.

Entities:

- have no methods
- have fields that reflect database structure (query result set structure)

All models must start with a capital letter and must be suffixed with \_model. Unlike libraries, the model instance names are case sensitive (this comes from CodeIgniter engine).

Read more about [CodeIgniter models](https://www.codeigniter.com/user_guide/general/models.html).

PepisCMS provides some base models that can be extended in order make development simpler:

NameDescription[Generic\_model](#generic-model)Generic model is the improved version od CodeIgniter model. It implements methods specified by both [EntitableInterface](./pepiscms/application/classes/EntitableInterface.php) and [AdvancedDataFeedableInterface](./pepiscms/application/classes/AdvancedDataFeedableInterface.php) interfaces. In most cases this class should be extended and parametrized in the constructor but it is left as a non-abstract for DataGrid and FormBuilder components that initialize and parametrize Generic\_model "on-the-fly" using prototype design pattern.[Array\_model](./pepiscms/application/models/Array_model.php)Provides Generic\_model capabilities that can be applied to data sources other than database.[Ssh\_model](./pepiscms/application/models/Ssh_model.php)Provides Generic\_model and Array\_model capabilities for data parsed over SSH#### View

[](#view)

View is used as the presentation layer. It is fully controlled by controller but it can also pull some data provided by models or libraries initialized by controller. It is a good technique to prepare all the data inside the controller and to use view only as the "display layer" with absolutely no logic inside - doing so makes it\*\*\*\* much easier to change the view, for example from pure HTML to JSON format used by JavaScript.

To load a view you should use the `$this->display()` method from the `Enhanced_controller`. It will automatically compute view's path based on the module name (if any), controller name and method name.

To assign a variable to the view, you should use the `$this->assign('variable-name', 'variable-value`)` method.

#### Controller

[](#controller)

Controllers are these components that interpret input, take some decisions and prepare data for the output. In the case of web applications by input we understand GET/POST variables, Session variables Cookies and several others. Controller implements some of the logic and pulls data from different locations – database, web services, APIs, sockets etc.

Controllers take advantage of libraries and models they load, they should not manipulate the database directly but by using models.

PepisCMS distinguishes 4 types of controllers:

NameDescription[EnhancedController](./pepiscms/application/classes/EnhancedController.php) extends Controller (abstract)Implements handy methods like assign($name, $variable) that are used in any other type of controllers.[AdminController](./pepiscms/application/classes/AdminController.php) extends EnhancedControllerUsed for administration panel only. Authorization and authentication is implemented in the constructor.[ModuleAdminController](./pepiscms/application/classes/ModuleAdminController.php) extends AdminControllerSimilar to the AdminController, used for back-end controllers of modules.[ModuleController](./pepiscms/application/classes/ModuleController.php) extends EnhancedControllerUsed for front-end controllers of modules. Use document library to set page titles and to interact with the systemGeneric model
-------------

[](#generic-model)

[Generic\_model](./pepiscms/application/models/Generic_model.php) is an extended Model that implements [EntitableInterface](./pepiscms/application/classes/EntitableInterface.php) required by [FormBuilder](./pepiscms/application/libraries/FormBuilder.php).

The `EntitableInterface` interface specifies the 3 basic methods: `saveById($id, $data)`, `deleteById($id)` and `getById($id)`. You can implement the `EntitableInterface` class by default but for most of the cases Generic\_model with its helper methods is more than enough – in most situations Generic\_model should only be extended.

Generic\_model also implements [AdvancedDataFeedableInterface](./pepiscms/application/classes/AdvancedDataFeedableInterface.php)interface that is needed by [DataGrid](./pepiscms/application/libraries/DataGrid.php) component.

Methods of the generic model are worth to mention because they are present in all the models used by PepisCMS.

Method nameDescription`setTable($table)`Sets table name on which the model will operate. Table name must be explicitly specified before the model is usable.`setIdFieldName($idField)`Overwrites the name of the ID field. The default ID field is called id. Specify id field if your database table's id field is non standard (example personal\_number).`setWhere($where_conditions)`Sets where conditions that will be used when obtaining the data for DataGrid. Where conditions should be of the same form as passed to the Database query object. The parameter must be an associative array where the keys specify the field names and the values are the desired values.`setAcceptedPostFields($fields)`Sets the list of accepted POST fields' names. The default saveById method accepts only fields that were previously defined as accepted. FormBuilder automatically sets the accepted post fields based on the defined inputs.`addAcceptedPostField($field)`Appends accepted POST field. You can specify a single field (string) or a set of extra fields. This method is handy when you need to append the list of accepted fields once the model/form has been defined, for instance in a FormBuilder callback.`applyFilters($db, $filters)`Static method that applies filters specified in the DataGrid format upon the specified DB object. This method is very usefull when you write your own getAdvancedFeed method and you want it to be compaible with the filers.`getById($id, $fields='*')`Returns instance of stdObject or FALSE`deleteById($id)`Deletes row by ID`saveById($id, $data_array)`Saves object in the database. If no $id is set, the object is inserted, when $id is set, the object is updated. $data\_array must be associative array and its keys must be previously registered by setAcceptedPostFields method!`move($id, $direction, $table=FALSE, $constraint_field_name=FALSE, $item_order_field_name='item_order', $id_field_name='id')`This method is used to move elements of a list. It is used for changing the order of menu elements in page controller. Dont try to understand how it works, even for the author is looks like magic after some months. The following method takes all the items belonging to the same "group" (all items having the same value of constraint\_field), moves the elements (swaps the item\_order field) and normalizes the item\_order values.`getDistinctAssoc($column, $table=FALSE, $pairs=FALSE)`Gets distinct values from a table's collumn. If table parameter is not specified, it will take it from the instance $table variable.You can predefine the return array by specifying $pairs.`getAssocPairs($key_collumn_name, $value_collumn_name, $table=FALSE, $imitial_array=FALSE, $possible_keys=FALSE)`Get an associative array build with keys found in $key\_collumn\_name collumn and values found in $value\_collumn\_name. You can specify the initial array as $imitial\_array`generateTextId($text_id_field_name=FALSE, $length=FALSE, $prefix=FALSE, $suffix=FALSE, $table=FALSE)`Generates random string ID that is checked for uniqueness. Random string IDs are used as tracking numbers and in other situations where giving the end user an order ID is not desired.`setDatabase($database_group)`Sets the database connection to be used by the model, database group must be defined in database config. Since 0.2.2Sometimes it is not desired to use the default Generic\_model methods, for example when you need to obtain minimalistic data set. [Generic\_model](./pepiscms/application/models/Generic_model.php) by default selects all from your database using the `*` wildcard sign.

FormBuilder library
-------------------

[](#formbuilder-library)

A library that can build and handle HTML forms based on the provided definition. Form builder can render the form using the default layout or you can register an additional renderer. FormBuilder can either use an instance of [EntitableInterface](./pepiscms/application/classes/EntitableInterface.php) or a anonymous instance of the [Generic\_model](./pepiscms/application/models/Generic_model.php) that binds to an arbitrary database table.

The main features of form builder are:

- Generates HTML forms from definition
- Handles input validation, both on server side (for security) and on client side (JavaScript for increased responsiveness)
- Handles database read/update/insert
- Can be customized using templates
- Can be extended using callbacks and custom feed objects that implement the [EntitableInterface](./pepiscms/application/classes/EntitableInterface.php)
- Can handle database foreign keys
- When using FormBuilder you can specify the fields of the form and their attributes in two manners: by API methods or by definition. The API methods were first that were developed but they are not recommended to use in new projects. Initializing the form from definition that is an associative array (multidimensional hash table) makes it much more flexible and reusable – when new attributes are implemented, the previously defined forms work with no problems. It is also simpler for the programmer because the order of attributes in the definition does not matter. If there is no attribute specified its default value is automatically completed.
- The definition used for generating FormBuilder is compatible with the definition used by DataGrid so that one definition can be written and reused both for the Form and for the Grid.
- Form builder is closely coupled with [EntitableInterface](./pepiscms/application/classes/EntitableInterface.php) - it uses its `saveById()` and `getById()` methods.

See complete [FormBuilder API](./pepiscms/application/libraries/FormBuilder.php)

### Generating a form

[](#generating-a-form)

In the most common scenario the customizable Generic\_model is used as the feed object for FormBuilder. The scenario looks as follows:

1. Initialize FormBuilder `$this->load->library('FormBuilder')`
2. Specify data model or use GenericModel providing the table name
3. Specify the value of entity ID - `$this->formbuilder->setId($id)`
4. Specify the fields and their properties by `$this->formbuilder->setDefinition($definition)`
5. Specify the back link `$this->formbuilder->setBackLink($link)` - URL that is used for the "Cancel" button and for redirecting the user once the form is saved
6. Trigger form populate/save actions and generate the resulting HTML

### Lifecycle callbacks

[](#lifecycle-callbacks)

Callbacks are used to extend or to overwrite certain operations done by FormBuilder.

READ related callbacks should take the OBJECT as the parameter while the WRITE callbacks should take ARRAY as parameter. The reason for that is that rows are retrieved from database as objects while the form values come as associative array.

If you are not fine with that, you can ensure a certain type by type casting: `$object = (object) $array` and PHP will do all the magic.

Callbacks are usually defined in controller code as methods prefixed with "\_"to prevent it from being accessed via HTTP. They can be delegated to external classes or can be simple functions as long as they are callable with the specified parameters. The concept of the callback is very similar to the concept of the ActionListener. Please note that if you define the callback in the controller class it must be public so that it can be called from an an external instance.

Method nameDescriptionCALLBACK\_BEFORE\_RENDERCalled after retrieving the data but before rendering the form. The callback function takes must take the OBJECT parameter as reference.CALLBACK\_BEFORE\_SAVECalled before saving the data. The callback function must take the ARRAY parameter as reference.CALLBACK\_AFTER\_SAVECalled after saving the data. The callback function must take the ARRAY parameter as reference.CALLBACK\_ON\_SAVE\_FAILURECalled when data save fails. It can be using for rollback operations.The callback function takes must take the ARRAY parameter as reference.CALLBACK\_ON\_SAVECalled on save. This kind of callback should be used when no feed object specified of when you want to overwrite the default SAVE operation. The callback function takes must take the ARRAY parameter as reference and MUST return TRUE or FALSE. If the function returns FALSE, it should also set FormBuilder validation error message.CALLBACK\_ON\_READCalled on read. This kind of callback should be used when no feed object specified of when you want to overwrite the default READ operation.The callback function takes must take the OBJECT parameter as reference and to FILL it.The callback does not need to return anything.Callback setup:

```
$this->formbuilder->setCallback( array($this, '_fb_callback_before_render'), FormBuilder::CALLBACK_BEFORE_RENDER );
$this->formbuilder->setCallback( array($this, '_fb_callback_before_save'), FormBuilder::CALLBACK_BEFORE_SAVE );
$this->formbuilder->setCallback( array($this, '_fb_callback_after_save'), FormBuilder::CALLBACK_AFTER_SAVE );
$this->formbuilder->setCallback( array($this, '_fb_callback_on_save'), FormBuilder::CALLBACK_ON_SAVE );
$this->formbuilder->setCallback( array($this, '_fb_callback_on_save_failure'), FormBuilder::CALLBACK_ON_SAVE_FAILURE );
$this->formbuilder->setCallback( array($this, '_fb_callback_on_read'), FormBuilder::CALLBACK_ON_READ );

/**
 * Called after validation, before saving
 * @param array $data_array
 */
public function _fb_callback_before_save( &$data_array ){}

/**
 * Some logs or statistics maybe?
 * @param array $data_array
 */
public function _fb_callback_after_save( &$data_array ){}

/**
 * Put here your rollback action
 * @param object $object
 */
public function _fb_callback_on_save_failure( &$object ){}

/**
 * Must overwrite the save procedure and return true or false
 * @param object $object
 */
public function _fb_callback_on_save( &$object ){}

/**
 * Must populate object
 * @param object $object
 */
public function _fb_callback_on_read( &$object ){}

/**
 * Can manipulate data after read, before rendering
 * @param object $object
 */
public function _fb_callback_before_render( &$object ){}
```

### Image fields’ callbacks

[](#image-fields-callbacks)

You can attach an independent callback to the image fields. The difference between form builder general callbacks and image callbacks is that image callback is only called when a new image is being uploaded while form builder callback is called each time you save a form.

Sample callback (taken from admin module CRUD template):

```
/**
 * Callback function changing the name of the file to SEO friendly
 *
 * @version: 1.2.3
 * @date: 2015-06-11
 *
 * @param $filename
 * @param $base_path
 * @param $data
 * @param $current_image_field_name
 * @return bool
 */
public function _fb_callback_make_filename_seo_friendly(&$filename, $base_path, &$data, $current_image_field_name)
{
    // List of the fields to be used, if no value is present for a given key
    // then the key will be ignored. By default all values of the keys
    // specified will be concatenated
    $title_field_names = array('name', 'title', 'label');

    $this->load->helper('string');
    $path = $base_path . $filename;
    $path_parts = pathinfo($path);

    // Attempt to build a name
    $new_base_filename = '';
    foreach ($title_field_names as $title_field_name) {
        // Concatenating all the elements
        if (isset($data[$title_field_name]) && $data[$title_field_name]) {
            $new_base_filename .= '-' . $data[$title_field_name];
        }
    }

    // Making it web safe
    if ($new_base_filename) {
        $new_base_filename = niceuri($new_base_filename);
    }

    // This should not be an else statement as niceuri can return empty string sometimes
    if (!$new_base_filename) {
        $new_base_filename = niceuri($path_parts['filename']);
    }

    // This should normally never happen, but who knows - this is bulletproof
    if (!$new_base_filename) {
        $new_base_filename = md5(time() + rand(1000, 9999));
    }

    $new_base_path = '';
//        $new_base_path = date('Y-m-d') . '/'; // Will create directory based on date
//        $new_base_path = $new_name_base . '/'; // Will create directory based on the niceuri value
//        @mkdir($base_path . $new_base_path); // Do not forget!
    // We don't like upper case extensions
    $extension = strtolower($path_parts['extension']);
    $new_name = $new_base_filename . '.' . $extension;

    // Protection against existing files
    $i = 2;
    while (file_exists($base_path . $new_base_path . $new_name)) {
        $new_name = $new_base_filename . '-' . $i . '.' . $extension;
        if ($i++ > 50 || strlen($i) > 2) // strlen is a protection against the infinity loop for md5 checksums
        {
            // This is ridiculous but who knowss
            $i = md5(time() + rand(1000, 9999));
        }
    }

    // No need to change filename? Then we are fine
    if ($filename == $new_name) {
        return TRUE;
    }

    // Finally here we go!
    if (rename($path, $base_path . $new_base_path . $new_name)) {
        $data[$current_image_field_name] = $new_base_path . $new_name;
        $filename = $new_base_path . $new_name;

        return TRUE;
    }
    return FALSE;
}
```

DataGrid library
----------------

[](#datagrid-library)

A library that feature rich data view grids, including pagination, sorting and filtering.

### Features

[](#features-1)

- Generates HTML views with minimum effort using grid definition
- Makes it possible to apply callback formatting functions to individual cells.
- Can define and apply filters
- Supports dataset pagination
- Enables dataset sorting by specified colums
- Resolves OneToMany and ManyToMany foreign keys
- Supports row actions (links)
- Supports row icons (thumbails) and additional row styling based on the tuple data

### DataGrid filters

[](#datagrid-filters)

Filters are used to restrict the dataset by applying "where" conditions to the query in a way that is transparent to the user.

Every filter can have "filter\_condition" parameter associated with it that specifies the condition type. You can have several filters associated with a field as long as the filter condition differs – for example you can implement "date between" filter by using "date ge" and "date le" at the same time.

#### Possible filter types

[](#possible-filter-types)

Filter typesDescriptionFILTER\_BASICBasic text field input, user can search for any value, "like" condition by defaultFILTER\_SELECTDrop box with predefined values. Values can be specified by programmer or they can be automatically obtained from a column values.FILTER\_DATEAccepts input in date field. A calendar widget is generated when the user focuses the input.FILTER\_MULTIPLE\_SELECTSimilar to FILTER\_SELECT but the user can choose multiple values.FILTER\_MULTIPLE\_CHECKBOXSimilar to FILTER\_MULTIPLE\_SELECT but user can check multiple checkboxes.FILTER\_FORCEDFilter that is not displayed in the grid, used for manually setting filter values.#### Possible filter conditions

[](#possible-filter-conditions)

Filter typesDescriptionFILTER\_CONDITION\_EQUALselects everything that is strictly equal to searched query field = input\_valueFILTER\_CONDITION\_NOT\_EQUALselects everything that is different from searched query field != input\_valueFILTER\_CONDITION\_GREATERselects everything that is strictly greater than searched query field &gt; input\_valueFILTER\_CONDITION\_GREATER\_OR\_EQUALselects everything that is greater or equal to searched query field &gt;= input\_value – tip: applies also to DATEFILTER\_CONDITION\_LESSselects everything that is strictly less than searched query field &lt; input\_valueFILTER\_CONDITION\_LESS\_OR\_EQUALselects everything that is less or equal to searched query field &lt;= input\_value– tip: applies also to DATEFILTER\_CONDITION\_LIKEselects everything that contains searched query field LIKE %input\_value% - default for text search### Usage

[](#usage)

DataGrid definition is an associative array and it is best to be build using [CrudDefinitionBuilder](#cruddefinitionbuilder).

Complete

```
$this->load->library('DataGrid');
echo $this->datagrid->setFiltersShownBeforeGrid(TRUE)
    ->setFiltersShownAfterGrid(TRUE)
    ->setOrderable(TRUE)
    ->setTableHeadVisible(TRUE)
    ->setTitle("My Table")
    // All links will be generated with respect to this base URL
    ->setBaseUrl(admin_url() . 'somepage/edit')
    ->setDefaultOrder('id', 'asc')
    ->setItemsPerPage(300)
    ->setDefinition($definition)
    ->addFilter('Since', 'published_since_datetime',DataGrid::FILTER_DATE, FALSE,
        DataGrid::FILTER_CONDITION_LESS_OR_EQUAL)
    ->addFilter('To', 'published_since_datetime', DataGrid::FILTER_DATE, FALSE,
        DataGrid::FILTER_CONDITION_GREATER_OR_EQUAL)
    ->setRowCssClassFormattingFunction(function ($line) {
        if ($line->is_active == 1) {
            return DataGrid::ROW_COLOR_GREEN;
        } else {
            return DataGrid::ROW_COLOR_RED;
        }
    })
    ->setFeedObject($this->MyFavourite_model)
    ->generate();
```

Minimalistic, with implicit values

```
$this->load->library('DataGrid');
// All links will be generated with respect to this base URL
echo $this->datagrid->setBaseUrl(admin_url() . 'somepage/edit')
    ->setDefinition($definition)
    ->setTable('items') // Will automatically instantiate Generic_model for 'items' table
    ->generate();
```

See complete [DataGrid API](./pepiscms/application/libraries/DataGrid.php)

### DataGrid cell value formatting callbacks

[](#datagrid-cell-value-formatting-callbacks)

Using cell value formatting callbacks you can modify the value of the cell on run time, for example add a string suffix, display image or insert a link.

A callback must be a function or a public method that returns a string and that takes two parameters: cell inline value and the object representing line (row) values. Usually a callback method is defined inside the controller and is prefixed with "\_" (underscore) to prevent it from being accessed via HTTP.

```
public function _datagrid_format_order_value( $cell_value, &$line ) {
    return $cell_value.' PLN';
}
```

CrudDefinitionBuilder
---------------------

[](#cruddefinitionbuilder)

[CrudDefinitionBuilder](./pepiscms/application/classes/CrudDefinitionBuilder.php) makes it easier and safer (typesafe) to generate DataGrid and [FormBuilder](#formbuilder-library) definitions.

Below some sample code (see [CrudDefinitionBuilder code](./pepiscms/application/classes/CrudDefinitionBuilder.php)for complete reference):

```
$definition = CrudDefinitionBuilder::create()
    ->withField('address')
        ->withFilterType(DataGrid::FILTER_BASIC)
        ->withShowInGrid(FALSE)
        ->withShowInForm(TRUE)
        ->withInputType(FormBuilder::TEXTFIELD)
        ->addValidationRule('required')
        ->addValidationRule('valid_phone_number')
        ->addValidationRule('max_length[13]')
    ->end()
    ->withField('date')
        ->withShowInGrid(TRUE)
        ->withShowInForm(FALSE)
        ->withInputType(FormBuilder::TEXTFIELD)
    ->end()
        ->withField('date_sent')
        ->withShowInGrid(TRUE)
        ->withShowInForm(FALSE)
        ->withInputType(FormBuilder::TEXTFIELD)
    ->end()
    ->withField('body')
        ->withFilterType(DataGrid::FILTER_BASIC)
        ->withShowInGrid(TRUE)
        ->withShowInForm(TRUE)
        ->withInputType(FormBuilder::TEXTAREA)
        ->addValidationRule('required')
        ->addValidationRule('max_length[480]')
    ->end()
    ->withField('is_incoming')
        ->withFilterType(DataGrid::FILTER_SELECT)
        ->withValues(array(
            0 => $this->lang->line('global_dialog_no'),
            1 => $this->lang->line('global_dialog_yes')
        ))
        ->withFilterValues(array(
            0 => $this->lang->line('global_dialog_no'),
            1 => $this->lang->line('global_dialog_yes')
        ))
        ->withShowInGrid(TRUE)
        ->withShowInForm(FALSE)
        ->withInputType(FormBuilder::TEXTAREA)
        ->withNoValidationRules()
    ->end()
    ->withImplicitTranslations($module_name, $this->lang)
    ->build();
```

ContainerAware
--------------

[](#containeraware)

[ContainerAware](./pepiscms/application/classes/ContainerAware.php) is a way to access CodeIgniter container services in a seamless way from your libraries and custom classes.

All you need to do is to make your class extend ContainerAware and you can then immediately access all services just like you access them from within the controllers or models.

Makes it possible to transform the code from:

```
// The oldschool CodeIgniter way

class YourOldSchoolNastyLibrary
{
    public function myServiceMethod() {
        $CI = CI_Controller::getInstance(); // THAT IS NASTY
        $CI->load->library('email');

        // Autocomplete and method prediction does not work or requires additional hacks :(
        return $this->email->from('noreply@example.com')
                ->to('recipient@example.com')
                ->subject('Hello')
                ->body('Hello World!')
                ->sent();
    }
}
```

into code having no static calls in your method bodies:

```
// The PepisCMS way

class YourNewNiceLibrary extends ContainerAware
{
    public function myServiceMethod() {
        $this->load->library('email');

        // Autocomplete and method prediction works out of the box :)
        return $this->email->from('noreply@example.com')
                ->to('recipient@example.com')
                ->subject('Hello')
                ->body('Hello World!')
                ->sent();
    }
}
```

If you can't (or don't want) to extend the ContainerAware class then you can implement your own *magic method* `\_\_get()' and to reuse a static helper provided by [ContainerAware](./pepiscms/application/classes/ContainerAware.php):

```
class YourNewNiceAlternativeLibrary
{
    public function __get($var)
    {
        return ContainerAware::__doGet($var);
    }

    public function myServiceMethod() {
        $this->load->library('email');

        // Autocomplete and method prediction does not work out of the box :(
        return $this->email->from('noreply@example.com')
                ->to('recipient@example.com')
                ->subject('Hello')
                ->body('Hello World!')
                ->sent();
    }
}
```

Simplified domain model
-----------------------

[](#simplified-domain-model)

[![Simplified domain model](docs/screens/SIMPLIFIED_DOMAIN_MODEL.png)](docs/screens/SIMPLIFIED_DOMAIN_MODEL.png)

Application helpers
-------------------

[](#application-helpers)

Below the list of the PepisCMS helpers:

- [dialog\_message](./pepiscms/application/helpers/dialog_message_helper.php)dialog / UI related functions.

    - `display_error($message)`
    - `display_warning($message)`
    - `display_notification($message)`
    - `display_success($message)`
    - `display_tip($message)`
    - `display_breadcrumb($breadcrumb_array, $icon = false)`
    - `display_session_message()` - Renders and prints session flash message.
    - `get_warning_begin()`
    - `get_warning_end()`
    - `display_steps($steps, $type)`
    - `display_steps_circle($steps)`
    - `display_steps_dot($steps)`
    - `display_action_bar($actions)`
    - `button_generic($label, $url, $icon_path, $extra_classes = '', $id = false)`
    - `button_cancel($url = '#', $extra_classes = '', $id = false, $label = false)`
    - `button_back($url = '#', $extra_classes = '', $id = false, $label = false)`
    - `button_next($url = '#', $extra_classes = '', $id = false, $label = false)`
    - `button_previous($url = '#', $extra_classes = '', $id = false, $label = false)`
    - `button_apply($extra_classes = '', $id = false, $label = false)`
    - `button_save($extra_classes = '', $id = false, $label = false)`
    - `dashboard_box($name, $url, $icon_path = false, $description = false, $is_popup = false, $target = false)`
    - `display_confirmation_box($message, $explanation = '')`
    - `display_error_box($message, $explanation = '')`
- [email\_html](./pepiscms/application/helpers/email_html_helper.php)functions that ease building HTML system emails.

    - `email_html_open($padding = 20)`
    - `email_html_close()`
    - `email_h1_open()`
    - `email_h1_close()`
    - `email_h2_open()`
    - `email_h2_close()`
    - `email_p_open()`
    - `email_p_close()`
    - `email_a_open($url)`
    - `email_a_close()`
    - `email_html_footer_open($padding=0, $margin_top=40)`
    - `email_html_footer_close()`
- [google\_maps](./pepiscms/application/helpers/google_maps_helper.php)functions for getting coordinates for a given address.

    - `google_maps_locate($address)` - Returns an array (lat, lng) representing coordinates of a given address.
- [mysqldump](./pepiscms/application/helpers/mysqldump_helper.php)functions for creating backups from MYSQL database.

    - ` mysqldump($db_host, $database, $db_user, $db_password, $tables = false, $dump_to_filename = false, $dump_structure = true)` - Dumps MySQL database to file.
- [os](./pepiscms/application/helpers/os_helper.php)functions for detecting Windows systems.

    - `is_windows()`
- [path](./pepiscms/application/helpers/path_helper.php)path helper functions.

    - `module_path($module_name = false)`
- [popup](./pepiscms/application/helpers/popup_helper.php)popup / UI related functions.

    - `popup_close_html()` - Returns string used to close popup window.
- [youtube](./pepiscms/application/helpers/youtube_helper.php)YouTube URL parsing functions.

    - `youtube_get_id_by_url($url)` - Extracts YouTube ID from YouTube video URL.

CodeIgniter helpers customization or extension:

- [PEPISCMS\_date](./pepiscms/application/helpers/PEPISCMS_date_helper.php)extension to CodeIgniter date helper.

    - `utc_timestamp()` - Generates a timestamp value compatible with MySQL UTC\_TIMESTAMP function.
    - `date_spectrum($today_time, $days_before = 30)` - Generates a date spectrum from days before to now.
    - `fill_date_spectrum_values($values, $today_time, $days_before = 30, $default_value = 0)` - Takes values map and makes sure there are no date gaps.
- [PEPISCMS\_string](./pepiscms/application/helpers/PEPISCMS_string_helper.php)extension to CodeIgniter string helper.

    - `niceuri($name)` - Generates a URL friendly string that can be used as URL slug (URL id). Supports Cyrillic as well.
    - `shortname($name, $maxlength = 60, $separator = '...')` - Generates a shortened string, inserts ... in the middle of the shortened value.
    - `remove\_separators($str)' - Returns string with all word separators removed (space, dash, minus, plus).
- [PEPISCMS\_url](./pepiscms/application/helpers/PEPISCMS_url_helper.php)extension to CodeIgniter url helper.

    - `admin_url($is_absolute = true)` - Returns base URL for admin.
    - `module_url($module_name = false)` - Returns relative admin module base URL. If no module is specified, the currently running module is used.
    - `module_resources_url($module_name = false)` - Returns relative module public resources URL for the specified module. If no module is specified, the currently running module is used.
    - `site_theme_url($theme_name = false)` - Returns relative theme path. If no theme is specified then the system configured theme is used.
    - `module_icon_small_url($module_name = false)` - Returns admin module icon URL. If no module is specified, the currently running module is used.
    - `current_url()` - Returns absolute URL for the current request.

Benchmarking
------------

[](#benchmarking)

PepisCMS was designed with small memory footprint and processing power in mind.

To enable profiler please change the following property:

```
// application/config.php

$config['enable_profiler'] = TRUE;
```

You might observe that for concurrent requests access check and menu rendering is skipped.

Changes comparing to CodeIgniter
--------------------------------

[](#changes-comparing-to-codeigniter)

ChangeDescriptionModularityThe system provides a way to break the components of the application in separate independent modules. The core of the project can be upgraded independent of the modules as long as its API is compatible.Extended ControllerModularity support, several types of controllersExtended ConfigModularity supportExtended LoaderAdded possibility to load themes Modularity support Helper methods like `resolveModuleDirectory()`Extended LangIntegration with the translator hook Added helper method `getCurrentLanguage()` Added support for modularityExtended OutputOverwritten cache mechanismExtended URIAdded possibility to shift URI componentsExtended UploadAdded possibility to accept any file type by setting accepted\_file\_types to "\*" Skipped image size checkExtended ValidationAdded custom validation methods.ContainerAwareMakes it possible to write any library just like if you were writing controller code.Enabling library and models autocomplete prediction
---------------------------------------------------

[](#enabling-library-and-models-autocomplete-prediction)

Autocomplete and method prediction works out of the box for classes that extend either [EnhancedController](./pepiscms/application/classes/EnhancedController.php)(all PepisCMS controller types), [Generic\_model](./pepiscms/application/models/Generic_model.php)and [ContainerAware](./pepiscms/application/classes/ContainerAware.php).

This is obtained by adding `@property` annotations to the above mentioned classes.

### Generating project headers manually

[](#generating-project-headers-manually)

To regenerate libraries and models definition and enable autocomplete predictions for CodeIgniter in PepisCMS you need to:

1. Install [Development tools](#development-tools) module and navigate to the module's dashboard [![Autocomplete](docs/screens/ENABLING_LIBRARY_AND_MODELS_AUTOCOMPLETE_PREDICTION_1.png)](docs/screens/ENABLING_LIBRARY_AND_MODELS_AUTOCOMPLETE_PREDICTION_1.png)
2. Generate *headers* file, the action will generate a definition file located under `application/dev/_project_headers.php`[![_project_headers.php](docs/screens/ENABLING_LIBRARY_AND_MODELS_AUTOCOMPLETE_PREDICTION_2.png)](docs/screens/ENABLING_LIBRARY_AND_MODELS_AUTOCOMPLETE_PREDICTION_2.png)
3. Mark CodeIgniter Controller.php and Model.php as text (`Right click -> Mark as plaintext`). The files paths are `vendor/codeigniter/framework/system/core/Controller.php`and `vendor/codeigniter/framework/system/core/Model.php` respectively.
4. Benefit from autocomplete predictions and code suggestions :) [![Autocomplete](docs/screens/ENABLING_LIBRARY_AND_MODELS_AUTOCOMPLETE_PREDICTION_3.png)](docs/screens/ENABLING_LIBRARY_AND_MODELS_AUTOCOMPLETE_PREDICTION_3.png)

Optional libraries
------------------

[](#optional-libraries)

### PHPExcel for Excel spreadsheet import/export

[](#phpexcel-for-excel-spreadsheet-importexport)

PHPSpreadsheet bridge library is not provided by default. To enable support for Excel file import/export please add the missing dependency. Once the library is present in the classmap, the Excel support capabilities will automatically be enabled. Excel support can be enabled at any point.

```
composer require phpoffice/phpspreadsheet 1.5.* --update-no-dev
```

### PHPCas for CAS authentication

[](#phpcas-for-cas-authentication)

PHPCas bridge library is not provided by default. To enable CAS support, please install PHPCas library **prior to PepisCMS setup configuration**.

```
composer require jasig/phpcas 1.3.5 --update-no-dev
```

### Enabling Symfony bridge

[](#enabling-symfony-bridge)

Symfony bridge library is not provided by default. Symfony bridge can be enabled at any point.

```
composer require piotrpolak/codeigniter-symfony2-bridge --update-no-dev
```

### Enabling Twig support

[](#enabling-twig-support)

```
composer require twig/twig 1.* --update-no-dev
```

Icon set
--------

[](#icon-set)

Farm Fresh Icons Pack  licensed under [Creative Commons Attribution 4.0 License](https://creativecommons.org/licenses/by/4.0/).

###  Health Score

31

—

LowBetter than 68% of packages

Maintenance26

Infrequent updates — may be unmaintained

Popularity15

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~394 days

Total

5

Last Release

1111d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7e8806a7475dd55dcf06f23489a27df7fa2b907697bbca65f294acdc37548593?d=identicon)[piotrpolak](/maintainers/piotrpolak)

---

Top Contributors

[![piotrpolak](https://avatars.githubusercontent.com/u/1048408?v=4)](https://github.com/piotrpolak "piotrpolak (466 commits)")

---

Tags

cmscodeignitercomposerlong-term-supportltsphp

###  Code Quality

TestsBehat

### Embed Badge

![Health badge](/badges/piotrpolak-pepiscms/health.svg)

```
[![Health](https://phpackages.com/badges/piotrpolak-pepiscms/health.svg)](https://phpackages.com/packages/piotrpolak-pepiscms)
```

###  Alternatives

[microweber/microweber

New generation CMS with drag and drop

3.4k13.8k1](/packages/microweber-microweber)[pods-framework/pods

Pods is a development framework for creating, extending, managing, and deploying customized content types in WordPress.

1.1k1.7k](/packages/pods-framework-pods)[pradosoft/prado

Component Framework for PHP

19185.2k16](/packages/pradosoft-prado)[stenope/stenope

Static site builder for Symfony

13518.6k](/packages/stenope-stenope)[chameleon-system/chameleon-base

The Chameleon System core.

1026.5k3](/packages/chameleon-system-chameleon-base)[erdiko/core

Erdiko micro MVC core libraries

192.5k4](/packages/erdiko-core)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
