Configuration
Configuring a CakePHP application is a piece of cake. After you have installed CakePHP, creating a basic web application requires only that you setup a database configuration.
There are, however, other optional configuration steps you can take in order to take advantage of CakePHP flexible architecture. You can easily add to the functionality inherited from the CakePHP core, configure additional/different URL mappings (routes), and define additional/different inflections.
The application's configuration files live in the config/ directory of your project:
config/core.php- core settings such as debug level, error handling, sessions, security salts and the internal caches.config/bootstrap.php- application bootstrapping: cache configurations, log configurations, plugin loading, custom inflections.config/database.php- database connections (copy it fromconfig/database.php.default).config/routes.php- URL routing.config/email.php- email transport configurations (copy it fromconfig/email.php.default).config/acl.php,config/acl.ini.php- ACL settings.config/Schema/- schema files, e.g. for database sessions and i18n.
The CONFIG constant points to this directory. In the legacy layout the same files are in app/Config/, and CONFIG points there when the project has no top-level config/ directory. See CakePHP Folder Structure for both layouts.
database.php, database.php.default
Database Configuration
CakePHP expects database configuration details to be in a file at config/database.php. An example database configuration file can be found at config/database.php.default. A finished configuration should look something like this:
// config/database.php
class DATABASE_CONFIG
{
public $default = [
'datasource' => 'Database/Mysql',
'persistent' => false,
'host' => 'localhost',
'login' => 'cakephpuser',
'password' => 'c4k3roxx!',
'database' => 'my_cakephp_project',
'prefix' => '',
'encoding' => 'utf8mb4',
];
}The $default connection array is used unless another connection is specified by the $useDbConfig property in a model. For example, if my application has an additional legacy database in addition to the default one, I could use it in my models by creating a new $legacy database connection array similar to the $default array, and by setting public $useDbConfig = 'legacy'; in the appropriate models.
Fill out the key/value pairs in the configuration array to best suit your needs.
A connection can also be set with one DSN (a URL) in the 'dsn' key, for example 'dsn' => env('DATABASE_URL'). The config/database.php.default file of the application skeleton reads DATABASE_URL, which is the test database in the tests. See Database DSNs and Environment Variables.
dsn (optional)
A DSN such as mysql://user:password@localhost/my_app?encoding=utf8mb4 that sets the datasource and the connection keys in one string. See Database DSNs. Added in v2.12.7.
datasource
The name of the datasource this configuration array is for. The built-in database drivers are Database/Mysql, Database/Postgres, Database/Sqlite and Database/Sqlserver. All of them use PDO, so the matching PDO extension (pdo_mysql, pdo_pgsql, pdo_sqlite or pdo_sqlsrv) must be installed. You can use plugin syntax to indicate plugin datasource to use.
persistent
Whether or not to use a persistent connection to the database. The Sqlserver datasource does not support persistent connections and throws an exception if this is set to true.
host
The database server's hostname (or IP address).
login
The username for the account.
password
The password for the account.
database
The name of the database for this connection to use.
prefix (optional)
The string that prefixes every table name in the database. If your tables don't have prefixes, set this to an empty string.
port (optional)
The TCP port or Unix socket used to connect to the server. For SQL Server the port is appended to the host when connecting.
encoding
Indicates the character set to use for the connection. This defaults to the database's default encoding. If you wish to use UTF-8 encoding with MySQL you must use 'utf8' or 'utf8mb4' without the hyphen. The character set is passed in the PDO DSN when connecting (charset=... for MySQL, options='--client_encoding=...' for PostgreSQL), so no SET NAMES query is needed. For SQL Server, 'utf8' selects the driver's UTF-8 encoding.
flags (optional)
An array of PDO attributes passed to the PDO constructor. As of PHP 8.1, the MySQL and SQLite PDO drivers return integer and float columns as PHP integers and floats. If your application relies on the old behavior of receiving strings, set 'flags' => [PDO::ATTR_STRINGIFY_FETCHES => true].
schema
The schema to use. Used by PostgreSQL (defaults to public) and SQL Server (defaults to dbo).
sslmode (optional)
PostgreSQL only. The sslmode value added to the DSN, e.g. 'require'.
options (optional)
SQL Server only. An array of additional connection options that are added to the DSN, e.g. ['TrustServerCertificate' => 'yes', 'Encrypt' => 'no'].
Piece of Cake 2 fork
The Sqlserver datasource targets SQL Server 2022 and newer. It reads the port from port, defaults schema to dbo and accepts SSL/TLS settings in the options array. See the Migrating from CakePHP 2.10.
unix_socket
Used by drivers that support it to connect via unix socket files. If you are using PostgreSQL and want to use unix sockets, leave the host key blank.
ssl_key
The file path to the SSL key file. Must be combined with ssl_cert. (Only supported by MySQL.)
ssl_cert
The file path to the SSL certificate file. Must be combined with ssl_key. (Only supported by MySQL.)
ssl_ca
The file path to the SSL certificate authority. (Only supported by MySQL.)
settings
An array of key/value pairs that should be sent to the database server as SET commands when the connection is created. This option is only supported by the Mysql, Postgres, and Sqlserver datasources at this time.
Changed in version 2.4
The settings, ssl_key, ssl_cert and ssl_ca keys was added in 2.4.
NOTE
The prefix setting is for tables, not models. For example, if you create a join table for your Apple and Flavor models, you name it prefix_apples_flavors (not prefix_apples_prefix_flavors), and set your prefix setting to 'prefix_'.
At this point, you might want to take a look at the CakePHP Conventions. The correct naming for your tables (and the addition of some columns) can score you some free functionality and help you avoid configuration. For example, if you name your database table big_boxes, your model BigBox, your controller BigBoxesController, everything just works together automatically. By convention, use underscores, lower case, and plural forms for your database table names - for example: bakers, pastry_stores, and savory_cakes.
Database DSNs
Piece of Cake 2 fork
The 'dsn' key was added in v2.12.7; earlier releases ignore it silently. It is a backport of the DSN support of CakePHP 3.x and later, where the key is called url, and uses the DATABASE_URL format of CakePHP, Doctrine and Symfony.
A connection can be set with one DSN in the 'dsn' key. This keeps the credentials of each environment in one environment variable. Leave out of the array the keys that the DSN sets (datasource, host, port, login, password and database), and keep only the other settings:
// config/database.php
class DATABASE_CONFIG
{
public $default = [
'persistent' => false,
'prefix' => '',
];
public function __construct()
{
// Property defaults cannot call functions, so set the DSN here
$this->default['dsn'] = env('DATABASE_URL');
}
}# config/.env.local
DATABASE_URL="mysql://my_app:secret@127.0.0.1:3306/my_app?encoding=utf8mb4"The DSN is parsed when the connection is created (the first ConnectionManager::getDataSource() call, usually the first query), and its parts are mapped to the connection keys:
| DSN part | Connection key |
|---|---|
scheme mysql | datasource Database/Mysql |
scheme postgres, postgresql or pgsql | datasource Database/Postgres |
scheme sqlite | datasource Database/Sqlite |
scheme sqlserver, mssql or sqlsrv | datasource Database/Sqlserver |
| user and password | login and password |
| host and port | host (without the brackets of an IPv6 address) and port |
path, without the leading / | database |
| query parameters | keys of the same name |
For example:
# MySQL
DATABASE_URL="mysql://user:password@localhost:3306/my_app?encoding=utf8mb4"
# PostgreSQL
DATABASE_URL="postgres://user:password@localhost:5432/my_app?schema=public"
# SQLite in memory
DATABASE_URL="sqlite:///:memory:"
# SQLite file, relative to the working directory (three slashes)
DATABASE_URL="sqlite:///tmp/my_app.sqlite"
# SQLite file, absolute path (four slashes)
DATABASE_URL="sqlite:////var/db/my_app.sqlite"
# SQL Server
DATABASE_URL="sqlserver://user:password@localhost:1433/my_app?encoding=utf8&options[TrustServerCertificate]=yes"- Precedence: The keys taken from the DSN replace the same keys of the array, and the other keys of the array are kept, as in CakePHP 3.x and later. The array therefore holds the defaults (
persistent,prefix,encoding, ...) and the DSN decides the connection. A DSN without a password keeps thepasswordof the array; writeuser:@hostfor an empty password. - Empty values: A
'dsn'that isnull,''orfalseis ignored, soenv('DATABASE_URL')falls back to the array when the variable is not set. The'dsn'key itself is removed from the configuration that the datasource gets. - Encoding: The user, password, host and database are URL-decoded. Encode reserved characters of a password:
%40for@,%3Ffor?,%23for#and%25for%. - Query parameters: They become keys as they are, e.g.
encoding,schema,prefix,persistent=true,flags[1002]=SET%20NAMES%20utf8mb4oroptions[Encrypt]=no. The valuestrue,falseandnullbecome the PHP values.datasource=MyPlugin.Database/Customoverrides the datasource of the scheme and also allows a scheme that is not registered.1002inflags[1002]is the value ofPDO::MYSQL_ATTR_INIT_COMMAND; a DSN cannot contain constant names. - IPv6: Write the host in brackets, e.g.
mysql://user:password@[::1]:3306/my_app. - Errors: An invalid DSN or an unknown scheme throws a
CakeExceptionthat names the connection. The message does not contain the user name or password. - Schemes of plugins: A plugin can add schemes, or replace the built-in ones, with
ConnectionManager::setDsnClassMap(). See Registering DSN Schemes.
The 'dsn' key also works with ConnectionManager::create(), and ConnectionManager::parseDsn() returns the keys of a DSN:
ConnectionManager::create('reporting', ['dsn' => env('REPORTING_DATABASE_URL')]);
ConnectionManager::parseDsn('postgres://user:secret@db:5432/app');
// ['login' => 'user', 'password' => 'secret', 'host' => 'db', 'port' => '5432',
// 'database' => 'app', 'datasource' => 'Database/Postgres']Environment Variables
Settings that differ between environments, such as the debug level, the security salts and the database credentials, can be read from environment variables with env() instead of being written into the configuration files. In production, set the variables in the configuration of the web server, container or process manager. For local development, the application skeleton can load them from a .env file.
Loading .env Files
Applications created from the pieceofcake2/app skeleton load environment variables from .env files in config/ at the top of config/core.php, with symfony/dotenv, as a Symfony application does. Because config/core.php is read first, the variables are available to the rest of the configuration, the console and the tests:
// config/core.php
use Symfony\Component\Dotenv\Dotenv;
(new Dotenv())->usePutenv()->loadEnv(CONFIG . '.env');The CakePHP 3+/5 application skeleton (cakephp/app) also loads config/.env in the application, not in the framework. As in CakePHP 5, the framework itself does not load .env files.
Piece of Cake 2 fork
.env loading is part of the pieceofcake2/app skeleton since v2.4.0. Since v2.5.0, it uses symfony/dotenv and the files described here. Earlier versions use josegonzalez/dotenv and also read .env files in the project root: v2.4.2 loads only the first file that exists, v2.4.1 merges the files with the earlier file winning, and v2.4.0 loads config/.env and the root .env. See Migrating from an Earlier Skeleton to switch. For other applications, see Adding .env Support to an Existing Application.
loadEnv() loads these files in this order and merges them, so a later file wins over an earlier one:
| File | Loaded | In Git |
|---|---|---|
config/.env | always (required) | committed: the defaults of the application |
config/.env.local | except when APP_ENV is test | ignored: the values of your machine |
config/.env.{APP_ENV}, e.g. config/.env.test | always | committed: the defaults of an environment |
config/.env.{APP_ENV}.local | always | ignored: the values of your machine for that environment |
- A variable that is set in the real environment (web server, shell, container, CI) is never overwritten, so real environment variables win over all files.
APP_ENVis read from the real environment, otherwise from the files: the skeleton'sconfig/.envsetsAPP_ENV=dev.vendor/bin/phpunit,bin/cake testandwebroot/test.phpsetAPP_ENV=testwhen it is not set, so the tests loadconfig/.env.test, which pointsDATABASE_URLto the test database (see Testing). In production, setAPP_ENV=prodas a real environment variable.config/.envmust exist. The skeleton ships it, with the defaults for development; commit it. The.localfiles hold only what differs on your machine, such as your database and the salts.
The loaded values are written to $_SERVER, $_ENV and putenv() as strings, so you can read them with env(), getenv(), $_SERVER or $_ENV:
// config/core.php
Configure::write('Security.salt', env('SECURITY_SALT') ?: 'a-default-salt');As in Symfony, only the .local files are listed in the skeleton's .gitignore: config/.env.local and config/.env.*.local. config/.env and config/.env.test are committed. Never put real secrets in a committed file: keep them in a .local file or in real environment variables.
A .env file is meant for development and tests. In production, set APP_ENV=prod and the other settings as real environment variables in the web server, container or process manager configuration; they always take precedence over the files.
.env File Syntax
A .env file contains one NAME=value assignment per line, the common dotenv style also used by Symfony and Laravel. Lines starting with # are comments, and an export prefix is accepted:
# config/.env.local
APP_DEBUG=2
SECURITY_SALT=a-long-random-string
DATABASE_URL="mysql://my_app:secret@127.0.0.1:3306/my_app"symfony/dotenv keeps all values as strings. Quote a value that contains spaces. In unquoted and double-quoted values, $NAME and ${NAME} are replaced with the value of a variable (${NAME:-default} gives a default); single-quoted values are kept as they are, so single-quote a password that contains $.
Adding .env Support to an Existing Application
Applications that use the legacy app/ layout, or that were created from an earlier version of the skeleton, can load .env files the same way. Install the library:
composer require symfony/dotenvThen add the following code at the top of app/Config/core.php (config/core.php in the modern layout): the use statement after the opening file comment, and the loadEnv() call before the first Configure::write() call. In the legacy layout, CONFIG is app/Config/, so the files are app/Config/.env, app/Config/.env.local and so on.
// app/Config/core.php
use Symfony\Component\Dotenv\Dotenv;
(new Dotenv())->usePutenv()->loadEnv(CONFIG . '.env');Create app/Config/.env with the defaults (it is required, and can be empty) and commit it, add the .local files to .gitignore, and read the variables in your configuration with env(), as shown in the next section. usePutenv() also writes the values with putenv(), so that getenv() returns them.
Environment Variables of the Application Skeleton
The config/core.php, config/bootstrap.php, config/database.php.default and config/email.php.default files of the pieceofcake2/app skeleton read the following variables. Its config/.env file lists them.
| Variable | Setting | When not set |
|---|---|---|
APP_ENV | the environment (dev, test or prod): selects config/.env.{APP_ENV}; test by default for vendor/bin/phpunit, bin/cake test and webroot/test.php | dev, from config/.env |
APP_DEBUG | debug (0, 1, 2) | 0 |
SECURITY_SALT | Security.salt | the value in config/core.php |
SECURITY_CIPHER_SEED | Security.cipherSeed (1 to 4294967295; see cipherSeed) | the value in config/core.php |
COOKIE_KEY | Cookie.key, the CookieComponent key for the 'aes' type (see Migrating to 'aes') | null: CookieComponent uses Security.salt |
DATABASE_URL | the 'dsn' of the default and test connections (see Database DSNs) | the values in config/database.php |
MAILER_DSN | the 'dsn' of the default email profile (see Mailer DSN) | the values in config/email.php |
Empty variables are treated as not set. The keys of a DSN replace the same keys of the configuration, and the other keys are kept as defaults. The 'dsn' key needs pieceofcake2/cakephp 2.12.7 or later.
The skeleton reads the debug level in one line, and uses debug level 0 when APP_DEBUG is not set:
// config/core.php
Configure::write('debug', env('APP_DEBUG') ?? 0);If your config/database.php or config/email.php was created from an earlier skeleton, copy the __construct() method of config/database.php.default or config/email.php.default into it, and remove an APP_ENV branch that used the test connection as default (config/.env.test sets DATABASE_URL to the test database instead). Copy the APP_ENV default of tests/bootstrap.php, bin/cake and webroot/test.php from the skeleton too. Earlier skeletons read the DB_DATASOURCE, DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD and DB_DATABASE variables (and DB_TEST_* for the test connection) with an applyEnv() method; one DATABASE_URL replaces them:
# Before
DB_HOST="127.0.0.1"
DB_USERNAME="my_app"
DB_PASSWORD="secret"
DB_DATABASE="my_app"
# After
DATABASE_URL="mysql://my_app:secret@127.0.0.1/my_app"For example, a config/.env.local file with the settings of your machine:
# config/.env.local
DATABASE_URL="mysql://my_app:secret@127.0.0.1:3306/my_app?encoding=utf8mb4"
MAILER_DSN="smtp://127.0.0.1:1025"and a config/.env.test.local file with the test database of your machine, which is loaded after config/.env.test in the tests:
# config/.env.test.local
DATABASE_URL="mysql://my_app:secret@127.0.0.1:3306/test_my_app?encoding=utf8mb4"Class Loading and Additional Class Paths
CakePHP framework classes are loaded by Composer's autoloader, so you never need App::uses() for them. Your own classes can be autoloaded the same way by adding a classmap to your application's composer.json, as the pieceofcake2/app skeleton does:
"autoload": {
"classmap": ["src/"]
}With this in place, remove the App::uses() calls for your controllers, models, helpers and other classes in src/: App::uses() is deprecated as of 2.13.0. Run composer dump-autoload every time you add a new class file, so that the classmap includes it. For a plugin that Composer does not autoload, add its folder to the classmap of your application instead of calling App::uses(). See Removing App::uses() calls.
Piece of Cake 2 fork
The framework is loaded through Composer's classmap instead of include paths and its own App::uses() calls were removed. Application code that still uses App::uses() keeps working.
App::uses() and App::build() are still available. When App::uses() or a setting names a class, CakePHP looks for it in the application directory (src/, or app/ in the legacy layout). Templates are also found in templates/, locales in resources/locales/ and plugins in plugins/.
It's occasionally useful to be able to share MVC classes between applications on the same system. If you want the same controller in both applications, you can use CakePHP's config/bootstrap.php to bring these additional classes into view.
By using App::build() in config/bootstrap.php we can define additional paths where CakePHP will look for classes:
App::build([
'Model' => [
'/path/to/models',
'/next/path/to/models',
],
'Model/Behavior' => [
'/path/to/behaviors',
'/next/path/to/behaviors',
],
'Model/Datasource' => [
'/path/to/datasources',
'/next/path/to/datasources',
],
'Model/Datasource/Database' => [
'/path/to/databases',
'/next/path/to/database',
],
'Model/Datasource/Session' => [
'/path/to/sessions',
'/next/path/to/sessions',
],
'Controller' => [
'/path/to/controllers',
'/next/path/to/controllers',
],
'Controller/Component' => [
'/path/to/components',
'/next/path/to/components',
],
'Controller/Component/Auth' => [
'/path/to/auths',
'/next/path/to/auths',
],
'Controller/Component/Acl' => [
'/path/to/acls',
'/next/path/to/acls',
],
'View' => [
'/path/to/views',
'/next/path/to/views',
],
'View/Helper' => [
'/path/to/helpers',
'/next/path/to/helpers',
],
'Console' => [
'/path/to/consoles',
'/next/path/to/consoles',
],
'Console/Command' => [
'/path/to/commands',
'/next/path/to/commands',
],
'Console/Command/Task' => [
'/path/to/tasks',
'/next/path/to/tasks',
],
'Lib' => [
'/path/to/libs',
'/next/path/to/libs',
],
'Locale' => [
'/path/to/locales',
'/next/path/to/locales',
],
'Vendor' => [
'/path/to/vendors',
'/next/path/to/vendors',
],
'Plugin' => [
'/path/to/plugins',
'/next/path/to/plugins',
],
]);NOTE
All additional path configuration should be done at the top of your application's bootstrap.php. This will ensure that the paths are available for the rest of your application.
core.php, configuration
Core Configuration
Each application in CakePHP contains a configuration file, config/core.php, to determine CakePHP's internal behavior. This file is a collection of Configure class variable definitions and constant definitions that determine how your application behaves. Before we dive into those particular variables, you'll need to be familiar with Configure, CakePHP's configuration registry class.
CakePHP Core Configuration
The Configure class is used to manage a set of core CakePHP configuration variables. These variables can be found in config/core.php. Below is a description of each variable and how it affects your CakePHP application.
debug
Changes CakePHP debugging output.
- 0 = Production mode. No output.
- 1 = Show errors and warnings.
- 2 = Show errors, warnings, and SQL. [SQL log is only shown when you add $this->element('sql_dump') to your view or layout.]
The application skeleton reads the debug level from the APP_DEBUG environment variable. See Environment Variables.
Error
Configure the Error handler used to handle errors for your application. By default ErrorHandler::handleError() is used. It will display errors using Debugger, when debug > 0 and log errors with CakeLog when debug = 0.
Sub-keys:
handler- callback - The callback to handle errors. You can set this to any callback type, including anonymous functions.level- int - The level of errors you are interested in capturing.trace- boolean - Include stack traces for errors in log files.
Exception
Configure the Exception handler used for uncaught exceptions. By default, ErrorHandler::handleException() is used. It will display a HTML page for the exception, and while debug > 0, framework errors like Missing Controller will be displayed. When debug = 0, framework errors will be coerced into generic HTTP errors. For more information on Exception handling, see the Exceptions section.
App.baseUrl
If you don't want or can't get mod_rewrite (or some other compatible module) up and running on your server, you'll need to use CakePHP's built-in pretty URLs. In config/core.php, uncomment the line that looks like:
Configure::write('App.baseUrl', env('SCRIPT_NAME'));Also remove the webroot/.htaccess file. In the legacy layout, remove these .htaccess files:
/.htaccess
/app/.htaccess
/app/webroot/.htaccess
Keep the document root set to webroot/ (app/webroot/). Without the .htaccess files, a document root that points to the project directory exposes the configuration, logs and source code; see Deployment.
This will make your URLs look like www.example.com/index.php/controllername/actionname/param rather than www.example.com/controllername/actionname/param.
If you are installing CakePHP on a webserver besides Apache, you can find instructions for getting URL rewriting working for other servers under the Web Server Configuration section.
App.fullBaseUrl
The fully qualified domain name (including protocol) to your application’s root. To configure CakePHP to use a particular domain URL for any URL generation inside the application, set this configuration variable. This will override the automatic detection of full base URL and can be useful when generating links from the CLI (e.g. sending emails). If the application runs in a subfolder, you should also set App.base.
App.base
The base directory the app resides in. Should be used if the application runs in a subfolder and App.fullBaseUrl is set.
App.encoding
Define what encoding your application uses. This encoding is used to generate the charset in the layout, and encode entities. It should match the encoding values specified for your database.
Routing.prefixes
Un-comment this definition if you'd like to take advantage of CakePHP prefixed routes like admin. Set this variable with an array of prefix names of the routes you'd like to use. More on this later.
Cache.disable
When set to true, persistent caching is disabled site-wide. This will make all read/writes to Cache fail.
Cache.check
If set to true, enables view caching. Enabling is still needed in the controllers, but this variable enables the detection of those settings.
Session
Contains an array of settings to use for session configuration. The defaults key is used to define a default preset to use for sessions, any settings declared here will override the settings of the default config.
Sub-keys
cookie- The name of the cookie to use. Defaults to 'CAKEPHP'timeout- The number of minutes you want sessions to live for. This timeout is handled by CakePHPcookieTimeout- The number of minutes you want session cookies to live for.checkAgent- Do you want the user agent to be checked when starting sessions? You might want to set the value to false for clients that change their user agent string during a session.defaults- The default configuration set to use as a basis for your session. There are four builtins: php, cake, cache, database.handler- Can be used to enable a custom session handler. Expects an array of callables, that can be used withsession_save_handler, or an array with anenginekey naming a class that implementsCakeSessionHandlerInterface. Using this option will automatically addsession.save_handlerto the ini array.autoRegenerate- Enabling this setting, turns on automatic renewal of sessions, and sessionids that change frequently. SeeCakeSession::$requestCountdown.cacheLimiter- The cache control headers used for the session cookie. See session_cache_limiter() for accepted values.ini- An associative array of additional ini values to set.
The built-in defaults are:
- 'php' - Uses settings defined in your
php.ini. - 'cake' - Saves session files in CakePHP's
tmp/sessionsdirectory. - 'database' - Uses CakePHP's database sessions.
- 'cache' - Use the Cache class to save sessions.
To define a custom session handler, save it at src/Model/Datasource/Session/<name>.php. Make sure the class implements CakeSessionHandlerInterface and set Session.handler.engine to <name>.
To use database sessions, create the table from the config/Schema/sessions.php schema using the cake shell command: bin/cake schema create Sessions
See Sessions for more details.
Security.salt
A random string used in security hashing. It is also used to sign CSRF tokens and form tampering tokens, and as the default key for CookieComponent. Change it to a secret value unique to your application; CakePHP shows a notice while the default value from the skeleton is in use. The skeleton reads it from the SECURITY_SALT environment variable when it is set. See Generating the Security Salts for how to generate it and what changing it affects.
Piece of Cake 2 fork
CSRF tokens issued by SecurityComponent are signed with an HMAC using Security.salt (CVE-2020-15400). Changing the salt invalidates outstanding tokens. See Security Fixes.
Security.cipherSeed
A random numeric string (digits only) used to encrypt/decrypt strings with Security::cipher(). That method is used only by the 'cipher' encryption type of CookieComponent, which is weak and kept for backwards compatibility. Use the 'aes' type for cookies instead, and make sure Security.useOpenSsl is true (the app skeleton sets it). The skeleton reads it from the SECURITY_CIPHER_SEED environment variable when it is set. Only numbers from 1 to 4294967295 are meaningful; longer values, including the 29-digit default of the original config/core.php, all end up as the same seed 0. No value makes the 'cipher' type secure. See cipherSeed and the 'cipher' Cookie Type.
Security.useOpenSsl
When true, Security::encrypt() and Security::decrypt() (and therefore the 'aes' cookie encryption type) use OpenSSL instead of mcrypt. The mcrypt extension is not bundled with PHP 7.2 and later, so enable it in config/core.php:
Configure::write('Security.useOpenSsl', true);The default is false. Applications created from the pieceofcake2/app skeleton (v2.3.1 and later) already have this line; add it to existing applications.
Asset.timestamp
Appends a timestamp which is last modified time of the particular file at the end of asset files URLs (CSS, JavaScript, Image) when using proper helpers. Valid values: (boolean) false - Doesn't do anything (default) (boolean) true - Appends the timestamp when debug > 0 (string) 'force' - Appends the timestamp when debug >= 0
Acl.classname, Acl.database
Constants used for CakePHP's Access Control List functionality. See the Access Control Lists chapter for more information.
NOTE
Cache configuration is also found in core.php — We'll be covering that later on, so stay tuned.
The Configure class can be used to read and write core configuration settings on the fly. This can be especially handy if you want to turn the debug setting on for a limited section of logic in your application, for instance.
Generating the Security Salts
Security.salt must be a secret value that is unique to each application. Generate it with a cryptographically secure random generator; do not type a value yourself or reuse a value from an example. The commands below work in any POSIX shell (sh, bash, zsh) on Linux and macOS.
Security.salt is 32 random bytes, written as 64 hexadecimal characters:
php -r 'echo bin2hex(random_bytes(32)), PHP_EOL;'openssl rand -hex 32Use a salt of at least 32 characters. It is the default key of CookieComponent, and the 'aes' encryption type (Security::encrypt()) throws an exception for keys shorter than 32 bytes.
Security.cipherSeed is used only by the legacy 'cipher' cookie type and must be a number from 1 to 4294967295. Longer values, including the 29-digit default of the original config/core.php, all end up as the same seed, and no value makes 'cipher' secure. Read cipherSeed and the 'cipher' Cookie Type before you set it.
On Windows, run the PHP commands in Command Prompt or PowerShell with double quotes instead of single quotes, for example php -r "echo bin2hex(random_bytes(32)), PHP_EOL;".
In an application created from the pieceofcake2/app skeleton, set the values as the SECURITY_SALT and SECURITY_CIPHER_SEEDenvironment variables. For development, this appends a salt and an in-range seed to config/.env.local, which is ignored by Git (when a variable is set twice, the last line wins):
php -r 'printf("SECURITY_SALT=\"%s\"\nSECURITY_CIPHER_SEED=\"%d\"\n", bin2hex(random_bytes(32)), random_int(1, 4294967295));' >> config/.env.localprintf 'SECURITY_SALT="%s"\nSECURITY_CIPHER_SEED="%s"\n' "$(openssl rand -hex 32)" "$(od -An -N4 -tu4 /dev/urandom | tr -dc 0-9)" >> config/.env.localKeep the values secret and separate:
- Use different values in each environment (development, staging, production) and in each application.
- Do not commit them. In the skeleton,
config/.env.localis ignored by Git, butconfig/.envis committed; in production, set real environment variables instead of using a.envfile. If you write the values inconfig/core.php, keep that file out of public repositories. - If a salt has been exposed (committed, shared, or left at the example value), replace it.
What Depends on the Salts
Changing Security.salt affects the following:
- Passwords hashed with the salt.
SimplePasswordHasher, the default password hasher ofFormAuthenticateandBasicAuthenticate, and the deprecatedAuthComponent::password()prepend the salt to the password (Security::hash()with$salt = true). Stored hashes no longer match, and users cannot log in. Bcrypt hashes (BlowfishPasswordHasher,Security::hash($password, 'blowfish')) do not use the salt and are not affected. - Encrypted cookies.
CookieComponentuses the salt as its key unless you set$this->Cookie->key, and the'aes'type also mixes the salt into its key even when you set your own key. Cookies written before the change can no longer be read, except'cipher'and'rijndael'cookies that use their own key. - Data encrypted with
Security::encrypt(). When$hmacSaltis not given, the salt is part of the encryption key, andSecurity::decrypt()returnsfalsefor values encrypted before the change. - Sessions. When
Session.checkAgentis notfalse(the default), the session stores a hash of the user agent and the salt, so existing sessions are discarded and users are logged out. - CSRF and form tampering tokens. Tokens issued by
SecurityComponentandFormHelperare signed with the salt. Forms rendered before the change are rejected once.
Security.cipherSeed is used only by Security::cipher(). Changing it makes values encrypted with Security::cipher() unreadable, which in practice means the cookies written by the default 'cipher' type of CookieComponent. See cipherSeed and the 'cipher' Cookie Type.
Rotating the Salts
Sessions, CSRF tokens and form tokens recover by themselves: users log in again and resubmit forms, so change the salt at a quiet time. Before you change it, move the long-lived values away from it:
Move salted password hashes to bcrypt (
'passwordHasher' => 'Blowfish'). A hash cannot be converted, so check the old hash when a user logs in and save a bcrypt hash of the password. Change the salt only after the salted hashes are gone, or ask the remaining users to reset their passwords.Re-encrypt stored values that were encrypted with
Security::encrypt()and the default$hmacSalt, passing the old salt toSecurity::decrypt(). Better, pass a dedicated$hmacSaltthat does not change withSecurity.salt:php$plain = Security::decrypt($encrypted, $key, $oldSalt); $encrypted = Security::encrypt($plain, $key, $hmacSalt);Encrypted cookies cannot be carried over: the
'aes'type mixesSecurity.saltinto its key, so its cookies become unreadable when the salt changes, and users with a remember-me cookie have to log in again once. If you still use the'cipher'type, move to'aes'with its own key at the same time, so that cookies are lost only once, and make sureSecurity.useOpenSslistrue(the app skeleton sets it; see Migrating to 'aes').
Other Secrets
- Keys that you pass to
Security::encrypt()andSecurity::decrypt(), or set as theCookieComponentkey, must be at least 32 bytes long. Generate them likeSecurity.salt, and read them into the configuration from environment variables, for exampleCookie.keyfromCOOKIE_KEY(see Migrating to 'aes'). - Database and email passwords and API keys belong in environment variables or in ignored files such as
config/database.phpandconfig/email.php, not in committed code.
cipherSeed and the 'cipher' Cookie Type
Security.cipherSeed is used only by Security::cipher(). In practice that means CookieComponent, whose default encryption type is 'cipher'. The 'cipher' type has always been documented as insecure and kept only for backwards compatibility. This section describes a known weakness of the seed, what it means for your application, and how to move to the 'aes' type.
How the Seed Is Used
Security::cipher() seeds PHP's Mersenne Twister generator with mt_srand((int)(float)$seed) and XORs the value with numbers drawn from mt_rand(). The key (Security.salt, unless you set the CookieComponent key) is mixed in as well.
mt_srand() takes a 32-bit seed, so only numbers from 1 to 4294967295 are meaningful. Longer values do not add anything:
- Values with more than 19 digits do not fit in a PHP integer, and the conversion loses bits.
- Every value with 27 or more digits, and about 95% of the values with 26 digits, ends up as seed
0.
Well-known values that end up as seed 0 include:
76859309657453542496749683645, the default value inconfig/core.phpof the original CakePHP 2 and of this fork up to v2.12.5, also used as the fallback in applications created from earlier versions of thepieceofcake2/appskeleton7485712659625147843639846751, the example value of the blog tutorial in the original book- the 30-digit values generated by the command that earlier versions of
config/.env.examplein thepieceofcake2/appskeleton suggested
An In-Range Seed Is Not Enough
A seed from 1 to 4294967295 avoids the collapse to 0, but it does not make 'cipher' secure:
- There are only about 4.3 billion seeds, so all of them can be tried.
- The keystream comes from Mersenne Twister, which is not a cryptographic generator, and the value is only XORed with it.
Security.salt(or theCookieComponentkey) is still mixed in, but that does not turn the construction into real encryption.
Do not rely on 'cipher' to keep a value secret, whatever the seed.
Impact
- Only values encrypted with
Security::cipher()are affected: cookies thatCookieComponentwrites with the'cipher'type (the default), and your own calls toSecurity::cipher(). The'aes'and'rijndael'cookie types,Security::encrypt(), password hashes, sessions and CSRF tokens do not use the seed. - In applications that use one of the values above, or any other value with 27 or more digits, the seed adds no secret at all, and every such application uses the same seed.
- Changing the seed to any other value makes existing
'cipher'cookies unreadable, in the same way as switching to'aes'does.
Which Should I Do?
- New applications: use the
'aes'type with its own key andSecurity.useOpenSslset totrue(the app skeleton sets it), as described in Migrating to 'aes', and never use'cipher'. - Existing applications with
'cipher'cookies: migrate to'aes'. Existing cookie values are lost once: for example, users who logged in with a remember-me cookie have to log in again, and preferences stored in cookies are reset. Follow the steps in Migrating to 'aes'. - Applications that must keep reading old cookies for a transition period: there is no seamless path. Old cookies stay readable only as long as you keep the old seed, which keeps the weakness. Setting an in-range seed changes the keystream as well, so old cookies become unreadable anyway, and
'cipher'is still not secure afterwards. Plan a date on which the cookies are lost once, and switch to'aes'on that date instead of only changing the seed. - Applications that do not use
CookieComponentorSecurity::cipher(), or that use only the'aes'type: nothing to do beyond settingSecurity.cipherSeedto a valid value from 1 to 4294967295.
Migrating to 'aes'
Generate a cookie key of 32 random bytes. Do not reuse
Security.salt:bashphp -r 'echo bin2hex(random_bytes(32)), PHP_EOL;'bashopenssl rand -hex 32Set it as the
COOKIE_KEYenvironment variable: inconfig/.env.localfor development, and as a real environment variable in production.Make sure
Security.useOpenSslistrue(the app skeleton sets it). The'aes'type usesSecurity::encrypt()andSecurity::decrypt(), which use OpenSSL only when this setting istrue; otherwise they callmcrypt, which does not exist on PHP 8, and'aes'cookies fail. Older applications may not have the line, so add it toconfig/core.php(see Enable OpenSSL):phpConfigure::write('Security.useOpenSsl', true);Configure the type and the key of
CookieComponent. How depends on the version ofpieceofcake2/cakephp; see below.
Piece of Cake 2 fork
Since v2.12.6, Cookie.type and Cookie.key can be set in configuration.
v2.12.6 and later: set them in config/core.php, next to the salts. No controller changes are needed. Newer versions of the pieceofcake2/app skeleton have these lines; add them if your config/core.php does not:
// config/core.php
/**
* Default encryption type and key of CookieComponent. The key is a random
* value of at least 32 bytes.
*
* The key can be set with the COOKIE_KEY environment variable.
*/
Configure::write('Cookie.type', 'aes');
Configure::write('Cookie.key', env('COOKIE_KEY') ?: null);CookieComponent uses the 'type' setting or $this->Cookie->type() first, then Cookie.type, then 'cipher'. For the key, it uses the 'key' setting or $this->Cookie->key first, then Cookie.key, then Security.salt.
v2.12.5 and earlier: CookieComponent does not read Cookie.type and Cookie.key, so the lines above have no effect on it. Keep the Cookie.key line in config/core.php, and pass the type and the key in the controller: the type in the component settings, and the key in beforeFilter(), before any cookie is read. Do this in AppController or in every controller that uses the component:
// src/Controller/AppController.php
public $components = [
'Cookie' => ['type' => 'aes'],
];
public function beforeFilter()
{
parent::beforeFilter();
$key = Configure::read('Cookie.key');
if ($key) {
$this->Cookie->key = $key;
}
}Assign the key only when it is set, because a null key would replace the default key and encryption would fail. The 'type' setting is honored since v2.12.3; on older versions, call $this->Cookie->type('aes'); in beforeFilter(). This code keeps working on v2.12.6 and later, because explicit settings take precedence.
The 'aes' type needs a key of at least 32 bytes. When COOKIE_KEY is not set, Cookie.key is null and the key is Security.salt. If the salt is shorter than 32 bytes, Security::encrypt() and Security::decrypt() throw a CakeException whenever an encrypted cookie is written or read.
Optionally, give the cookie a new name with
$this->Cookie->name, so that old'cipher'cookies are ignored instead of being decrypted with the new type. They expire by themselves.Deploy. Users with a remember-me cookie log in again once.
The 'aes' type uses Security::encrypt(), which also mixes Security.salt into the key. Changing the salt later still makes 'aes' cookies unreadable.
Generating a cipherSeed
Only if you still use 'cipher', set Security.cipherSeed to a number from 1 to 4294967295. This avoids the collapse to 0, but 'cipher' stays insecure, and changing the seed makes existing 'cipher' cookies unreadable:
php -r 'echo random_int(1, 4294967295), PHP_EOL;'od -An -N4 -tu4 /dev/urandom | tr -dc 0-9; echoWarnings Since v2.12.6
Piece of Cake 2 fork
Since v2.12.6, pieceofcake2/cakephp reports these problems without changing behaviour:
'cipher'is deprecated. The first use of the'cipher'type or ofSecurity::cipher()in a process (one request or one console run) writes awarningto the log, also when debug is off. With debug on, the same message is also triggered asE_USER_DEPRECATED. The message names the source and the fix: setCookie.typeto'aes'andCookie.keyto a random value of at least 32 bytes, withSecurity.useOpenSslenabled.- When
Security.cipherSeedis not a digits-only number from 1 to 4294967295, the firstSecurity::cipher()call in a process also logs awarning. The seed itself is never logged. With debug on,Debugger::checkSecurityKeys()(called byAuthComponent) also triggers anE_USER_NOTICEfor such a seed. - The fallback
config/core.phpof the core, used only when the application has noconfig/core.php, sets the in-range seed'2659758734'(the same default as the app skeleton) andSecurity.useOpenSsl. The notice asking you to change the defaultSecurity.cipherSeedfires for both the former default and this new one. Cookie.typeandCookie.keyset the default type and key ofCookieComponent(see Migrating to 'aes').
Values are encrypted and decrypted exactly as before, so existing cookies stay readable, and nothing throws. Do not change Security.cipherSeed only to silence the warning: a new seed makes existing 'cipher' cookies unreadable, and 'cipher' stays insecure with any seed. Switch to 'aes' instead.
If your test suite turns deprecations or notices into exceptions, the first 'cipher' use in a test run, or AuthComponent with debug on and an out-of-range seed, now fails. Pass 'aes' as the mode of cookieEncrypted() / assertCookieEncrypted() of IntegrationTestTrait once the application uses 'aes'.
In v2.12.5 and earlier, nothing is reported; the weakness is the same.
Configuration Constants
While most configuration options are handled by Configure, there are a few constants that CakePHP uses during runtime.
constant LOG_ERROR
Error constant. Used for differentiating error logging and debugging. Currently PHP supports LOG_DEBUG.
Core Cache Configuration
CakePHP uses two cache configurations internally. _cake_model_ and _cake_core_. _cake_core_ is used to store file paths, and object locations. _cake_model_ is used to store schema descriptions, and source listings for datasources. Using a fast cache storage like APCu or Memcached is recommended for these configurations, as they are read on every request. By default both of these configurations expire every 10 seconds when debug is greater than 0. Both are defined at the end of config/core.php.
The available cache engines are File, Apc (which uses the APCu extension when it is loaded), Memcached, Memcache and Redis.
Piece of Cake 2 fork
The Xcache and Wincache cache engines were removed. Switch any configuration that uses them to one of the engines above.
As with all cached data stored in Cache you can clear data using Cache::clear().
Configure Class
class Configure
Despite few things needing to be configured in CakePHP, it's sometimes useful to have your own configuration rules for your application. In the past you may have defined custom configuration values by defining variable or constants in some files. Doing so forces you to include that configuration file every time you needed to use those values.
CakePHP's Configure class can be used to store and retrieve application or runtime specific values. Be careful, this class allows you to store anything in it, then use it in any other part of your code: a sure temptation to break the MVC pattern CakePHP was designed for. The main goal of Configure class is to keep centralized variables that can be shared between many objects. Remember to try to live by "convention over configuration" and you won't end up breaking the MVC structure we've set in place.
This class can be called from anywhere within your application, in a static context:
Configure::read('debug');static Configure::write($key, $value)
string $key: The key to write, can be adot notationvalue.mixed $value: The value to store.
Use write() to store data in the application's configuration:
Configure::write('Company.name', 'Pizza, Inc.');
Configure::write('Company.slogan', 'Pizza for your body and soul');NOTE
The dot notation used in the $key parameter can be used to organize your configuration settings into logical groups.
The above example could also be written in a single call:
Configure::write(
'Company',
[
'name' => 'Pizza, Inc.',
'slogan' => 'Pizza for your body and soul',
],
);You can use Configure::write('debug', $int) to switch between debug and production modes on the fly. This is especially handy for JSON or XML responses where debugging information can cause parsing problems.
static Configure::read($key = null)
string $key: The key to read, can be adot notationvalue
Used to read configuration data from the application. Defaults to CakePHP's important debug value. If a key is supplied, the data is returned. Using our examples from write() above, we can read that data back:
Configure::read('Company.name'); // yields: 'Pizza, Inc.'
Configure::read('Company.slogan'); // yields: 'Pizza for your body and soul'
Configure::read('Company');
// yields:
['name' => 'Pizza, Inc.', 'slogan' => 'Pizza for your body and soul'];If $key is left null, all values in Configure will be returned. If the value corresponding to the specified $key does not exist then null will be returned.
static Configure::consume($key)
string $key: The key to read, can use be adot notationvalue
Read and delete a key from Configure. This is useful when you want to combine reading and deleting values in a single operation.
static Configure::check($key)
string $key: The key to check.
Used to check if a key/path exists and has not-null value.
Added in version 2.3
Configure::check() was added in 2.3
static Configure::delete($key)
string $key: The key to delete, can be adot notationvalue
Used to delete information from the application's configuration:
Configure::delete('Company.name');static Configure::version()
Returns the CakePHP version for the current application.
static Configure::config($name, $reader)
string $name: The name of the reader being attached.ConfigReaderInterface $reader: The reader instance being attached.
Attach a configuration reader to Configure. Attached readers can then be used to load configuration files. See Loading Configuration Files for more information on how to read configuration files.
static Configure::configured($name = null)
string $name: The name of the reader to check, if null a list of all attached readers will be returned.
Either check that a reader with a given name is attached, or get the list of attached readers.
static Configure::drop($name)
Drops a connected reader object.
Reading and writing configuration files
CakePHP comes with two built-in configuration file readers. PhpReader is able to read PHP config files, in the same format that Configure has historically read. IniReader is able to read ini config files. See the PHP documentation for more information on the specifics of ini files. To use a core config reader, you'll need to attach it to Configure using Configure::config():
// Read config files from CONFIG (config/)
Configure::config('default', new PhpReader());
// Read config files from another path.
Configure::config('default', new PhpReader('/path/to/your/config/files/'));Both readers read from the CONFIG directory by default, and from a plugin's Config/ directory when you use plugin syntax such as Configure::load('MyPlugin.my_file').
You can have multiple readers attached to Configure, each reading different kinds of configuration files, or reading from different types of sources. You can interact with attached readers using a few other methods on Configure. To see which reader aliases are attached you can use Configure::configured():
// Get the array of aliases for attached readers.
Configure::configured();
// Check if a specific reader is attached
Configure::configured('default');You can also remove attached readers. Configure::drop('default') would remove the default reader alias. Any future attempts to load configuration files with that reader would fail.
Loading configuration files
static Configure::load($key, $config = 'default', $merge = true)
string $key: The identifier of the configuration file to load.string $config: The alias of the configured reader.boolean $merge: Whether or not the contents of the read file should be merged, or overwrite the existing values.
Once you've attached a config reader to Configure you can load configuration files:
// Load config/my_file.php using the 'default' reader object.
Configure::load('my_file', 'default');Loaded configuration files merge their data with the existing runtime configuration in Configure. This allows you to overwrite and add new values into the existing runtime configuration. By setting $merge to false, values will not ever overwrite the existing configuration.
Creating or modifying configuration files
static Configure::dump($key, $config = 'default', $keys = [])
string $key: The name of the file/stored configuration to be created.string $config: The name of the reader to store the data with.array $keys: The list of top-level keys to save. Defaults to all keys.
Dumps all or some of the data in Configure into a file or storage system supported by a config reader. The serialization format is decided by the config reader attached as $config. For example, if the 'default' adapter is a PhpReader, the generated file will be a PHP configuration file loadable by the PhpReader
Given that the 'default' reader is an instance of PhpReader. Save all data in Configure to the file my_config.php:
Configure::dump('my_config.php', 'default');Save only the error handling configuration:
Configure::dump('error.php', 'default', ['Error', 'Exception']);Configure::dump() can be used to either modify or overwrite configuration files that are readable with Configure::load()
Added in version 2.2
Configure::dump() was added in 2.2.
Storing runtime configuration
static Configure::store($name, $cacheConfig = 'default', $data = null)
string $name: The storage key for the cache file.string $cacheConfig: The name of the cache configuration to store the configuration data with.mixed $data: Either the data to store, or leave null to store all data in Configure.
You can also store runtime configuration values for use in a future request. Since configure only remembers values for the current request, you will need to store any modified configuration information if you want to use it in subsequent requests:
// Store the current configuration in the 'user_1234' key in the 'default' cache.
Configure::store('user_1234', 'default');Stored configuration data is persisted in the Cache class. This allows you to store Configuration information in any storage engine that Cache can talk to.
Restoring runtime configuration
static Configure::restore($name, $cacheConfig = 'default')
string $name: The storage key to load.string $cacheConfig: The cache configuration to load the data from.
Once you've stored runtime configuration, you'll probably need to restore it so you can access it again. Configure::restore() does exactly that:
// restore runtime configuration from the cache.
Configure::restore('user_1234', 'default');When restoring configuration information it's important to restore it with the same key, and cache configuration as was used to store it. Restored information is merged on top of the existing runtime configuration.
Creating your own Configuration readers
Since configuration readers are an extensible part of CakePHP, you can create configuration readers in your application and plugins. Configuration readers need to implement the ConfigReaderInterface. This interface defines a read() and a dump() method. If you really like XML files, you could create a simple Xml config reader for you application:
// src/Lib/Configure/MyXmlReader.php
class MyXmlReader implements ConfigReaderInterface
{
protected $_path;
public function __construct($path = null)
{
if (!$path) {
$path = CONFIG;
}
$this->_path = $path;
}
public function read($key)
{
$xml = Xml::build($this->_path . $key . '.xml');
return Xml::toArray($xml);
}
/**
* As of 2.3 a dump() method is also required
*/
public function dump($key, $data)
{
// code to dump data to file
}
}In your config/bootstrap.php you could attach this reader and use it:
Configure::config('xml', new MyXmlReader());
// ...
Configure::load('my_xml');With Composer classmap autoloading for src/, the reader class is found automatically after composer dump-autoload.
WARNING
It is not a good idea to call your custom configure class XmlReader because that class name is an internal PHP one already: XMLReader
The read() method of a config reader, must return an array of the configuration information that the resource named $key contains.
interface ConfigReaderInterface
Defines the interface used by classes that read configuration data and store it in Configure
method ConfigReaderInterface::read($key)
method ConfigReaderInterface::dump($key, $data)
Added in version 2.3
ConfigReaderInterface::dump() was added in 2.3.
exception ConfigureException
Thrown when errors occur when loading/storing/restoring configuration data. ConfigReaderInterface implementations should throw this exception when they encounter an error.
Built-in Configuration readers
class PhpReader
class IniReader
Inflection Configuration
CakePHP's naming conventions can be really nice - you can name your database table big_boxes, your model BigBox, your controller BigBoxesController, and everything just works together automatically. The way CakePHP knows how to tie things together is by inflecting the words between their singular and plural forms.
There are occasions (especially for our non-English speaking friends) where you may run into situations where CakePHP's Inflector (the class that pluralizes, singularizes, camelCases, and under_scores) might not work as you'd like. If CakePHP won't recognize your Foci or Fish, you can tell CakePHP about your special cases.
Loading custom inflections
You can use Inflector::rules() in the file config/bootstrap.php to load custom inflections:
Inflector::rules('singular', [
'rules' => [
'/^(bil)er$/i' => '\1',
'/^(inflec|contribu)tors$/i' => '\1ta',
],
'uninflected' => ['singulars'],
'irregular' => ['spins' => 'spinor'],
]);or:
Inflector::rules('plural', ['irregular' => ['phylum' => 'phyla']]);Will merge the supplied rules into the inflection sets defined in the framework's src/Utility/Inflector.php (vendor/pieceofcake2/cakephp/src/Utility/Inflector.php), with the added rules taking precedence over the core rules.
Bootstrapping CakePHP
If you have any additional configuration needs, use CakePHP's bootstrap file, found in config/bootstrap.php. This file is executed just after CakePHP's core bootstrapping.
This file is ideal for a number of common bootstrapping tasks:
- Defining convenience functions.
- Registering global constants.
- Defining additional model, view, and controller paths.
- Creating cache configurations.
- Configuring inflections.
- Loading configuration files.
Be careful to maintain the MVC software design pattern when you add things to the bootstrap file: it might be tempting to place formatting functions there in order to use them in your controllers.
Resist the urge. You'll be glad you did later on down the line.
You might also consider placing things in the AppController class. This class is a parent class to all of the controllers in your application. AppController is a handy place to use controller callbacks and define methods to be used by all of your controllers.
