The is_assoc method checks if the array passed is an associative array or not.
@@ -123,6 +123,11 @@
is_assoc($arr)
required
The array to check.
+
+
$consecutive
+
true
+
If true, it expects an indexed array to have sequential, consecutive numeric keys, starting with zero. If false, a key has to be not an integer for the array to be classified as associative.
Note: the $consecutive flag has been added to be able to test for all indexed arrays, to avoid breaking backward compatibilty with pre-1.9 code which expects all indexed arrays to be zero-based and have consecutive numeric keys.
The filter_recursive method provides a recursive version of PHP's array_filter() function. Like its counterpart, you can optionally pass a callback function to determine what should be filtered.
@@ -992,6 +1003,11 @@
filter_recursive($array, $callba
null
A valid callback that returns a boolean.
+
+
$mode
+
ARRAY_FILTER_USE_KEY
+
either ARRAY_FILTER_USE_KEY or ARRAY_FILTER_USE_BOTH
The sort method sorts a multi-dimensional array by multiple values.
@@ -1941,10 +1970,15 @@
multisort($array, $conditions, $ignore_
Array of sorting conditions.
-
$ornire_case
+
$ignore_case
false
Whether to sort case insensitive.
+
+
$reindex
+
true
+
When an indexed array is multisorted, do we want the result to be re-indexed or not.
+
@@ -2032,6 +2066,10 @@
multisort($array, $conditions, $ignore_
+
+ By default, Arr::multisort() works similar to PHP's default array_multisort, which preserves keys of associative arrays, but re-indexes indexed arrays.
+ You can disable this behavior, and preserve keys if indexed arrays too, by passing false for $reindex.
+
+ The colors in the first column are also available as background colors. Colors may depend on the terminal and terminal theme used.
+ Note that if you prefer UK English spelling, you can substitute "grey" for "gray".
+
You can use different file layouts to store your configuration. The layout type is determined by the file extension:
- PHP. The default type. A PHP file should return an array structure.
+ PHP The default type. A PHP file should return an array structure.
return array('key' => 'value');
- INI. See this page for a definition of the ini-file layout.
+ INI See this page for a definition of the ini-file layout.
[group]
key=value
- YAML. See this page for a definition of the yaml-file layout.
+ YAML See this page for a definition of the yaml-file layout.
group:
key: value
- JSON. See this page for a definition of the json-file layout.
+ JSON See this page for a definition of the json-file layout.
{
"group" :
{
@@ -66,14 +66,14 @@
Config File Types
}
- MEMCACHED. Stores or retrieves the config from a Memcached or Memcachedb store.
+ MEMCACHED Stores or retrieves the config from a Memcached or Memcachedb store.
It will use the config.memcached section of the app/config/config.php configuration
file to configure the memcached class used to connect to the store.
- DB. Use the following table structure:
+ DB Use the following table structure:
CREATE TABLE IF NOT EXISTS `config` (
`identifier` char(100) NOT NULL,
`config` longtext NOT NULL,
@@ -268,7 +268,7 @@
The load method reads in a config file into the system. It searches through the config directories for the requested file. You can optionally group the config files to avoid naming collisions.
@@ -292,19 +292,24 @@
load($file, $group = null, $reload = false,
$group
-
null
+
null
(Optional) A group name to use. If set to true then a group of the same name as $file will be created. If this is not set or is null then the loaded config will be merged with the root config.
$reload
-
false
+
false
(Optional) If set to true a reload of the requested configuration is forced, erasing cached configuration items related to the config file to be loaded.
$overwrite
-
false
+
false
(Optional) If set to true the loaded configuration items will be merged with the items already loaded in a non-recursive manner, with will overwrite array values in a multidimensional array, rather then merging them.
+
+
$appfirst
+
false
+
By default, module files override global files (app, core, packages). By setting this to true, files in the app will have precedence over module files.
+
@@ -333,6 +338,12 @@
load($file, $group = null, $reload = false,
+
+ When loading configuration files from a module, whatever the type, files found are loaded in the following order:
+ MODULE, APP, PACKAGES (in order of definition/loading), CORE
+ If you have a modules that require customisation in the app in which the module is used, without altering the code in the module (for examples modules that are distributed), you need to set $appfirst to true when loading the configuration, which alters the load order to:
+ APP, MODULE, PACKAGES (in order of definition/loading), CORE.
+
The database_exists method checks if a named database already exists. Will throw a Database_Exception if it cannot.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$database
+
required
+
the database name
+
+
+
$db
+
null
+
The database connection.
+
+
+
+
+
+
Returns
+
true if the database exists, false if not.
+
+
+
Throws
+
\Database_Exception on failure; \Fuel_Exception if not implemented
+
+
+
Example
+
+
// check if the database exists
+if (DBUtil::database_exists('my_database'))
+{
+ // deal with it
+}
+
+
+
+
+
+ This method is currently only available for MySQL/MariaDB, SQLSrv and SQLite.
+ In case of SQLite, you can check on either the attached database name or the FQFN or the attached database file (case-insensitive).
+
Fuel offers a driver based database abstraction layer. At the time of writing supported
- drivers are MySQL, MySQLi and PDO. Aside from regular database interaction, fuel also
- comes with a DBUtil class to perform database operations such as creating databases,
+ drivers are MySQL, MySQLi, SQL Server, and PDO. Aside from regular database interaction,
+ Fuel also comes with a DBUtil class to perform database operations such as creating databases,
adding fields and much more.
+ An integer representing a Unix timestamp to set the date object to. Defaults to time() with the defined offset applied.
+ Alternatively, you can also pass a DateTime object, which will be converted to a timestamp value.
+
$timezone
null
-
The timezone in which the time is set
+
The timezone in which the time is set. Defaults to "UTC".
+
+
+
$pattern
+
null
+
The default date pattern string to use when formatting the date held by the object. Defaults to "local".
The create_from_string creates a Date object from a named date string format or a
pattern.
-
This function uses strptime()
- for i18n purposes. That method isn't available on Windows hosts however, on those strtotime()
- is used instead and the pattern is ignored.
+
This function uses strptime().
+ This method isn't available on Windows hosts, and deprecated in PHP 8.1. In those cases, we emulate it using Date::strptime().
+ Note that this doesn't have locale support (i.e. pattern values representing locale values, like %c).
+ The Date object created is always in the currently active timezone. If a timezone is detected in the format,
+ its offset will be taken into account when creating the object.
+
@@ -289,24 +314,28 @@
range_to_array($start, $end, $inte
(
[timestamp:protected] => 1294181818
[timezone:protected] => UTC
+ [pattern:protected] => local
)
[1] => Fuel\Core\Date Object
(
[timestamp:protected] => 1294354618
[timezone:protected] => UTC
+ [pattern:protected] => local
)
[2] => Fuel\Core\Date Object
(
[timestamp:protected] => 1294527418
[timezone:protected] => UTC
+ [pattern:protected] => local
)
[3] => Fuel\Core\Date Object
(
[timestamp:protected] => 1294700218
[timezone:protected] => UTC
+ [pattern:protected] => local
)
)
@@ -464,15 +493,137 @@
is_valid($date, 'Y-m-d')
+
+
+
strftime($format, $timestamp)
+
The strftime method is a drop-in replacedment for the PHP strftime() function, for use on Windows or PHP 8.1+.
+ Unlike the PHP built-in function, this version has support for timezones. If a timezone is detected in the format, like
+ "%z" in the above example, an additional "tm_zone" value is returned in the array, indicating the offset to UTC, in seconds.
+
+
+
+
+
format($pattern_key = null, $timezone = null)
The format method returns a formatted date as specified by the pattern key. The
patterns are defined in the fuel/core/config/date.php config file - you can add your own
- by creating a similar file in app/config.
+ by creating a similar file in app/config. If you don't pass a pattern, the pattern given when
+ the object was constructed is used. If that wasn't given either, it defaults to 'local'. If the pattern
+ is not a key in the date config file, it is assumed to be a valid strftime() pattern string.
This method uses patterns for the strftime()
- function instead of date() to allow for i18n.
+ function instead of date() to allow for i18n. On PHP 8.1 or higher, or on platforms not supporting this function,
+ it is emulated by Date::strftime().
If you don't pass a timezone, the timezone set on the current Date object will be used when formatting the result. By default,
this is the system timezone, unless you have altered it by calling the set_timezone() method. You can also pass
@@ -531,6 +682,7 @@
format($pattern_key = 'local', $timezone =
+
If you echo a Date object or otherwise cast it to string, it will return the string representation of the objects' date, using the default or configured pattern, identical to calling format() without arguments.
@@ -579,6 +731,31 @@
get_timezone()
+
+
get_pattern()
+
The get_pattern method returns the Date object's configured date pattern
+
+
+
+
Static
+
No
+
+
+
Returns
+
string
+
+
+
Example
+
+
$date = Date::forge(1294176140, "Europe/London", "mysql");
+echo $date->get_pattern(); // "%Y-%m-%d %H:%M:%S", with default date config
+
+
+
+
+
+
+
get_timezone_abbr($display_timezone = false)
The get_timezone_abbr method returns the abbreviated timezone for either the timezone set in the Date object, or for the display timezone.
Converts an absolute path to a path relative to the given reference path.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$reference
+
required
+
Path to be used a a referencde
+
+
+
$to
+
required
+
Absolute path, to be converted to a relative path
+
+
+
+
+
+
Returns
+
string the path for $to, relative to $reference
+
+
+
Example
+
+
// get the relative path on *nix
+$relpath = File::relativepath('/a/b/c/d', '/a/b/e/f'); // returns "../e/f"
+$relpath = File::relativepath('/a/b/c/d', '/e/f/g/h'); // returns "../../../e/f/g/h"
+// get the relative path on Windows
+$relpath = File::relativepath('C:\\a\\b\\c\\d', 'C:\\a\\b\\e\\f'); // returns "..\e\f"
+$relpath = File::relativepath('C:\\a\\b\\c\\d', 'D:\\a\\b\\e\\f'); // throws an exception
+
+
+
+
+
+
+ Note that on Windows, if only one of the paths is prefixed with a drive letter, it is assumed that the other path
+ is on the same drive. When both are prefixed with a drive letter, it MUST be the same drive, if not, an exception
+ is thrown, as you can't create relative paths between different drives.
+
The search method is a static alias for locate() on the default finder instance.
@@ -175,6 +175,11 @@
search($dir, $file, $ext = '.php', $multip
true
If true, cache the results for subsequent requests to prevent unnecessary disk access.
+
+
$appfirst
+
false
+
By default, module files override global files (app, core, packages). By setting this to true, files in the app will have precedence over module files.
+
@@ -189,7 +194,22 @@
search($dir, $file, $ext = '.php', $multip
// will return APPPATH/views/welcome/index.php
$viewfile = Finder::search('views', 'welcome/index');
-
+
+// assuming we're in active module called "test", and requested all files, this could
+// return array("MODULEPATH/test/lang/en/welcome.php", "APPPATH/lang/en/welcome.php")
+$lang = Finder::search('lang/en', 'welcome', true, false);
+
+// assuming we're in active module called "test", and requested all files, this could
+// return array("APPPATH/lang/en/welcome.php", "MODULEPATH/test/lang/en/welcome.php")
+$lang = Finder::search('lang/en', 'welcome', true, false, true);
+
+// searching explicitly in the module, this would return
+// array("MODULEPATH/test/lang/en/welcome.php")
+$lang = Finder::search('test::lang/en', 'welcome', '.php', true);
+
+// searching explicitly in the app, this would return
+// array("APPPATH/lang/en/welcome.php")
+$lang = Finder::search('::lang/en', 'welcome', '.php', true);
The locate method locates files in the defined search paths.
@@ -431,6 +451,11 @@
locate($dir, $file, $ext = '.php', $multip
true
If true, cache the results for subsequent requests to prevent unnecessary disk access.
+
+
$appfirst
+
false
+
By default, module files override global files (app, core, packages). By setting this to true, files in the app will have precedence over module files.
+
@@ -445,7 +470,23 @@
locate($dir, $file, $ext = '.php', $multip
// will return APPPATH/views/welcome/index.php
$viewfile = Finder::instance()->locate('views', 'welcome/index');
-
+
+// assuming we're in active module called "test", and requested all files, this could
+// return array("MODULEPATH/test/lang/en/welcome.php", "APPPATH/lang/en/welcome.php")
+$lang = Finder::instance()->locate('lang/en', 'welcome', true, false);
+
+// assuming we're in active module called "test", and requested all files, this could
+// return array("APPPATH/lang/en/welcome.php", "MODULEPATH/test/lang/en/welcome.php")
+$lang = Finder::instance()->locate('lang/en', 'welcome', true, false, true);
+
+// searching explicitly in the module, this would return
+// array("MODULEPATH/test/lang/en/welcome.php")
+$lang = Finder::instance()->locate('test::lang/en', 'welcome', '.php', true);
+
+// searching explicitly in the app, this would return
+// array("APPPATH/lang/en/welcome.php")
+$lang = Finder::instance()->locate('::lang/en', 'welcome', '.php', true);
+
- Optional: Name of the user to connect with, if login is required.
+ Name of the user to connect with, if login is required.
@@ -72,7 +72,7 @@
Configuration
string
''
- Optional: Name of the password to connect with, if login is required.
+ Name of the password to connect with, if login is required.
@@ -117,6 +117,10 @@
Configuration
+
+ All configuration values are optional. If you omit one, the default value as given above will be used.
+ This is also the case when you pass a array with custom configuration values when you call forge().
+
+ Note that the hydration code in the Input class uses Format::forge($input, 'json')->to_array(), to be able to access nested data using dot‑notation.
+ This implies that all json objects in the input are converted to arrays instead of StdClass !
+
load($file, $group = null, $language = null,
// Will load the example language file in italian.
// If that doesn't exist, it will load the configured language
-Lang::load('foo::example', 'bar', 'it');
+Lang::load('foo::example', 'bar', 'it');
+
+// Special case: if you want to explicitly load a file from the app, even when in
+// an active module, use this. It will not merge the result with a file in the
+// active module, like a standard load would do.
+Lang::load('::example', 'bar', 'it');
+
@@ -556,7 +562,7 @@
The version method will move the migrations up by one, or up to a specific version if given.
+
The up method will move the migrations up by one, or up to a specific version if given.
@@ -241,7 +241,7 @@
up($version, $name = 'default', $type = 'app')
down($version, $name = 'default', $type = 'app')
-
The version method will move the migrations down by one, or down to a specific version if given.
+
The down method will move the migrations down by one, or down to a specific version if given.
@@ -296,11 +296,66 @@
down($version, $name = 'default', $type = 'a
If no migrations where found, or if the version specified resulted in no migrations being executed, the array returned is empty.
+
+
has($name, $type, $seq = null)
+
The has method allows you to check if a given migration has already run. This is most useful inside migrations, to check for dependencies.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$type
+
required
+
Type of migration. Valid values are 'app', 'module' and 'package'.
+
+
+
$name
+
required
+
Name of the package or module. In case of app, use 'default' as a placeholder.
+
+
+
$seq
+
null
+
+
+
+
+
+
Returns
+
bool
+
+
+
Example
+
+
// skip further processing if migration 10 of the module 'mymodule' has not already run
+// use this in a migration up() method to postpone that migration
+if ( ! Migrate::has('module', 'mymodule', '010'))
+{
+ return false;
+}
+
The loaded method allows you to check if a module is currently loaded. If no module name is given then all loaded module are returned.
+
The loaded method allows you to check if a module is currently loaded. If no module name is given then all loaded modules are returned.
@@ -191,6 +191,59 @@
loaded($module = null)
+
+
installed($module = null)
+
The installed method allows you to check if a module is currently installed, i.e. present in a defined module path. If no module name is given then all installed modules are returned.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$module
+
null
+
Name of the module to be checked.
+
+
+
+
+
+
Returns
+
bool|array
+
+
+
Example
+
+
// Check if the users module is installed
+$loaded = Module::installed('users');
+
+// Get all loaded modules
+$loaded = Module::installed();
+/*
+Returns something like:
+array(
+ 'users' => '/path/to/users',
+ 'groups' => '/path/to/groups',
+ 'notloaded' => '/path/to/notloaded',
+)
+*/
+
The installed method allows you to check if a package is currently installed, i.e. present in a defined package path. If no package name is given then all installed packages are returned.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$package
+
null
+
Name of the package to be checked.
+
+
+
+
+
+
Returns
+
bool|array
+
+
+
Example
+
+
// Check if the orm package is installed
+$loaded = Package::installed('orm');
+
+// Get all installed packages
+$loaded = Package::installed();
+/*
+Returns something like:
+array(
+ 'orm' => '/path/to/orm',
+ 'parser' => '/path/to/parser',
+ 'notloaded' => '/path/to/notloaded',
+)
+*/
+
+ The app_total method returs an array with two values, the number of microseconds Fuel is running processing the current request,
+ and the number of bytes of memory the process has allocated sofar (excluding PHP internal bootstrap memory used).
+
+ The init method initializes the profiler state. It will create a profiler instance, and sets up database query profiling.
+ As long as the profiler is not initialized, all profiler methods apart from app_total() are NOOP's.
+
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
None
+
+
+
Returns
+
void
+
+
+
Example
+
+
Profiler::reset();
+
+
+
+
+
+
+
+
reset()
+
+ The reset method reset the Profiler to its uninitialized state. You will have to call init() again if you want to re-enable the profiler.
+
The active method returns wether or not the named or default session instance is active (loaded and initialized).
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$instance
+
null
+
Cookiename (as defined in config/session.php) that identifies the required session instance.
+
+
+
+
+
+
Returns
+
bool, true if the session is active and can be used, false if not.
+
+
+
Example
+
+
// Make sure we have an active session before using it
+if (Session::active())
+{
+ $var = Session::get('var');
+}
+
+
+
+
+
+
+ You may need this check if your application has cases where no session is active, and can not be activated, for example because the database session table has not been created yet.
+ Web-based installers as part of your application are a great example where this may be the case.
+
+
+
set($variable, $value = null)
The set method allows you to set a session variable.
+ The number_format is virtually identical to the PHP built-in function with the same name, but it also supports a currency symbol,
+ and it uses information from the current locale to determine the value for fields which are null.
+
+
Note that in the argument list, the thousand and decimal separator are the other way around compared to the PHP built-in function, because it happens more often that the thousand separator needs to be supressed.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$num
+
required
+
The float value to format.
+
+
+
$decimals
+
null
+
The ending to check for.
+
+
+
$thousands_separator
+
null
+
Thousand separator to use.
+
+
+
$decimal_separator
+
null
+
Decimal separator to use.
+
+
+
$currency_symbol
+
null
+
Currency Symbol to use. If null, information from the current the locale will be used. By default, it is false, and no currency info will added to the number.
+
+
+
+
+
+
Returns
+
bool
+
+
+
Example
+
+
$num = 123456.789;
+
+setlocale(LC_ALL, 'nl_NL.UTF-8');
+echo Str::number_format($num); // will return "123456,79"
+echo Str::number_format($num, null, null, null, "EUR"); // will return "EUR 123.456,789"
+echo Str::number_format($num, 3, ""); // will return "€ 123456,789"
+
+setlocale(LC_ALL, 'en_US.UTF-8');
+echo Str::number_format($num); // will return "123,456.79"
+echo Str::number_format($num, 3, ""); // will return "123456.789"
+echo Str::number_format($num, 3, null, null, null); // will return "$123,456.789"
The contents of a partials section can be accessed through a view variable $partials, an array with an entry for each of the partial
sections defined. You access a section using its name. So for a partial section called 'sidebar', you would use echo $partials['sidebar']; in your page template.
+
Partials will be searched for in the following locations, in this order:
+
+
APPPATH/themes, in case of a app or global controller, and use_modules is set to true.
+
MODULEPATH/module/themes, in case of a module controller, and use_modules is set to true.
+
APPPATH/themes, in case of a app or global controller, and use_modules is set to true.
+
THEMEPATH/module, in case of a module controller.
+
THEMEPATH.
+
+
+
Partial chrome
@@ -262,9 +272,10 @@
Configuration
boolean|string
false
- Whether to automatically prefix the view filename with the current module name. If it contains a string,
- it will be used to prefix the theme view path. This allows you to move all module theme views into a
- separate folder, and avoid collisions between module names and app views...
+ If true, you can use a "themes" directory in a module (or in the app) to override view files in the
+ theme folder structure. If it contains a string, it will be used to prefix the theme view path.
+ This also allows you to move all module theme views into a separate folder, and avoid collisions
+ between module names and app views...
- The use_modules method enables or disables the prefixing feature for views loaded from a
- module. If true, the views loaded via the Theme class will be prefixed by the current active module
- name (if any). If a string is passed, it will be prefixed as well, allowing you to store all modules in a
+ By default, when using themes, the views requested by the controller will be loaded from the active (or
+ fallback) theme directory structure. The use_modules method enables or disables the
+ possibility of overriding these views with a view from the app or module "themes" directory.
+ If true, the views loaded via the Theme class will be prefixed by the current active module
+ path (or the APPPATH). If a string is passed, it will be prefixed as-as, allowing you to store all modules in a
separate directory, to avoid name conficts between module names and non-prefixed view names. If the view can
not be found, it's checked again without the prefix, allowing for global views from inside a module. If that
doesn't exist either, the View class will be called to load the view the regular way.
@@ -1471,7 +1473,7 @@
These are the developers that make commits on a near-daily basis, and make all final decisions about the framework.
-
-
Harro Verton - Project Manager, maintainer of the 1.x codebase and the 2.0 core
-
Steve West - Developer, development lead for the 2.0 ORM, fieldsets, validation
-
-
-
- Do you think you have what it takes to become a Core Developer? Start with discussing the future of the
- framework in IRC, send in pull requests for open issues, attack one of the many approved feature requests, or
- join the work for the new 2.0 version.
+
Development
+
+ The Fuel PHP framework is currently being maintained by FlexCoders Ltd, a web application development company
+ based in Glasgow, UK. Any improvements made to the framework are backported to the open source version
+ if and where possible.
+
+ There are no intentions to stop maintaining the framework, nor to end its open source status.
+ Contributions in the form of Pull Requests on github remain welcome.
Alumni
@@ -53,6 +50,8 @@
Alumni
of the FuelPHP framework. Without them, it would not be what it is today!
+
Harro Verton - Project Lead, Developer, development lead for the 2.0 codebase
+
Steve West - Developer, development lead for the 2.0 ORM, fieldsets, validation
Frank de Jonge - Developer, development of the email package and 2.0 composer packages
Jelmer Schreuder - Project Architect, development of the ORM package
Phil Sturgeon - Developer, development of the Oil package
- Whether to show notices.
+ If true, PHP notices are shown inline. If false, an E_USER_NOTICE exception is thrown.
@@ -215,13 +215,24 @@
Configuration options
locale
-
string
+
string | array
'en_US'
- Used for setlocale() required on some php installations, set to false
- to prevent it from being set.
+ Used for set the locale for your application, if it differs from the default server or
+ PHP configuation locale. See setlocale() for more information. The syntax setting for this can differ per OS, Ubuntu for example requires a
- .utf8 (the encoding) suffix.
+ .utf8 (the encoding) suffix.. To pass multiple options, pass an indexed array
+ with the locales in order of preference.
+ If you don't need to use a difffent locale, set to false.
+
+
+
locale_category
+
int | array
+
LC_ALL
+
+ One or more categories for which the defined locale should be set, define either a single
+ category, like the LC_ALL constant, or an indexed array of LC constants.
+ The array is needed because unlike other constants in PHP, these can't be or'd.
@@ -597,6 +608,15 @@
Configuration options
you load the module.
+
+
.recursive
+
bool
+
false
+
+ If true, and the requested URI resolves to a defined route, but that route doesn't resolve
+ to a valid controller action, the resolved route will be processed again by the routing engine.
+
in your applications config/config.php file. Errors defined here will allow your script to continue. No exception
is being thrown for these errors, so you can no longer catch these.
+
+ If you want to continue on PHP notices, you may also want to add E_USER_NOTICE to the array, as the framework uses this code to generate its own notices.
+
It is strongly adviced not to continue on errors, as it might lead to bugs in your code that are
very difficult to find once your application moves into production!
@@ -226,7 +229,7 @@
+ Fuel provides a few global functions for things that are used in the framework, but may also be handy in your own applications. These functiona re defined in base.php, which can be found in the Fuel core directory.
+
+
+
call_fuel_func_array()
+
A faster equivalent to call_user_func_array(), especially in older PHP versions.
+
+
http_build_url()
+
The reverse function of parse_url(). It is defined in a PECL extension (pecl_http >= 0.21.0), but not every server has the extension loaded, and not everyone has the option to change installed PHP modules.
+
+
in_arrayi()
+
Equivalent to the built-in function in_array(), but does a case-insensitive check.
+
+
e(string $s)
+
A shortcut to \Security::htmlentities(), mainly used in view files.
Imports a Fuel core class, and loads the App overload if defined as well.
+
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$class
+
required
+
Class name, or relative path and class name in case the load is from a subdirectory.
+
+
+
$folder
+
'classes'
+
Directory the class has to be loaded from. In general, this is always "classes", the Fuel standard location.
+
+
+
$content
+
null
+
Optional content for tags that may have any content.
+
+
+
+
+
+
Example
+
+
// will "require" COREPATH/classes/controller/rest.php
+// and APPPATH/classes/controller/rest.php if it exists.
+import('controller/rest', 'classes');
+
+
+
+
+
+
is_uuid(string $uuid)
+
Checks if the given string is in valid UUID format.
+
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$uuid
+
required
+
String to test for a valid UUID.
+
+
+
+
+
+
Returns
+
True if the string is a valid UUID, false if not.
+
+
+
Example
+
+
// will return true
+$valid = is_uuid('dedd6906-de08-4b7f-b4de-46ae04942516');
+
+// will return false, 'x' is not a valid character
+$valid = is_uuid('dedd6906-xe08-4b7f-b4de-46ae04942516');
+
+
+
+
+
+
array_to_attr(array $attr)
+
Takes an array of attributes and turns it into a string for an html tag.
If true, all cached data will be erased after all migrations have run, via a call to Cache::delete_all().
+
+
flag
+
string
+
+
null
+
+
+ A valid filename, accessible and writeable by both the web application and application tasks from the CLI.
+ The (empty) file is created when the migrations start, and removed when they are finished. This can be used to
+ block access to (parts of) the application, and/or enable application maintenance mode.
+
+
@@ -151,7 +163,7 @@
Run a Migration
Note:
- The migrate:current task is to match your schema to the version listed in fuel/[app|core]/config/migrate.php as if you have just got
+ The migrate:current task is to match your schema to the version listed in fuel/[app|core]/config/migrations.php as if you have just got
a copy of the application, the very latest migration not be the one considered stable. Using oil for migrations will modify this migration
config number so the current command will not be relevant in many situations.
@@ -188,11 +200,35 @@
Prepping a migration
The after() method will only be called if the migration itself was succesful. If the migration method returns false, it
will not be called.
+
+
Restoring or truncating the database
+
+
+ When you alter your database structure, for example by dropping all tables, or by restoring an older version of the database, you may create
+ a mismatch between the migration status table in the database and the data in the applications config file. In this case, delete the config
+ file, and run all migrations. The config file will be reconstructed from data in the database, and any missing migrations will run, bringing
+ the database in sync with the code again.
+
+
+
+ Please note that there are no provisions to repair a damaged database. You can not for example delete a table, run migrations, and expect
+ that table to be recreated again !
+
+
+
Reverting to an older version of your code
+
+
+ This can also lead to a disconnect between the structure of your database and the migration versions the application will be expecting.
+ As the old version of the code might be of a lower migration version, you need to check the migration versions of the app, all modules and
+ all packages, and you need to manually revert any migrations applied to the database but not present in the code being reverted to,
+ before you revert your code.
+
- FuelPHP, as a PHP 5.3+ framework, relies heavily on namespacing to separate the different components of the framework and
+ FuelPHP, as a PHP framework, relies heavily on namespacing to separate the different components of the framework and
of your application, to make the code as portable as possible, and to prevent any collisons in class names when you're moving
bits of your application around.
+ Fuel provides polyfills for popular functions added to PHP after the release of PHP 5.3.
+
+
+
+
+
+
Function
+
Description
+
+
+
array_first()
+
+ Returns the first value from an array.
+ Introduced in PHP 8.5.
+
+
+
+
array_last()
+
+ Returns the last value from an array.
+ Introduced in PHP 8.5.
+
+
+
+
array_key_first()
+
+ Returns the first key from an array.
+ Introduced in PHP 7.3.
+
+
+
+
array_key_last()
+
+ Returns the last key from an array.
+ Introduced in PHP 7.3.
+
+
+
+
hash_pbkdf2()
+
+ Implements PBKDF2 hashing.
+ Introduced in PHP 5.5.
+
+
+
+
json_validate()
+
+ Checks if a string contains valid JSON.
+ Introduced in PHP 8.3.
+
+
+
+
http_build_url()
+
+ The reverse function of parse_url(). It is defined in a PECL extension, but not every server has the extension loaded, and not everyone has the option to change installed PHP modules.
+ Defined in pecl_http >= 0.21.0.
+
:everything - Like :any, but also matches "nothing"
:segment - This matches only 1 segment in the URI, but that segment can be anything
:num - This matches any numbers
+
:decimal - This matches decimal values, with support for both decimal point and decimal comma.
:alpha - This matches any alpha characters, including UTF-8
:alnum - This matches any alphanumeric characters, including UTF-8
@@ -107,6 +108,11 @@
Slightly Advanced Routing
'(\d{2})/about' => 'site/about/$1', // Routes /12/about to /site/about/12
);
+
+ Note that you need to disable "routing.strip_extensions" in your application config when
+ you want to use ":decimal", as by default everthing after a dot will be seen as
+ extension and stripped. This is not an issue when you use a decimal comma.
+
Advanced Routing
@@ -206,6 +212,37 @@
Inline routes
}
};
+
Route recursion
+
+
+ By default, the requested URI is processed by the routing engine only once. Using the configuration key 'routing.recursive',
+ you can enable recursive route lookups.
+
+
+
+ This means that when a given URI resolves to a defined route, but this route doesn't resolve to a valid controller action,
+ the resulting route is reprocessed. This allows you to define aliases or redirects:
+
+
+
<?php
+return array(
+ // default routes
+ '_root_' => 'homepage/index',
+
+ // alias in another language
+ 'un/:slug' => 'one/$1',
+ 'deux/:slug' => 'two/$1',
+ 'trois/:slug' => 'three/$1',
+
+ // redirect old uri's
+ 'old/uri/:slug' => 'controller/new/$1',
+
+ // site routes
+ 'one/:slug' => 'controller/one/$1',
+ 'two/:slug' => 'controller/two/$1',
+ 'three/:slug' => 'controller/three/$1',
+);
- FuelPHP is a simple, flexible, community driven PHP 5 web framework. It was born out of the frustrations people have with the current available frameworks and developed
- with support from a community of developers. FuelPHP is extremely portable, works on almost any server and prides itself on clean syntax.
+ FuelPHP is a simple, flexible, community driven PHP framework for developing web based applications.
+ It is compatible with every PHP version from 5.3.3 onwards, and prides itself on providing maximum
+ backward compatibility.
+
+ It was born out of the frustrations people have with the current available frameworks and developed
+ with support from a community of developers. FuelPHP is extremely portable, works on almost any server
+ and prides itself on clean syntax.
Check the phpinfo(); in a separate testfile and see if you're running 5.3 or higher. More info on requirements is here.
-
When developing locally, update your server to the latest version of PHP 5.3. If you are not developing locally you'll need to ask your hosting company. Versions of PHP below 5.3 have lost support not just by us, but by PHP themselves.
+
When developing locally, update your server to the latest version of PHP supported. If you are not developing locally you'll need to ask your hosting company.
this makes it possible to login in multiple ways at the same time.
+
+
login_type
+
string
+
'both'
+
+ The type of login you want to utilize. Valid values are "username", "email" or "both".
+
+
salt
string
@@ -163,6 +171,14 @@
Configuration
login drivers, it does not mean "allow a user to be logged-in multiple times"!
+
+ Note that for 'login_type', "both" is the default for compatibility with existing installations, but should be used with
+ caution, as theoretically, you can create a user with as the username the email address from an existing user, and thus
+ potentionally hijack or block that account.
+ Also, even though in most methods both values where checked, not all methods did support checking both, or could find multiple
+ user records and blindly use the first one found. Which is another reason not to use "both" !
+
The change_password method allows you to change a users password.
@@ -461,9 +461,9 @@
change_password($old_password, $n
The users new password
-
$username
-
null
-
The name of the user of whom you want to change the password
+
$username_or_email
+
''
+
Either the users username or email address of the user you want to change the password of (depending on the "login_type" config setting). If not given, the currently logged-in user is assumed.
@@ -493,7 +493,7 @@
change_password($old_password, $n
-
reset_password($username)
+
reset_password($username_or_email)
The reset_password method allows you to assign a new random password to a user.
@@ -513,9 +513,9 @@
reset_password($username)
Description
-
$username
-
required
-
The name of the user for whom you want to reset the password
+
$username_or_email
+
''
+
Either the users username or email address you want to reset the password for (depending on the "login_type" config setting).
@@ -541,7 +541,7 @@
reset_password($username)
-
delete_user($username)
+
delete_user($username_or_email)
The delete_user method allows you to delete a user account.
@@ -561,9 +561,9 @@
delete_user($username)
Description
-
$username
-
required
-
The name of the user account you want to delete
+
$username_or_email
+
''
+
Either the users username or email address of the user you want to delete (depending on the "login_type" config setting).
@@ -586,7 +586,7 @@
delete_user($username)
-
This will delete all metadata too, using ORM's cascade_delete feature.
+
This will delete all metadata too, using ORM's "ON DELETE CASCADE" feature.
The has_any_access method uses the defined ACL drivers to check the users access according to the given array of conditions.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$conditions
+
required
+
takes a array of locations and the required rights on the location as either a string or array
+
+
+
$entity
+
required
+
user or group identifier in the form of array(driver_id, id).
+
+
+
+
+
+
Returns
+
boolean, true if access was granted to ANY of the given conditions, false if not.
+
+
+
Example
+
+
// check if user is allowed to comment when one right is granted
+if ( ! Auth::acl()->has_any_access(array('comments.create', 'comments.edit')))
+{
+ Response::redirect('no_admin');
+}
+
+
+
+
+
+
+
+
has_all_access($conditions, Array $entity)
+
The has_all_access method uses the defined ACL drivers to check the users access according to the given array of conditions.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$conditions
+
required
+
takes a array of locations and the required rights on the location as either a string or array
+
+
+
$entity
+
required
+
user or group identifier in the form of array(driver_id, id).
+
+
+
+
+
+
Returns
+
boolean, true if access was granted to ALL of the given conditions, false if not.
+
+
+
Example
+
+
// check if user is allowed to comment when both rights are granted
+if ( ! Auth::acl()->has_all_access(array('comments.create', 'comments.edit')))
+{
+ Response::redirect('no_admin');
+}
- The default setup to use if none is profided.
+ The default setup to use if none is provided.
@@ -132,7 +132,7 @@
Group configuration
useragent
string
-
'FuelPHP, PHP 5.3 Framework'
+
'FuelPHP, PHP Framework'
The user agent.
@@ -209,6 +209,17 @@
Group configuration
Use this to set a default from name.
+
+
force_to
+
null|string
+
null
+
+ Set to a valid email address to force all outgoing emails to be
+ send to this address instead.
+ This allows you to test outgoing emails without sending them to real addresses
+ by mistake.
+
+
validate
bool
@@ -341,6 +352,19 @@
Group configuration
https://, since some Email clients (Outlook!) do not support relative protocol URI's.
+
+
+
+
Mandrill configuration
+
+
+
+
+
Param
+
Type
+
Default
+
Description
+
mandrill.key
string
@@ -385,10 +409,9 @@
Group configuration
- Make sure to install mandrill/mandrill composer package if you want to use the mandrill driver.
+ Make sure to install the mandrill/mandrill composer package if you want to use the mandrill driver.
-
Mailgun configuration
@@ -400,7 +423,7 @@
Mailgun configuration
Description
-
key
+
mailgun.key
string
'YOUR KEY'
@@ -408,7 +431,7 @@
Mailgun configuration
-
domain
+
mailgun.domain
string
'YOUR DOMAIN'
@@ -416,24 +439,29 @@
Mailgun configuration
-
endpoint
+
mailgun.endpoint
string|null
'ALTERNATIVE API ENDPOINT URL'
- (OPTIONAL) Omit entirely or set to null to use Mailgun's default endpoint.
- Can be set to match the region in which the domain is provisioned.
+ (OPTIONAL) Omit entirely or set to null to use Mailgun's default endpoint.
+ Can be set to match the region in which the domain is provisioned.
Example: 'https://api.eu.mailgun.net/v3'
+
+
+ Make sure to install the mailgun/mailgun-php composer package if you want to use the mandrill driver.
+
Note that while RFC5322 explicitly allows multiple From addresses, we do not support this, as most email clients can handle this.
+
+
@@ -432,11 +446,17 @@
to($email, $name = false)
// Add a single address
$email->to('me@example.com', 'My Name');
-// Add multiple addresses
+// Using an assoc array
+$email->to(array(
+ 'email' => 'me@example.com',
+ 'name' => 'My Name',
+));
+
+// Or as an key-value array
$email->to(array(
'me@example.com',
// with a name
- 'me@example.com' => 'His/Her name.',
+ 'me@example.com' => 'My Name',
));
@@ -489,11 +509,17 @@
cc($email, $name = false)
// Add a single address
$email->cc('me@example.com', 'My Name');
-// Add multiple addresses
+// Using an assoc array
+$email->cc(array(
+ 'email' => 'me@example.com',
+ 'name' => 'My Name',
+));
+
+// Or as an key-value array
$email->cc(array(
'me@example.com',
// with a name
- 'me@example.com' => 'His/Her name.',
+ 'me@example.com' => 'My Name',
));
@@ -546,11 +572,18 @@
bcc($email, $name = false)
// Add a single address
$email->bcc('me@example.com', 'My Name');
-// Add multiple addresses
+// Using an assoc array
+$email->bcc(array(
+ 'email' => 'me@example.com',
+ 'name' => 'My Name',
+));
+
+// Or as an key-value array
$email->bcc(array(
+ // without a name
'me@example.com',
// with a name
- 'me@example.com' => 'His/Her name.',
+ 'me@example.com' => 'My Name',
));
@@ -603,17 +636,25 @@
reply_to($email, $name = false)
// Add a single address
$email->reply_to('me@example.com', 'My Name');
-// Add multiple addresses
+// Using an assoc array
+$email->reply_to(array(
+ 'email' => 'me@example.com',
+ 'name' => 'My Name',
+));
+
+// Or as an key-value array
$email->reply_to(array(
+ // without a name
'me@example.com',
// with a name
- 'me@example.com' => 'His/Her name.',
+ 'me@example.com' => 'My Name',
));
+
Note that while RFC5322 explicitly allows multiple Reply-To addresses, it is discouraged to use this, as not all email clients can handle this.
@@ -742,7 +783,7 @@
clear_addresses()
$email->to(array(
'me@example.com',
// with a name
- 'me@example.com' => 'His/Her name.',
+ 'me@example.com' => 'My Name',
));
// Reset them
@@ -1485,7 +1526,7 @@
custom properties and relations, allowing you to exclude properties from all of them.
+
protected static $_property_map
+
+
+ Sometimes you run into issues where column names in a database are not compatible or practical for use
+ in PHP. For example, some database platforms allow characters like "<" or ">", or even spaces, in
+ column names.
+
+
+
+ This is not an issue for the database itself, for the queries the ORM generates, or for creating ORM model
+ objects, but it is for accessing the data. After all, you can't have spaces in an object property name, and
+ names like "$model->small<large" are illegal in PHP. To deal with this, you can create a
+ property map, in which you map column names to property names:
+
+ This mapping allows you to access the column values using "$model->with_no_space" and "$model->small_large".
+
+
+
+ In terms of precedence, mapped property names are checked after real properties, relations and EAV properties, but before
+ any custom properties the model object my have.
+
// set up the statistics relation the usual way
protected static $_has_many = array(
'statistics' => array(
- 'key_from' => 'id', // key in this model
- 'model_to' => 'Model_Statistic', // related model
- 'key_to' => 'patient_id', // key in the related model
- 'cascade_save' => true, // update the related table on save
- 'cascade_delete' => true, // delete the related data when deleting the parent
+ 'key_from' => 'id', // key in this model
+ 'model_to' => 'Model_Statistic', // related model
+ 'key_to' => 'patient_id', // key in the related model
+ 'cascade_save' => true, // update the related table on save
+ 'constraint' => \Orm\Relation::CONSTRAINT_CASCADE, // delete the related data when deleting the parent
)
);
@@ -126,7 +126,7 @@
+ Contrary to popular belief, an ORM model is not the same a an application model. ORM models map directly to a single record (the Active Active Record Pattern),
+ where as application model classes contain your business logic, and may (or may not) use the ORM to access the data in the configured storage backend.
+
+
+ Although it is possible, and perfectly fine in most cases, to use the ORM directly in your controllers, it is strongly advised not to do so, but seperate your controller logic from your business logic,
+ which makes it a lot easier to make changes to that logic without having to search through all your controllers and other classes to make sure the changes have no side effect. Prime examples are for
+ example changes in database relations, adding or removing columns, and or changing the meaning or contents of a column.
+
+
+ The most common way to seperate the two types of model is to put them into different namespaces in your application, so you have no name collisions and you can not accidentially mix up the two.
+
+
+
+
Installation
@@ -59,6 +77,65 @@
Installation
),
+
+
+
Configuration
+
+
There are a few features or behaviours in the ORM that are configurable:
+
+
+
+
+
Param
+
Type
+
Default
+
Description
+
+
+
caching
+
bool
+
true
+
+ By default, the ORM caches all hydrated objects, so that when you request the same object a second time, you get the cached
+ (and potentially modified!) object, and not a new object for the same record (which can lead to data inconsistency).
+ You can override whatever default you set on a per-query basis if needed using the caching() method.
+
+
+
+
relation_lazy_load
+
bool
+
false
+
+ When set to true, an isset() or empty() check on an object relation will always return true,
+ whether or not the related records are fetched. When the actual related records are accessed, they will be "lazy loaded" with
+ an additional query.
+
+
+
+
sql_max_timestamp_mysql
+
string
+
'2038-01-18 22:14:08'
+
+
+
+
+
sql_max_timestamp_unix
+
integer
+
2147483647
+
+ Used to set the upper limit for the timestamp in the Temporal model<.strong>, if no limit is given.
+
+
+
+
+
+
+ Lazy loading of relations was default behavior in the ORM prior to version 1.9. If you have an application that relies on this, do not forget
+ to enable this feature in the config when you upgrade your application to this or a later version!
+
+
+
+
Object Caching
@@ -184,7 +261,7 @@
My query result doesn't reflect the record values in the database
+ The ORM Model Class is not only the container for a database record, it also provides methods to manipulate the object and its data.
+
+
+
+
cached_object($objpk, $class = null)
+
The cached_object method allows you to retrieve specific model object from the object cache, by primary key and model class name.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$objpk
+
required
+
The primary key value of the model object you want to retrieve. If the model has a compound primary key, you can pass the key values in an array, in the order the keys are defined in the model.
+
+
+
$class
+
null
+
The model you want to lookup. If not given, the current model name is used.
+
+
+
+
+
+
Returns
+
Orm\Model | false
+
+
+
Example
+
+
// tries to retrieve OtherModel object with primary key value "12" from the cache
+$from_cache = MyModel::cached_object(12, 'OtherModel');
+
+
+
+
+
+
+
+
condition($type = null)
+
The condition method allows you to retrieve the models defined conditions.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$type
+
null
+
The type of condition you want to retrieve. Currently supported are 'order_by' and 'where'. When no type is given, all conditions are returned.
+
+
+
+
+
+
Returns
+
array()
+
+
+
Example
+
+
// tries to retrieve MyModel where conditions
+$where = MyModel::conditions('where');
+
+
+
+
+
+
+
+
connection($writeable = false)
+
The connection method allows you to retrieve the models defined database connection.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$writeable
+
false
+
The type of connection you want to retrieve. A model can have seperate connection definitions for read and write operations. By default, the read connection is returned.
+
+
+
+
+
+
Returns
+
string | null
+
+
+
Example
+
+
// retrieves the MyModel write connection
+$where = MyModel::connection(true);
+
+
+
+
+
+
+
+
find($id = null, $options = null)
+
The find method allows you to retrieve a record as a model object or an array of model objects.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$id
+
null
+
The primary key of the record you want to retrieve, or one of the special keywords 'all', 'first' or 'last'.
+
+
+
$options
+
null
+
Array of options that can be passed, including relations and query conditions.
+
+
+
+
+
+
Returns
+
Orm/Model | array | null
+
+
+
+
See the CRUD documentation for detailed examples on how to use this method.
+
+
+
+
flush_cache($class = null)
+
The flush_cache method allows you to (selectively) delete model objects from the object cache.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$class
+
null
+
+ If not given, the entire cache is emptied. Optionally you can specify a model (either as a string containing a class name,
+ or a model object, and only flush the cache for that model.
+
+
+
+
+
+
+
Returns
+
void
+
+
+
+
+
+
+
primary_key()
+
The primary_key method returns an array with the column names that define the tables primary key.
+
+
+
+
Static
+
Yes
+
+
+
Returns
+
array
+
+
+
Example
+
+
// returns array('id') for default PK's
+$pk = MyModel::primary_key();
+
+
+
+
+
+
+
+
implode_pk($data)
+
The implode_pk method allows you convert the value of a (compound) primary key into a string.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$data
+
required
+
+ Either an array with key-value pairs, or an object with properties. All column names that are part of
+ the models primary key must be present, no validation is done.
null
is returned
+ if the data doesn't contain all key values.
+
+
+
+
+
+
+
Returns
+
string | null
+
+
+
Example
+
+
// with PK defined as both columns "A" and "B", this returns "[1][2]"
+$pk = MyModel::implode_pk(array('A' => 1, 'B' => 2));
The forge method allows you to forge a new model instance.
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$data
+
array()
+
+ Multi-dimensional array of data to populate the new model object. This array may included data for
+ related model objects.
+
+
+
+
$new
+
true
+
+ If set to
false
,
$data
+ must contain at least all primary key values. The object will be set to "loaded" state, as if it was retrieved from the
+ database. This is mainly used after reading data from the database and hydrating it into model objects, or to recreate
+ objects from data stored elsewhere, for example in an external cache.
+
+
+
+
$view
+
null
+
+ Used internally when models are created from on of the table views defined in the model. It changes the model object into
+ a read-only state.
+
+
+
+
$cache
+
true
+
+ If set to true and
$new
set to false, and the data given contains all PK values, any existing
+ model object is cache is returned, instead of a newly instantiated object, optionally updated with any remaining data passed.
+
+
+
+
+
+
+
Returns
+
string | null
+
+
+
Example
+
+
// create a new MyModel model object
+$mymodel = MyModel::forge();
+
+
+
+
+
+
+
+
get_filtered_properties()
+
+ The get_filtered_properties method returns the list of properties returned by a call to
to_array()
.
+ It will take into account the list of excluded property names defined in the model.
+
+
+
+
+
Static
+
Yes
+
+
+
Returns
+
array
+
+
+
Example
+
+
// with PK defined as both columns "A" and "B", this returns "[1][2]"
+$pk = MyModel::implode_pk(array('A' => 1, 'B' => 2));
+
+
+
+
+
+ Excluding properties can come in handy for properties you don't want to expose, for example if you want to return model data to the caller in a JSON response.
+ See the static model property $_to_array_exclude.
+
+
+
+
+
max($key = null)
+
+ The max method returns the maximum value of the given column name.
+
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$key
+
null
+
+ Name of a numeric table column. If not given, the primary key column is used.
+
+
+
+
+
+
+
Returns
+
int | bool
+
+
+
Example
+
+
// get the last id issued
+$last = MyModel::max('id');
+
+
+
+
+
+ This method does not support compound primary keys (as you can only query MAX() on a single column), and will return false if there is no result.
+
+
+
+
+
min($key = null)
+
+ The min method returns the minimum value of the given column name.
+
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$key
+
null
+
+ Name of a numeric table column. If not given, the primary key column is used.
+
+
+
+
+
+
+
Returns
+
int | bool
+
+
+
Example
+
+
// get the first id issued
+$last = MyModel::min('id');
+
+
+
+
+
+ This method does not support compound primary keys (as you can only query MAX() on a single column), and will return false if there is no result.
+
+
+
+
+
observers($specific = null, $default = null)
+
+ The observers method returns a list of all observers defined in the model.
+
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$specific
+
null
+
+ Name of a spefific observer to get the definition of. Supports dot-notation to directly get any array element in the definition.
+ If none given, it will return all observers defined in the current model class.
+
+
+
+
$default
+
null
+
+ The value to return is no data was found.
+
+
+
+
+
+
+
Returns
+
mixed
+
+
+
Example
+
+
// get the observers defined in the model
+// might return array('Orm\Observer_Typing' => array())
+MyModel::observers();
+
+
+
+
+
+ The array value associated with the observer in the result will contain the additional configuration the observer requires.
+
+
+
+
+
properties()
+
+ The properties method returns an array of all properties (i.e. column names) defined in the model class.
+
+
+
+
+
Static
+
Yes
+
+
+
Returns
+
array
+
+
+
+
+ Note: If the model does not define its properties, the ORM will attempt to generate it dynamically, by running
+ a "list all columns" query on the defined table. As this is performance impacting, you should not use this in a production
+ environment, but you could dump the generated array, and use that to populate the model properties array.
+
+
+ Not all database drivers support a "list all columns" method, and will throw an exception instead.
+
+
+
+
+
property($key, $default = null)
+
+ The property method returns the definition of a single model class property.
+
+
+
+
+
Static
+
Yes
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$key
+
required
+
+ Name of a property you want to query.
+
+
+
+
$default
+
null
+
+ The value to return is no data was found.
+
+
+
+
+
+
+
Returns
+
mixed
+
+
+
Example
+
+
// get the definition of the primary key
+MyModel::property('id');
+
+
+
+
+
+ If no properties are defined in the model class, a call to properties() will be made in an attempt to generate them.
+
+
+
+
+
query()
+
+ The query method returns an ORM query object for the current model class.
+
+
+
+
+
Static
+
Yes
+
+
+
Returns
+
ORM\Query
+
+
+
Example
+
+
// get query object, and get the first record
+$query = MyModel::query()->get_one();
+
+
+
+
+
See the CRUD documentation for detailed examples on how to use this method.
+
+
+
+
related_class($relation)
+
+ The related_class method returns the name of the ORM model class a relation maps to.
+
+ The generated table name will be derived from the model name, after the namespaces and any "model_" prefix is stripped, lowercase, and made plural (for english names only).
+ So "\Some\Model_Cat" will map to a table called "cats".
+
+
+
+
+
delete($cascade = null, $use_transaction = false)
+
The delete method deletes the record associated with the current model object from the database.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$cascade
+
null
+
+ This argument allows you to override the constraint definition on a relation.
null
is the default behavior,
+ in which case the constraint as defined on the relation will be used.
+
true
is the equivalent of \Orm\Relation::CONSTRAINT_CASCADE, while
false
+ is the equivalent of \Orm\Relation::CONSTRAINT_SETDEFAULT.
+
+
+
+
$use_transaction
+
false
+
+ Whether or not you want to wrap the delete in a database transaction. This allows automatic rollback, especially important when you use cascading deletes and
+ one of them fails. Without a transaction, you'll end up with partially deleted relations.
+
+
+
+
+
+
+
Returns
+
Model | false
+
+
+
Example
+
+
// delete the current record
+$record->delete();
+
+
+
+
+
+ When the delete() operation fails logically, the method returns false. Otherwise it will return a new model
+ instance, retaining all model data but with the primary keys reset, so a model in new state.
+
+
+ Note also that database exceptions that drivers might throw are not caught in this method !
+
+
+
+
+
disable_event($event)
+
The disable_event method allows you to disable a particular observer event defined in the model on a per-model instance basis.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$event
+
required
+
+ Name of the event to disable. Supported are 'after_load', 'after_create', 'after_clone', 'before_save', 'after_save', 'before_insert', 'after_insert',
+ 'before_update', 'after_update', , 'before_delete' and 'after_delete'.
+
+
+
+
+
+
+
Returns
+
void
+
+
+
Example
+
+
// disable the after_save observers
+$record->disable_event('after_save');
+
+
+
+
+
+
+
+
enable_event($event)
+
The disable_event method allows you to enable a particular observer event that was disabled previously. See disable_event().
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$event
+
required
+
+ Name of the event to disable. Supported are 'after_load', 'after_create', 'after_clone', 'before_save', 'after_save', 'before_insert', 'after_insert',
+ 'before_update', 'after_update', , 'before_delete' and 'after_delete'.
+
+
+
+
+
+
+
Returns
+
void
+
+
+
Example
+
+
// remove a defined block of all after_save observers
+$record->enable_event('after_save');
+
+
+
+
+
+
+
+
from_array(array $values, $from_cache = false)
+
The from_array method allows you to populate a model object, and optionally related models objects, from a multi-dimensional array.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$values
+
required
+
+ Multi-dimensional array of key-value pairs, representing column names and column values.
+
+
+
+
$from_cache
+
false
+
+ When set to true, the model object cache will be checked before creating any related model objects from the data passed.
+
+
+
+
+
+
+
Returns
+
Model, the current object, for chaining.
+
+
+
Example
+
+
// create a model object and populate it
+$mymodel = MyModel::forge();
+$mymodel->from_array($data);
+
+//NB: this is identical to:
+$mymodel = MyModel::forge($data);
+
+
+
+
+
+ Be careful with enabling $from_cache. As objects are passed around by reference in PHP, modifying a cached object with the data
+ passed will also modify any variable containing a reference to that object. This can lead to unexpected results and possible data corruption !
+
+
+
+
+
get($property, array $conditions = array())
+
The get method allows you to get a property from the model object. Properties include columns, related objects, EAV values or custom/runtime data stored in the object.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$property
+
required
+
+ The name of the property whos value you want to retrieve.
+
+
+
+
$conditions
+
array()
+
+ Only used for relations that aren't fetched yet. This allows you to add additional conditions (order_by or where clauses)
+ to the query that will fetch the related model objects. This allows you to fetch a subset, or to alter the default ordering.
+
+
+
+
+
+
+
Returns
+
mixed
+
+
+
Example
+
+
// get all the related child records (from a defined related called 'children')
+$mymodel->get('children');
+
+
+
+
+
+
+
+
get_diff()
+
The get_diff method returns an array with all properties that have been modified on the object since it was loaded.
The is_changed method allows you to test if a model object has been altered since it was loaded.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$property
+
null
+
+ The name of specific property whos value you want to check for changes. If not given, or
null
,
+ all properties will be checked.
+
+
+
+
$observe
+
false
+
+ Whether or not 'before_save' observers should run. This can be desirable since you could have observers defined
+ on the model that would autonomously alter data when saving the model, without code or user interaction being involved.
+
+
+
+
$recurse
+
false
+
+ When
true
, it will call
is_changed()
+ on any related object of relations given in $property.
+
+
+
+
+
+
+
Returns
+
bool
+
+
+
Example
+
+
// you can use get_diff() to check what has changed
+if ($mymodel->is_changed()
+{
+ echo "something has changed in the object !";
+}
+// not only check if child objects were added or removed, but
+// also if loaded child objects themselfs have been modified
+if ($mymodel->is_changed('child', false, true)
+{
+ echo "something related to 'child' model objects is changed";
+}
+
+
+
+
+
+ Using the $recurse option is particularly handy if you've loaded a hierarchical tree of model objects, with relations that
+ have "cascade_save" enabled, or use an "EAV" container, so it returns a true status of the fact something in the chain needs saving.
+
+
+
+
+
is_fetched($relation)
+
The is_fetched method allows you check if related objects have been loaded.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$relation
+
required
+
+ The name of the relation you want to check.
+
+
+
+
+
+
+
Returns
+
bool
+
+
+
Example
+
+
if ( ! $mymodel->is_fetched('children'))
+{
+ echo "no child records have been loaded yet !";
+}
+
+
+
+
+
+ Note that you can't use isset($mymodel->children), as that would access the property, which in turn would trigger a query
+ to autoload the related records (which in turn would make is_fetched() return true) !
+
+
+
+
+
is_new()
+
The is_new method can be used to check if the object has a representation in the database, i.e. if a corresponding record exists.
+
+
+
+
Static
+
No
+
+
+
Returns
+
bool
+
+
+
Example
+
+
if ( ! $mymodel->is_new())
+{
+ echo "no record exists of this object yet";
+}
+
+
+
+
+
+ Note that that if your model uses database assigned primary keys (like AUTO_INCREMENT or SERIAL), the objects primary key properties will not
+ have a value at this point. But the absence of such values doesn't say anything about the "new" state, as the model could have primary key
+ values that are manually assigned or generated by observers, in which case it could already have a primary key set, even though it is still
+ classified as "new".
+
+
+
+
+
is_parent($all = false)
+
The is_new method can be used to check if the object has a representation in the database, i.e. if a corresponding record exists.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$all
+
false
+
+ If set to
false
, it will return
true
+ as soon as a relation is detected of which the current model object is a parent. Otherwise, it will check all relations, and will
+ return an array of relations from which the current model object is a parent (which could be empty).
+
+
+
+
+
+
+
Returns
+
bool | array
+
+
+
Example
+
+
if ($rels = $mymodel->is_parent(true))
+{
+ echo "don't delete it, it still has child records in " . impode(",", $rels) . " !";
+}
+
+
+
+
+
+ You can use this as a manual foreign key check, either because you don't want to wait for a database driver exception in case of a foreign key
+ violation, or because the database you work with doesn't have any foreign key constraints defined, and you want to make sure you don't want to
+ corrupt the database by leaving child records without a parent.
+
+
+
+
+
reset()
+
The reset method deletes all changes made to the model object, and resets it to the state it was after loading.
+
+
+
+
Static
+
No
+
+
+
+
+ If you call reset() on an object in "new" state, it will be completely wiped, like you had just called ClassName::forge().
+
+
+
+
+
save($cascade = null, $use_transaction = false)
+
The save method save the record associated with the current model object to the database, by using an INSERT if the object is in "new" state, or an UPDATE if not.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$cascade
+
null
+
+ This argument allows you to control cascading save behaviour.
null
is the default behavior,
+ configured in the relations of the model.
true
or
false
+ explicitly enables or disables cascading saves, or you can pass an array with relation names, if you want selective cascading saves.
+
+
+
+
$use_transaction
+
false
+
+ Whether or not you want to wrap the save in a database transaction. This allows automatic rollback, especially important when you use cascading saves and
+ one of them fails for some reason. Without a transaction, you'll end up with partially saved relations.
+
+
+
+
+
+
+
Returns
+
Model | false
+
+
+
Example
+
+
// saves the current record
+$record->save();
+
+
+
+
+
+ When the save() operation fails logically, the method returns false. Otherwise it will return true.
+
+
+ Note also that database exceptions that drivers might throw are not caught in this method !
+
The to_array method allows you to convert the model object, any relational data loaded, and optionally any custom/runtime data or EAV data, to be return as a multi-dimensional array.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$custom
+
false
+
+ Set this to true if you want to include custom or runtime data stored in the model object.
+
+
+
+
$recurse
+
false
+
+ Used internally for object recursion detected. No NOT EVER set this to anything other than
false
or weird things will happen!
+
+
+
+
$eav
+
false
+
+ Set this to true if you want to include EAV properties stored in the model object.
+
+
+
+
+
+
+
Returns
+
array
+
+
+
Example
+
+
// dump the contents of the current object into an array
+$array = $record->to_array();
+
+
+
+
+
+ Did I mention not to set the recurse variable to anything other than false?
+
+
+
+
+
to_object($custom = false)
+
The to_object method allows you to convert the model object into a StdClass object with only the data properties.
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+
+
+
Param
+
Default
+
Description
+
+
+
$custom
+
false
+
+ Set this to true if you want to include custom or runtime data stored in the model object.
+
+
+
+
+
+
+
Returns
+
StdClass
+
+
+
Example
+
+
// these are identical
+$obj1 = $record->to_object();
+$obj2 = (object) $record->to_array();
// Does Ben have a next sibling? echo's 'false'
echo $ben->has_next_sibling() ? 'true' : 'false';
+
+
+
+
+
+
+
+
+
has_siblings()
+
+ The has_siblings method tells you if the object you're calling it on has any siblings, i.e. if it is the only child or not.
+
+
+
+
+
Static
+
No
+
+
+
Parameters
+
+ None.
+
+
+
+
Returns
+
Bool, true if the object has siblings, false if not
+
+
+
Example
+
+
// Does Henry have siblings? echo's 'true'
+echo $henry->has_siblings() ? 'true' : 'false';
+
+// Does Tim have siblings? echo's 'false'
+echo $tim->has_siblings() ? 'true' : 'false';
@@ -1972,7 +2008,7 @@
related($relation, $conditions = array())
$related
required
-
The name of the relation to include.
+
The name of the relation to include, or an array with relation names and/or relation/condition combinations.
$conditions
@@ -1992,6 +2028,15 @@
related($relation, $conditions = array())
// include related 'child' objects in the result
$tree = $bill->related('child')->dump_tree();
+// include related 'child' and 'granbchild' objects in the result
+$tree = $bill->related('child')->related('grandchild')->dump_tree();
+
+// alternative, with conditions
+$tree = $bill->related(array(
+ 'child',
+ 'grandchild' => array('order_by' => array('age', 'asc'))
+ ))->dump_tree();
+
// get the descendants of $ben
$descendants = $ben->descendants()->related('child')->get();
@@ -2011,7 +2056,7 @@
The delete function will soft delete related models providing that cascade_delete is true. If the related model is not soft delete as well then a RelationNotSoft exception is thrown.
+
The delete function will soft delete related models providing that constraint is set to \Orm\Relation::CONSTRAINT_CASCADE. If the related model is not soft delete as well then a RelationNotSoft exception is thrown.
Restore
-
The restore function will also restore related entries providing the cascade_delete is true for the relation.
+
The restore function will also restore related entries providing the constraint is set to \Orm\Relation::CONSTRAINT_CASCADE for the relation.
This method will delete the object from the database. It works in exactly the same way as the normal Model's delete function except that the information is not removed from the database. This means that you can still reference the object at a given time, but it is no longer valid for the present.
+
+ This method will delete the object from the database. It works in exactly the same way as the normal Model's delete function except that the information is not removed
+ from the database, but the end-timestamp will be set on the record. This means that you can still reference the object at a given time, but it is no longer valid for the present.
While not exactly good practice, in some cases it's probably cleanest to just have the event method with
- your model. That's where the Observer_Self comes in, it checks if you model has a method named after
- the event and prefixed with _event_. For example for the after_save event you need
- to add a public method _event_after_save() to your model so it can have the observer call on
- the model itself.
+
This observer logs changes made to model objects, when you insert, update or delete them.
+
+
Making this observer work requires some configuration in the ORM configuration file:
+ You need to explicitly enable the observer in the configuration (adding the observer to the model alone is not enough),
+ you need to define the name of the audit table to use, and you need to define which session value defines the session
+ uniquely. If you don't define a session key, the internal session key (the value returned by Session::key()) is used.
+
+
+
+ The audit observer uses two tables to record changes: the audit log table, named in the configuration, containing a single
+ record per session, uniquely identifying the session, the user, and timestamps for the first and last change in the session.
+ And a table recording the model name, the operation type and the model property diff, in json format. It uses the table name
+ defined in the configuration, with a "_diff" suffix.
+
+
+
These are the definitions for the audit tables (here called "audit" and "audit_diff"):
Once setup, all that remains is to add the observer to your models:
// Just add the Observer
-protected static $_observers = array('Orm\\Observer_Self');
+protected static $_observers = array('Orm\\Observer_Audit');
+);
-// But if you only observe some events you can optimize by only adding those
-protected static $_observers = array('Orm\\Observer_Self' => array(
- 'events' => array('after_save', 'before_insert')
-));
+
+ Note that this records every change to your tables if they are updated via ORM models, which means that especially
+ the diff table can grow large very rapidly, especially in large and much used applications. So make sure you have
+ provisions in place to keep the size of the tables under control, either by purging older records, or migrating
+ older records to archival storage.
+
Observer_CreatedAt
@@ -94,6 +142,122 @@
Observer_CreatedAt
If you want to be able to set the created_at timestamp in your code, set the 'overwrite' property to false.
This will cause the observer to keep the value you have set manually.
+
Observer_Typing
+
+
+ This is for 2 things: type enforcement for input and type casting for output from the DB. That means
+ that when you're saving the Typing observer will try to cast the input value to the expected type and
+ throw an exception when it can't. And when you're retrieving DB data, normally it would all be strings
+ (even integers and floats) but with the typing observer those will be cast to their scalar type.
+
+
+
In addition to the above the Typing observer also adds support for serialized & json fields. Both should
+ be string type fields ("text" preferably) but will have their value encoded for saving (using
+ serialize() or json_encode()) and decoded when retrieving from the DB (using
+ unserialize() or json_decode()).
+
+
The Observer_Typing isn't meant as an alternative to validation, don't try to use it as
+ such. Neither are the exceptions thrown by this observer meant to be read by the visitor of your site,
+ they're meant to help you debug your code.
+
+
// Just add the Observer
+protected static $_observers = array('Orm\\Observer_Typing');
+
+// But adding it just for these specific events is enough
+protected static $_observers = array('Orm\\Observer_Typing' => array(
+ 'events' => array('before_save', 'after_save', 'after_load')
+));
+
+
+ For this observer to work you must have your the $_properties static variable set in your
+ model, or not set at all using detection with DB::list_columns() (MySQL only!). When
+ configuring it yourself the following settings are available:
+
+ The SQL data type, Required to have the typing observer used on a field.
+
+
+
+
db_decimals
+
int
+
Number of decimals the value in the database has, if different from the specification in "data_type".
+
+
+
null
+
bool
+
+ Whether null is allowed as a value, default true
+
+
+
+
character_maximum_length
+
int
+
+ The maximum number of characters allowed for a string data type (varchar, text, serialized or encrypted result)
+
+
+
+
encryption_key
+
string
+
+ A custom encryption key to encrypt and decrypt this value. If given, it will replace the "crypto_key" set in the Crypt config file.
+
+
+
+
min
+
int
+
+ The minimal value for an integer
+
+
+
+
max
+
int
+
+ The maximum value for an integer
+
+
+
+
options
+
array
+
+ Array of valid string values for set or enum data type
+ Note: currently the options themselves cannot contain comma's.
+
+
+
+
+
+ In case of data_type "decimal", you can suffix the type with the number of decimals required. If defined,
+ the value returned is a string, formatted with the defined number of decimal digits, and taking the
+ current defined locale into account.
+
+
+
+ The date and time related data types will be converted to and from a Date object.
+
+
+
+ By default the Typing observer is locale aware, meaning that it can deal with incoming string values
+ that use a decimal comma for fields defined as decimal or float, if the current locale defines the
+ decimal separator as a comma. It will also format outgoing decimal values according to the current
+ locale settings. You can disable this by defining the "orm.use_locale" config key, either in your
+ main config.php file or in a separate orm.php config file, and set it to false.
+
+
Observer_UpdatedAt
This observer acts only upon before_save or before_update and expects your model to have a
@@ -285,118 +449,22 @@
Observer_Validation
// The fieldset will be build as HTML when cast to string
echo $fieldset;
-
Observer_Typing
-
-
- This is for 2 things: type enforcement for input and type casting for output from the DB. That means
- that when you're saving the Typing observer will try to cast the input value to the expected type and
- throw an exception when it can't. And when you're retrieving DB data, normally it would all be strings
- (even integers and floats) but with the typing observer those will be cast to their scalar type.
-
-
-
In addition to the above the Typing observer also adds support for serialized & json fields. Both should
- be string type fields ("text" preferably) but will have their value encoded for saving (using
- serialize() or json_encode()) and decoded when retrieving from the DB (using
- unserialize() or json_decode()).
+
Observer_Self
-
The Observer_Typing isn't meant as an alternative to validation, don't try to use it as
- such. Neither are the exceptions thrown by this observer meant to be read by the visitor of your site,
- they're meant to help you debug your code.
+
While not exactly good practice, in some cases it's probably cleanest to just have the event method with
+ your model. That's where the Observer_Self comes in, it checks if you model has a method named after
+ the event and prefixed with _event_. For example for the after_save event you need
+ to add a public method _event_after_save() to your model so it can have the observer call on
+ the model itself.
// Just add the Observer
-protected static $_observers = array('Orm\\Observer_Typing');
+protected static $_observers = array('Orm\\Observer_Self');
-// But adding it just for these specific events is enough
-protected static $_observers = array('Orm\\Observer_Typing' => array(
- 'events' => array('before_save', 'after_save', 'after_load')
+// But if you only observe some events you can optimize by only adding those
+protected static $_observers = array('Orm\\Observer_Self' => array(
+ 'events' => array('after_save', 'before_insert')
));
-
- For this observer to work you must have your the $_properties static variable set in your
- model, or not set at all using detection with DB::list_columns() (MySQL only!). When
- configuring it yourself the following settings are available:
-
- The SQL data type, Required to have the typing observer used on a field.
-
-
-
-
db_decimals
-
int
-
Number of decimals the value in the database has, if different from the specification in "data_type".
-
-
-
null
-
bool
-
- Whether null is allowed as a value, default true
-
-
-
-
character_maximum_length
-
int
-
- The maximum number of characters allowed for a string data type (varchar, text, serialized or encrypted result)
-
-
-
-
encryption_key
-
string
-
- A custom encryption key to encrypt and decrypt this value. If given, it will replace the "crypto_key" set in the Crypt config file.
-
-
-
-
min
-
int
-
- The minimal value for an integer
-
-
-
-
max
-
int
-
- The maximum value for an integer
-
-
-
-
options
-
array
-
- Array of valid string values for set or enum data type
- Note: currently the options themselves cannot contain comma's.
-
-
-
-
-
- In case of data_type "decimal", you can suffix the type with the number of decimals required. If defined,
- the value returned is a string, formatted with the defined number of decimal digits, and taking the
- current defined locale into account.
-
-
-
- By default the Typing observer is locale aware, meaning that it can deal with incoming string values
- that use a decimal comma for fields defined as decimal or float, if the current locale defines the
- decimal separator as a comma. It will also format outgoing decimal values according to the current
- locale settings. You can disable this by defining the "orm.use_locale" config key, either in your
- main config.php file or in a separate orm.php config file, and set it to false.
-
'key_from' => 'article_id',
'key_to' => 'parent_article_id',
'cascade_save' => true,
- 'cascade_delete' => false,
+ 'constraint' => \Orm\Relation::CONSTRAINT_SETDEFAULT,
// there are some more options for specific relation types
));
@@ -131,8 +131,8 @@
Configuration Options
argument when calling save() or delete() on the originating model.
-
cascade_delete
-
bool false
+
constraint
+
string \Orm\Relation::CONSTRAINT_SETDEFAULT
conditions
@@ -145,6 +145,24 @@
Configuration Options
+
+
+ 'constraint' here refers to the ON DELETE constraint of the relation. The options are:
+ \Orm\Relation::CONSTRAINT_SETDEFAULT, when deleting a parent, set the foreign key in the child to its default value, as defined in the model properties.
+ If no default is defined, the foreign key is set to null.
+ \Orm\Relation::CONSTRAINT_CASCADE, when deleting a parent, also delete all related children.
+ \Orm\Relation::CONSTRAINT_RESTRICT, throw an DeleteConstraintViolation exception when the parent has related children.
+ The message of the exception will contain the name of the relation on which the violation occurred, which can be used to provide feedback to the user.
+
+
+ Note that 'constraint' can be defined on all relationship types. Be careful however of using \Orm\Relation::CONSTRAINT_CASCADE on a "belongs_to" relation,
+ as that would delete the parent record, which only makes sense if the other side of the relationship is defined as "has_one".
+
+
+ The boolean option 'cascade_delete' is deprecated as of Fuel v1.9. It did the same as \Orm\Relation::CONSTRAINT_CASCADE when true, or
+ \Orm\Relation::CONSTRAINT_SETDEFAULT when false, but lacked the option to block deletes when related records are present.
+
+
@@ -300,25 +318,23 @@
Relation types
The Orm supports the following relationship types natively:
-
Belongs To
- Has the primary key of the relation kept in its table, belongs to 1 related object.
Has One
- Has its primary key saved in one other row of another table (which belongs to this), has 1
- related object.
+ The "1" side of a "1:1" relation. Its primary key provides the foreign key for the record belonging to the relation. It is the parent in the relationship.
Has Many
- Has its primary key saved in many other rows of another table (which belong to this one), has
- many related objects.
+ The "1" side of a "1:N" relation. Its primary key provides the foreign key for the records belonging to the relation. It is the parent in the relationship.
+
Belongs To
+ The "1" side of a "1:1" or "N:1" relation. Its record contains the foreign key for the relation. It is the child in the relationship.
Many to Many
- Have their primary keys saved in a table in between which keeps pairs of primary keys from both
- tables. Have and belong to many objects.
+ This allows you to define an "N:M" relation between two models, using a "through" or "junction" table to store the primary keys of both sides.
+ There are situations where you have a many-many relation between two tables, but you have values that are
+ not a property of either table, but of the relation.
+
+
+
+ An example of this could be a relation between "Recipes" and "Ingredients", where a recipe has multiple ingredients,
+ and ingredients can be used in multiple recipes. But something like how much of an ingredient is needed in the recipe
+ is a property of the relation between the two. In this case, you can define a hybrid relation between the two:
+
+
+
// recipe model relationship definitions
+class Model_Recipe extends /Orm/Model
+{
+ protected static $_many_many = array(
+ 'ingredients' => array(
+ 'key_from' => 'id',
+ 'key_through_from' => 'recipe_id', // column 1 from the table in between, should match a recipe.id
+ 'table_through' => 'recipes_ingredients', // both models plural without prefix in alphabetical order
+ 'key_through_to' => 'ingredient_id', // column 2 from the through-table, should match an ingredient.id
+ 'model_to' => 'Model_Ingredient',
+ 'key_to' => 'id',
+ 'cascade_save' => true,
+ 'constraint' => \Orm\Relation::CONSTRAINT_SETDEFAULT, // don't delete the ingredients when deleting the recipe
+ )
+ );
+
+ protected static $_has_many = array(
+ 'comments' => array(
+ 'key_from' => 'id',
+ 'model_to' => 'Model_RecipeIngredient',
+ 'key_to' => 'recipe_id',
+ 'cascade_save' => true,
+ 'constraint' => \Orm\Relation::CONSTRAINT_CASCADE, // delete the through table records on delete of the recipe
+ )
+ );
+}
+
+// ingredient model relationship definitions
+class Model_Ingredient extends /Orm/Model
+{
+ protected static $_many_many = array(
+ 'recipes' => array(
+ 'key_from' => 'id',
+ 'key_through_from' => 'ingredient_id', // column 1 from the table in between, should match an ingredient.id
+ 'table_through' => 'recipes_ingredients', // both models plural without prefix in alphabetical order
+ 'key_through_to' => 'recipe_id', // column 2 from the through-table, should match a recipe.id
+ 'model_to' => 'Model_Ingredient',
+ 'key_to' => 'id',
+ 'cascade_save' => true,
+ 'constraint' => \Orm\Relation::CONSTRAINT_SETDEFAULT, // don't delete the recipes when deleting the ingredient
+ )
+ );
+
+ protected static $_has_many = array(
+ 'comments' => array(
+ 'key_from' => 'id',
+ 'model_to' => 'Model_RecipeIngredient',
+ 'key_to' => 'ingredient_id',
+ 'cascade_save' => true,
+ 'constraint' => \Orm\Relation::CONSTRAINT_CASCADE, // delete the through table records on delete of the ingredient
+ )
+ );
+
+// through-table model relationship definitions
+class Model_RecipeIngredient extends /Orm/Model
+{
+ protected static $_table_name = 'recipes_ingredients';
+
+ protected static $_belongs_to = array(
+ 'recipe' => array(
+ 'key_from' => 'recipe_id',
+ 'model_to' => 'Model_Recipe',
+ 'key_to' => 'id',
+ 'cascade_save' => true,
+ 'constraint' => \Orm\Relation::CONSTRAINT_SETDEFAULT,
+ ),
+ 'ingredient' => array(
+ 'key_from' => 'ingredient_id',
+ 'model_to' => 'Model_Ingredient',
+ 'key_to' => 'id',
+ 'cascade_save' => true,
+ 'constraint' => \Orm\Relation::CONSTRAINT_SETDEFAULT,
+ )
+ );
+}
+
+
+ If you're just using it as a "through-table", that table doesn't have to have its own primary key, you could define a compound
+ primary key for it, using both the "recipe_id" and "ingredient_id" properties. Although this works fine for the hybrid relationship
+ too, you'll have to use array('recipe_id', 'ingredient_id') for the "key_from" of the "has_many", and "key_to" of the "belongs_to"
+ relation definitions. Depending on your requirements it might be better to give the through table its own primary "id" key (as used in this example)
+ and use unique indexes for the foreign keys.
+
+ The ORM package comes with tasks that automate things, thus making your life just that little bit easier.
+
+
+
+
ModelDBCheck
+
+
The modeldbcheck task allows you to check your application model definition against the current database schema.
+
+
+ The task will scan your application "classes" directories, in the app, and all defined model and package
+ paths, for model classes that extend "\Orm\Model", either directly, or via a base class.
+
+
+
+ For every ORM model found, it will connect to the database using the models' defined table name, and retrieve
+ the database schema for that table. It will then verify if all columns defined in the schema are present
+ in the model properties list. If not, it will generate a basic array for that column, which you can simply
+ copy and paste into the model. It will also warn you if you have columns defined that are no longer
+ present in the schema.
+
+
+
$ php oil refine modeldbcheck
+
+
+
+ Which will return something like
+
+
+
Enumerate application models...
+10 ORM database models found to verify
+
+Verifying model \Auth\Model\Auth_Group
+Verifying model \Auth\Model\Auth_User
+Verifying model \Auth\Model\Auth_Role
+Verifying model \Auth\Model\Auth_Grouppermission
+Verifying model \Auth\Model\Auth_Metadata
+Verifying model \Auth\Model\Auth_Permission
+Verifying model \Auth\Model\Auth_Provider
+Verifying model \Auth\Model\Auth_Rolepermission
+Verifying model \Auth\Model\Auth_Userpermission
+
+
+
+ If you define and run your own migrations, there is usually no mismatch detected. But if your database is
+ designed and managed by a third party, or is part of another application, you might find the schema changed
+ since the last time you checked or worked on the application.
+
+
+ In these cases it is important to check, and missing columns in your model properties definition aren't
+ detected until you want to access a column, or you do an INSERT or UPDATE and a missing column is defined
+ in the schame as "NOT NULL", in which case the query will fail.
+
+ You can also use the ORM to query database views instead of tables.
+
+
+ Two different ways of accessing views are supported:
+
+
A model representation of a single view
+
A model representation of a table with views for subsets
+
+
+
+
+
View model
+
+
+ A view model is simply a model that uses a view instead of a table for selection.
+ The resulting model objects will be read-only, any attempt to call save() or update() will return false.
+
+
+
class Model_Patient extends \Orm\Model
+
+ /**
+ * @var string define the name of the view this model should use
+ *
+ * @var string
+ */
+ protected static $_table_name = 'vw_PatientView';
+
+ /**
+ * @var bool the given table name is actually a view
+ */
+ protected static $_table_is_view = true;
+
+}
+
+
And that is it. Define the rest of the model as usual, and use is as a standard model:
+
// get the patient record for John Doe
+$patient = Model_Patient::query()->where('name', '=', 'John Doe')->get_one();
+
+// will return false, not throw an error !
+$patient->save();
+
+
+
+ Note that for models, it is required to define a primary key, which by default is 'id'. If your view does not have
+ an 'id' column, make sure the view has one or more fields which can be defined as primary key.
+
+
+
+
+
+
Table model with views
+
+
+ This is a standard ORM model, with the addition that you can define views to return table data. This can be useful in organisations
+ where views are used by the database administrator to hide the selection SQL from the application developers.
+
+
+
class Model_Patient extends \Orm\Model
+
+ /**
+ * @var string define the name of the view this model should use
+ *
+ * @var string
+ */
+ protected static $_table_name = 'Patients';
+
+ /**
+ * @var bool define the available views on this table
+ */
+ protected static $_views = array(
+ // use the alias 'discharged' for the view 'vw_PatientsDischargedToday'
+ // view returns all columns defined in the model properties
+ 'discharged' => array(
+ 'view' => 'vw_PatientsDischargedToday',
+ 'columns' => true,
+ ),
+ // use the view name directly
+ // and returns a specific set of columns
+ 'vw_PatientsAdmittedToday' => array(
+ 'columns' => array(
+ 'id',
+ 'name',
+ 'dob',
+ 'room',
+ ),
+ ),
+ );
+}
+
+
You can now query the model the usual way, or define you want to use one of the views:
+
// check if John Doe was discharged today
+$patient = Model_Patient::query()->use_view('discharged')->where('name', '=', 'John Doe')->get_one();
+
+if ($patient)
+{
+ // yes, John Doe is discharged today
+}
+
+// check if John Doe was admitted today
+$patient = Model_Patient::query()->use_view('vw_PatientsAdmittedToday')->where('name', '=', 'John Doe')->get_one();
+
+if ($patient)
+{
+ // yes, John Doe is admitted today
+ // note the patient object will contain a subset of data due to the column list defined
+}
+ PHPQuickProfiler was originally made by ParticleTree, which no longer exists.
+ You may find an old version of the original documentation in the Way Back Machine, here.
FuelPHP Usage
@@ -57,6 +59,9 @@
FuelPHP Usage
Application Usage
+ The profiler is active by default for applications running in DEVELOPMENT mode. It can manually be switched on or off in your code by setting the
+ boolean \Fuel::$profiler. Is is only active if the output content type is detected to be "text/html".
+
You can add data to PHPQuickProfiler through the Profiler class methods.
You can find the original PHPSecLib documentation here.
+
You can find the original PHPSecLib documentation here.
FuelPHP Usage
@@ -55,7 +55,6 @@
FuelPHP Usage
Application Usage
- For use in your application the PHPSecLib package has been converted to a namespaced, autoloader friendly library.
You can use it directly from your application.
<?php
@@ -68,7 +67,7 @@
Application Usage
public function action_index()
{
// connect to my server
- $ssh = new \phpseclib\Net\SSH2('myserver.example.org');
+ $ssh = new \phpseclib3\Net\SSH2('myserver.example.org');
// login
if ( ! $ssh->login('username', 'password'))
@@ -85,11 +84,18 @@
Application Usage
}
+
+ Note that the current version of PHPSecLib defined in Fuel's composer.json is version 3. If you want to change the version,
+ please be aware that it may have tighter PHP version restrictions than Fuel itself has. Also, Fuel's Crypt class references
+ the phpseclib3 namespace, so you might want to alias either the PHPSecLib 3 namespace, or overload the Crypt class, to
+ address this problem.
+