Update Kohana to 3.1.3.1
This commit is contained in:
@@ -24,7 +24,7 @@ spl_autoload_register(array('Kohana', 'auto_load'));
|
||||
ini_set('unserialize_callback_func', 'spl_autoload_call');
|
||||
~~~
|
||||
|
||||
## Initilization and Configuration
|
||||
## Initialization and Configuration
|
||||
|
||||
Kohana is then initialized by calling [Kohana::init], and the log and [config](files/config) reader/writers are enabled.
|
||||
|
||||
@@ -74,18 +74,6 @@ Kohana::init(array(
|
||||
|
||||
... [trimmed]
|
||||
|
||||
try
|
||||
{
|
||||
$request = Request::instance()->execute();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// If we are in development and the error wasn't a 404, show the stack trace.
|
||||
if ( Kohana::$environment == "development" AND $e->getCode() != 404 )
|
||||
{
|
||||
throw $e;
|
||||
}
|
||||
...[trimmed]
|
||||
~~~
|
||||
|
||||
[!!] Note: The default bootstrap will set `Kohana::$environment = $_ENV['KOHANA_ENV']` if set. Docs on how to supply this variable are available in your web server's documentation (e.g. [Apache](http://httpd.apache.org/docs/1.3/mod/mod_env.html#setenv), [Lighttpd](http://redmine.lighttpd.net/wiki/1/Docs:ModSetEnv#Options)). This is considered better practice than many alternative methods to set `Kohana::$enviroment`, as you can change the setting per server, without having to rely on config options or hostnames.
|
||||
@@ -121,44 +109,3 @@ Route::set('default', '(<controller>(/<action>(/<id>)))')
|
||||
'action' => 'index',
|
||||
));
|
||||
~~~
|
||||
|
||||
## Execution
|
||||
|
||||
Once our environment is initialized and routes defined, it's time to execute our application. This area of the bootstrap is very flexible. Do not be afraid to change this around to whatever suits your needs.
|
||||
|
||||
### Basic Example
|
||||
The most simple way to do this, and what comes default with Kohana 3 is simply:
|
||||
~~~
|
||||
// Execute the main request
|
||||
echo Request::instance()
|
||||
->execute()
|
||||
->send_headers()
|
||||
->response;
|
||||
~~~
|
||||
|
||||
### Catching Exceptions
|
||||
|
||||
**See [Error Handling](errors) for a more detailed description and more examples.**
|
||||
|
||||
The previous example provides no error catching, which means if an error occurs a stack trace would be shown which could show sensitive info, as well as be unfriendly for the user. One way to solve this is to add a `try catch` block. If we get an exception, we will show the view located at `views/errors/404.php`. **Note: Because we catch the exception, Kohana will not log the error! It is your responsibility to log the error.**
|
||||
|
||||
~~~
|
||||
try
|
||||
{
|
||||
// Execute the main request
|
||||
$request = Request::instance()->execute();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// Be sure to log the error
|
||||
Kohana::$log->add(Kohana::ERROR, Kohana::exception_text($e));
|
||||
|
||||
// If there was an error, send a 404 response and display an error
|
||||
$request->status = 404;
|
||||
$request->response = View::factory('errors/404');
|
||||
}
|
||||
|
||||
// Send the headers and echo the response
|
||||
$request->send_headers();
|
||||
echo $request->response;
|
||||
~~~
|
@@ -1,6 +1,6 @@
|
||||
# Conventions and Coding Style
|
||||
|
||||
It is encouraged that you follow Kohana's [coding style](http://dev.kohanaframework.org/wiki/kohana2/CodingStyle). This makes code more readable and allows for easier code sharing and contributing.
|
||||
It is encouraged that you follow Kohana's coding style. This makes code more readable and allows for easier code sharing and contributing.
|
||||
|
||||
## Class Names and File Location
|
||||
|
||||
@@ -12,8 +12,6 @@ The following conventions apply:
|
||||
2. All class file names and directory names are lowercase.
|
||||
3. All classes should be in the `classes` directory. This may be at any level in the [cascading filesystem](files).
|
||||
|
||||
[!!] Unlike Kohana v2.x, there is no separation between "controllers", "models", "libraries" and "helpers". All classes are placed in the "classes/" directory, regardless if they are static "helpers" or object "libraries". You can use whatever kind of class design you want: static, singleton, adapter, etc.
|
||||
|
||||
### Examples {#class-name-examples}
|
||||
|
||||
Remember that in a class, an underscore means a new directory. Consider the following examples:
|
||||
@@ -31,20 +29,133 @@ Form | classes/form.php
|
||||
In order to produce highly consistent source code, we ask that everyone follow the coding standards as closely as possible.
|
||||
|
||||
### Brackets
|
||||
Please use [BSD/Allman Style](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) bracketing. Brackets are always on their own line. The exception to this rule is the opening bracket for a class, which can be on the same line.
|
||||
|
||||
if ($foo == 'bar')
|
||||
Please use [BSD/Allman Style](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) bracketing.
|
||||
|
||||
#### Curly Brackets
|
||||
|
||||
Curly brackets are placed on their own line, indented to the same level as the control statement.
|
||||
|
||||
// Correct
|
||||
if ($a === $b)
|
||||
{
|
||||
$baz->bar();
|
||||
...
|
||||
}
|
||||
else
|
||||
{
|
||||
$baz->default();
|
||||
...
|
||||
}
|
||||
|
||||
// The opening bracket for a class can be on the same line
|
||||
Class Foobar {
|
||||
|
||||
// Incorrect
|
||||
if ($a === $b) {
|
||||
...
|
||||
} else {
|
||||
...
|
||||
}
|
||||
|
||||
#### Class Brackets
|
||||
|
||||
The only exception to the curly bracket rule is, the opening bracket of a class goes on the same line.
|
||||
|
||||
// Correct
|
||||
class Foo {
|
||||
|
||||
// Incorrect
|
||||
class Foo
|
||||
{
|
||||
|
||||
#### Empty Brackets
|
||||
|
||||
Don't put any characters inside empty brackets.
|
||||
|
||||
// Correct
|
||||
class Foo {}
|
||||
|
||||
// Incorrect
|
||||
class Foo { }
|
||||
|
||||
#### Array Brackets
|
||||
|
||||
Arrays may be single line or multi-line.
|
||||
|
||||
array('a' => 'b', 'c' => 'd')
|
||||
|
||||
array(
|
||||
'a' => 'b',
|
||||
'c' => 'd',
|
||||
)
|
||||
|
||||
##### Opening Parenthesis
|
||||
|
||||
The opening array parenthesis goes on the same line.
|
||||
|
||||
// Correct
|
||||
array(
|
||||
...
|
||||
)
|
||||
|
||||
// Incorrect:
|
||||
array
|
||||
(
|
||||
...
|
||||
)
|
||||
|
||||
##### Closing parenthesis
|
||||
|
||||
###### Single Dimension
|
||||
|
||||
The closing parenthesis of a multi-line single dimension array is placed on its own line, indented to the same level as the assignment or statement.
|
||||
|
||||
// Correct
|
||||
$array = array(
|
||||
...
|
||||
)
|
||||
|
||||
// Incorrect
|
||||
$array = array(
|
||||
...
|
||||
)
|
||||
|
||||
###### Multidimensional
|
||||
|
||||
The nested array is indented one tab to the right, following the single dimension rules.
|
||||
|
||||
// Correct
|
||||
array(
|
||||
'arr' => array(
|
||||
...
|
||||
),
|
||||
'arr' => array(
|
||||
...
|
||||
),
|
||||
)
|
||||
|
||||
array(
|
||||
'arr' => array(...),
|
||||
'arr' => array(...),
|
||||
)
|
||||
|
||||
##### Arrays as Function Arguments
|
||||
|
||||
|
||||
// Correct
|
||||
do(array(
|
||||
...
|
||||
))
|
||||
|
||||
// Incorrect
|
||||
do(array(
|
||||
...
|
||||
))
|
||||
|
||||
As noted at the start of the array bracket section, single line syntax is also valid.
|
||||
|
||||
// Correct
|
||||
do(array(...))
|
||||
|
||||
// Alternative for wrapping long lines
|
||||
do($bar, 'this is a very long line',
|
||||
array(...));
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
@@ -99,7 +210,7 @@ Vertical spacing (for multi-line) is done with spaces. Tabs are not good for ver
|
||||
.'but vertical alignment should be completed with spaces, after '
|
||||
.'indenting with tabs.';
|
||||
|
||||
### String concatenation
|
||||
### String Concatenation
|
||||
|
||||
Do not put spaces around the concatenation operator:
|
||||
|
||||
@@ -149,7 +260,7 @@ Please use elseif, not else if:
|
||||
// Incorrect:
|
||||
else if($bar)
|
||||
|
||||
### Switch structures
|
||||
### Switch Structures
|
||||
|
||||
Each case, break and default should be on a separate line. The block inside a case or default must be indented by 1 tab.
|
||||
|
||||
@@ -262,7 +373,7 @@ Since we are reading left to right, it simply doesn't make sense to put the cons
|
||||
|
||||
### Comments
|
||||
|
||||
#### One-line comments
|
||||
#### One-line Comments
|
||||
|
||||
Use //, preferably above the line of code you're commenting on. Leave a space after it and start with a capital. Never use #.
|
||||
|
||||
@@ -272,7 +383,7 @@ Use //, preferably above the line of code you're commenting on. Leave a space af
|
||||
// incorrect
|
||||
# Incorrect
|
||||
|
||||
### Regular expressions
|
||||
### Regular Expressions
|
||||
|
||||
When coding regular expressions please use PCRE rather than the POSIX flavor. PCRE is considered more powerful and faster.
|
||||
|
||||
|
@@ -4,7 +4,18 @@ Kohana provides classes that make it easy to work with both cookies and sessions
|
||||
|
||||
[Cookies](http://en.wikipedia.org/wiki/HTTP_cookie) should be used for storing non-private data that is persistent for a long period of time. For example storing a user preference or a language setting. Use the [Cookie] class for getting and setting cookies.
|
||||
|
||||
[!!] Kohana uses "signed" cookies. Every cookie that is stored is combined with a secure hash to prevent modification of the cookie. If a cookie is modified outside of Kohana the hash will be incorrect and the cookie will be deleted. This hash is generated using [Cookie::salt()], which uses the [Cookie::$salt] property. You should change this setting when your application is live.
|
||||
[!!] Kohana uses "signed" cookies. Every cookie that is stored is combined with a secure hash to prevent modification of the cookie. If a cookie is modified outside of Kohana the hash will be incorrect and the cookie will be deleted. This hash is generated using [Cookie::salt()], which uses the [Cookie::$salt] property. You must define this setting in your bootstrap.php:
|
||||
|
||||
Cookie::$salt = 'foobar';
|
||||
|
||||
Or define an extended cookie class in your application:
|
||||
|
||||
class Cookie extends Kohana_Cookie
|
||||
{
|
||||
public static $salt = 'foobar';
|
||||
}
|
||||
|
||||
You should set the salt to a secure value. The example above is only for demonstrative purposes.
|
||||
|
||||
Nothing stops you from using `$_COOKIE` like normal, but you can not mix using the Cookie class and the regular `$_COOKIE` global, because the hash that Kohana uses to sign cookies will not be present, and Kohana will delete the cookie.
|
||||
|
||||
|
@@ -2,19 +2,19 @@
|
||||
|
||||
Kohana includes several tools to help you debug your application.
|
||||
|
||||
The most basic of these is [Kohana::debug]. This simple method will display any number of variables, similar to [var_export](http://php.net/var_export) or [print_r](http://php.net/print_r), but using HTML for extra formatting.
|
||||
The most basic of these is [Debug::vars]. This simple method will display any number of variables, similar to [var_export](http://php.net/var_export) or [print_r](http://php.net/print_r), but using HTML for extra formatting.
|
||||
|
||||
// Display a dump of the $foo and $bar variables
|
||||
echo Kohana::debug($foo, $bar);
|
||||
echo Debug::vars($foo, $bar);
|
||||
|
||||
Kohana also provides a method to show the source code of a particular file using [Kohana::debug_source].
|
||||
Kohana also provides a method to show the source code of a particular file using [Debug::source].
|
||||
|
||||
// Display this line of source code
|
||||
echo Kohana::debug_source(__FILE__, __LINE__);
|
||||
echo Debug::source(__FILE__, __LINE__);
|
||||
|
||||
If you want to display information about your application files without exposing the installation directory, you can use [Kohana::debug_path]:
|
||||
If you want to display information about your application files without exposing the installation directory, you can use [Debug::path]:
|
||||
|
||||
// Displays "APPPATH/cache" rather than the real path
|
||||
echo Kohana::debug_path(APPPATH.'cache');
|
||||
echo Debug::path(APPPATH.'cache');
|
||||
|
||||
If you are having trouble getting something to work correctly, you could check your Kohana logs and your webserver logs, as well as using a debugging tool like [Xdebug](http://www.xdebug.org/).
|
@@ -17,7 +17,7 @@ Click any of the links to toggle the display of additional information:
|
||||
|
||||
## Disabling Error/Exception Handling
|
||||
|
||||
If you do not want to use the internal error handling, you can disable it when calling [Kohana::init]:
|
||||
If you do not want to use the internal error handling, you can disable it (highly discouraged) when calling [Kohana::init]:
|
||||
|
||||
Kohana::init(array('errors' => FALSE));
|
||||
|
||||
@@ -37,49 +37,40 @@ If you get a white screen when an error is triggered, your host probably has dis
|
||||
|
||||
Errors should **always** be displayed, even in production, because it allows you to use [exception and error handling](debugging.errors) to serve a nice error page rather than a blank white screen when an error happens.
|
||||
|
||||
## HTTP Exception Handling
|
||||
|
||||
## Last thoughts
|
||||
Kohana comes with a robust system for handing http errors. It includes exception classes for each http status code. To trigger a 404 in your application (the most common scenario):
|
||||
|
||||
In production, **your application should never have any uncaught exceptions**, as this can expose sensitive information (via the stack trace). In the previous example we make the assumption that there is actually a view called 'views/errors/404', which is fairly safe to assume. One solution is to turn 'errors' off in Kohana::init for your production machine, so it displays the normal php errors rather than a stack trace.
|
||||
throw new HTTP_Exception_404('File not found!');
|
||||
|
||||
~~~
|
||||
// snippet from bootstrap.php
|
||||
Kohana::init(array('
|
||||
...
|
||||
'errors' => false,
|
||||
));
|
||||
~~~
|
||||
There is no default method to handle these errors in Kohana. It's recommended that you setup an exception handler (and register it) to handle these kinds of errors. Here's a simple example that would go in */application/classes/foobar/exception/handler.php*:
|
||||
|
||||
So rather than displaying the Kohana error page with the stack trace, it will display the default php error. Something like:
|
||||
|
||||
**Fatal error: Uncaught Kohana_View_Exception [ 0 ]: The requested view errors/404 could not be found ~ SYSPATH/classes/kohana/view.php [ 215 ] thrown in /var/www/kohanut/docs.kohanaphp.com/3.0/system/classes/kohana/view.php on line 215**
|
||||
|
||||
Keep in mind what I said earlier though: **your application should never have any uncaught exceptions**, so this should not be necesarry, though it is a good idea, simply because stack traces on a production environment are a *very* bad idea.
|
||||
|
||||
Another solution is to always have a `catch` statement that can't fail, something like an `echo` and an `exit` or a `die()`. This should almost never be necesarry, but it makes some people feel better at night. You can either wrap your entire bootstrap in a try catch, or simply wrap the contents of the catch in another try catch. For example:
|
||||
|
||||
~~~
|
||||
try
|
||||
{
|
||||
// Execute the main request
|
||||
$request->execute();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
try
|
||||
class Foobar_Exception_Handler
|
||||
{
|
||||
// Be sure to log the error
|
||||
Kohana::$log->add(Kohana::ERROR, Kohana::exception_text($e));
|
||||
|
||||
// If there was an error, send a 404 response and display an error
|
||||
$request->status = 404;
|
||||
$request->response = View::factory('errors/404');
|
||||
public static function handle(Exception $e)
|
||||
{
|
||||
switch (get_class($e))
|
||||
{
|
||||
case 'Http_Exception_404':
|
||||
$response = new Response;
|
||||
$response->status(404);
|
||||
$view = new View('error_404');
|
||||
$view->message = $e->getMessage();
|
||||
$view->title = 'File Not Found';
|
||||
echo $response->body($view)->send_headers()->body();
|
||||
return TRUE;
|
||||
break;
|
||||
default:
|
||||
return Kohana_Exception::handler($e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// This is completely overkill, but helps some people sleep at night
|
||||
echo "Something went terribly wrong. Try again in a few minutes.";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
And put something like this in your bootstrap to register the handler.
|
||||
|
||||
set_exception_handler(array('Foobar_Exception_Handler', 'handle'));
|
||||
|
||||
> *Note:* Be sure to place `set_exception_handler()` **after** `Kohana::init()` in your bootstrap, or it won't work.
|
||||
|
||||
> If you receive *Fatal error: Exception thrown without a stack frame in Unknown on line 0*, it means there was an error within your exception handler. If using the example above, be sure *404.php* exists under */application/views/error/*.
|
||||
|
@@ -8,7 +8,7 @@ The default Kohana classes, and many extensions, use this definition so that alm
|
||||
|
||||
[!!] You should **never** modify any of the files that are distributed with Kohana. Always make modifications to classes using transparent extension to prevent upgrade issues.
|
||||
|
||||
For instance, if you wanted to create method that sets encrypted cookies using the [Encrypt] class, you would creat a file at `application/classes/cookie.php` that extends Kohana_Cookie, and adds your functions:
|
||||
For instance, if you wanted to create method that sets encrypted cookies using the [Encrypt] class, you would create a file at `application/classes/cookie.php` that extends Kohana_Cookie, and adds your functions:
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
@@ -74,11 +74,11 @@ If you are using the [Cookie](cookies) class, and want to change a setting, you
|
||||
|
||||
## Example: TODO: an example
|
||||
|
||||
Just post the code and breif descript of what function it adds, you don't have to do the "How it works" like above.
|
||||
Just post the code and brief description of what function it adds, you don't have to do the "How it works" like above.
|
||||
|
||||
## Example: TODO: something else
|
||||
|
||||
Just post the code and breif descript of what function it adds, you don't have to do the "How it works" like above.
|
||||
Just post the code and brief description of what function it adds, you don't have to do the "How it works" like above.
|
||||
|
||||
## More examples
|
||||
|
||||
|
@@ -1,12 +1,12 @@
|
||||
# Cascading Filesystem
|
||||
|
||||
The Kohana filesystem is a heirarchy of similar directory structures that cascade. The heirarchy in Kohana (used when a file is loaded by [Kohana::find_file]) is in the following order:
|
||||
The Kohana filesystem is a hierarchy of similar directory structures that cascade. The hierarchy in Kohana (used when a file is loaded by [Kohana::find_file]) is in the following order:
|
||||
|
||||
1. **Application Path**
|
||||
Defined as `APPPATH` in `index.php`. The default value is `application`.
|
||||
|
||||
2. **Module Paths**
|
||||
This is set as an associative array using [Kohana::modules] in `APPPATH/bootstrap.php`. Each of the values of the array will be searched **in the order that the modules are added**.
|
||||
This is set as an associative array using [Kohana::modules] in `APPPATH/bootstrap.php`. Each of the values of the array will be searched **in the order that the modules are defined**.
|
||||
|
||||
3. **System Path**
|
||||
Defined as `SYSPATH` in `index.php`. The default value is `system`. All of the main or "core" files and classes are defined here.
|
||||
|
@@ -6,7 +6,7 @@ TODO: Brief intro to classes.
|
||||
|
||||
## Helper or Library?
|
||||
|
||||
Kohana 3 does not differentiate between "helper" classes and "library" classes like in previous versions. They are all placed in the `classes/` folder and follow the same conventions. The distinction is that in general, a "helper" class is used statically, (for examples see the [helpers included in Kohana](helpers)), and library classes are typically instanciated and used as objects (like the [Database query builders](../database/query/builder)). The distinction is not black and white, and is irrelevant anyways, since they are treated the same by Kohana.
|
||||
Kohana 3 does not differentiate between "helper" classes and "library" classes like in previous versions. They are all placed in the `classes/` folder and follow the same conventions. The distinction is that in general, a "helper" class is used statically, (for examples see the [helpers included in Kohana](helpers)), and library classes are typically instantiated and used as objects (like the [Database query builders](../database/query/builder)). The distinction is not black and white, and is irrelevant anyways, since they are treated the same by Kohana.
|
||||
|
||||
## Creating a class
|
||||
|
||||
|
@@ -3,7 +3,7 @@
|
||||
Configuration files are used to store any kind of configuration needed for a module, class, or anything else you want. They are plain PHP files, stored in the `config/` directory, which return an associative array:
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
|
||||
return array(
|
||||
'setting' => 'value',
|
||||
'options' => array(
|
||||
@@ -38,24 +38,31 @@ Please note that you can only access the top level of keys as object properties,
|
||||
|
||||
Configuration files are slightly different from most other files within the [cascading filesystem](files) in that they are **merged** rather than overloaded. This means that all configuration files with the same file path are combined to produce the final configuration. The end result is that you can overload *individual* settings rather than duplicating an entire file.
|
||||
|
||||
For example, if we wanted to change something in some file
|
||||
For example, if we wanted to change or add to an entry in the inflector configuration file, we would not need to duplicate all the other entries from the default configuration file.
|
||||
|
||||
// config/inflector.php
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'irregular' => array(
|
||||
'die' => 'dice', // does not exist in default config file
|
||||
'mouse' => 'mouses', // overrides 'mouse' => 'mice' in the default config file
|
||||
);
|
||||
|
||||
[TODO]
|
||||
|
||||
TODO exmaple of adding something to inflector
|
||||
|
||||
## Creating your own config files
|
||||
|
||||
Let's say we want a config file to store and easily change things like the title of a website, or the google analytics code. We would create a config file, let's call it `site.php`:
|
||||
|
||||
// config/site.php
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
// config/site.php
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'title' => 'Our Shiny Website',
|
||||
'analytics' => FALSE, // analytics code goes here, set to FALSE to disable
|
||||
);
|
||||
'title' => 'Our Shiny Website',
|
||||
'analytics' => FALSE, // analytics code goes here, set to FALSE to disable
|
||||
);
|
||||
|
||||
We could now call `Kohana::config('site.title')` to get the site name, and `Kohana::config('site.analytics')` to get the analytics code.
|
||||
|
||||
|
@@ -1 +1,67 @@
|
||||
Discuss the format of i18n files, and how to use them.
|
||||
# I18n
|
||||
|
||||
Kohana has a fairly simple and easy to use i18n system. It is slightly modeled after gettext, but is not as featureful. If you need the features of gettext, please use that :)
|
||||
|
||||
## __()
|
||||
|
||||
Kohana has a __() function to do your translations for you. This function is only meant for small sections of text, not entire paragraphs or pages of translated text.
|
||||
|
||||
To echo a translated string:
|
||||
|
||||
<?php echo __('Hello, world!');?>
|
||||
|
||||
This will echo 'Home' unless you've changed the defined language, which is explained below.
|
||||
|
||||
## Changing the displayed language
|
||||
|
||||
Use the I18n::lang() method to change the displayed language:
|
||||
|
||||
I18n::lang('fr');
|
||||
|
||||
This will change the language to 'es-es'.
|
||||
|
||||
## Defining language files
|
||||
|
||||
To define the language file for the above language change, create a `i18n/fr.php` that contains:
|
||||
|
||||
<?php
|
||||
|
||||
return array
|
||||
(
|
||||
'Hello, world!' => 'Bonjour, monde!',
|
||||
);
|
||||
|
||||
Now when you do `__('Hello, world!')`, you will get `Bonjour, monde!`
|
||||
|
||||
## I18n variables
|
||||
|
||||
You can define variables in your __() calls like so:
|
||||
|
||||
echo __('Hello, :user', array(':user' => $username));
|
||||
|
||||
Your i18n key in your translation file will need to be defined as:
|
||||
|
||||
<?php
|
||||
|
||||
return array
|
||||
(
|
||||
'Hello, :user' => 'Bonjour, :user',
|
||||
);
|
||||
|
||||
## Defining your own __() function
|
||||
|
||||
You can define your own __() function by simply defining your own i18n class:
|
||||
|
||||
<?php
|
||||
|
||||
class I18n extends Kohana_I18n
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
function __($string, array $values = NULL, $lang = 'en-us')
|
||||
{
|
||||
// Your functionality here
|
||||
}
|
||||
|
||||
This will cause the built-in __() function to be ignored.
|
@@ -1,5 +1,36 @@
|
||||
<http://kohanaframework.org/guide/using.messages>
|
||||
# Messages
|
||||
|
||||
Add that message files can be in subfolders, and you can use dot notation to retreive an array path: `Kohana::message('folder/subfolder/file','array.subarray.key')`
|
||||
Kohana has a robust key based lookup system so you can define system messages.
|
||||
|
||||
Also reinforce that messages are merged by the cascade, not overwritten.
|
||||
## Getting a message
|
||||
|
||||
Use the Kohana::message() method to get a message key:
|
||||
|
||||
Kohana::message('forms', 'foobar');
|
||||
|
||||
This will look in the `messages/forms.php` file for the `foobar` key:
|
||||
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'foobar' => 'Hello, world!',
|
||||
);
|
||||
|
||||
You can also look in subfolders and sub-keys:
|
||||
|
||||
Kohana::message('forms/contact', 'foobar.bar');
|
||||
|
||||
This will look in the `messages/forms/contact.php` for the `[foobar][bar]` key:
|
||||
|
||||
<?php
|
||||
|
||||
return array(
|
||||
'foobar' => array(
|
||||
'bar' => 'Hello, world!',
|
||||
),
|
||||
);
|
||||
|
||||
## Notes
|
||||
|
||||
* Don't use __() in your messages files, as these files can be cached and will not work properly.
|
||||
* Messages are merged by the cascading file system, not overwritten like config files.
|
@@ -23,4 +23,5 @@ Every application follows the same flow:
|
||||
4. Calls the controller action, which generates the request response.
|
||||
5. Calls the [Controller::after] method.
|
||||
* The above 5 steps can be repeated multiple times when using [HMVC sub-requests](requests).
|
||||
3. Application flow returns to index.php
|
||||
12. The main [Request] response is displayed
|
@@ -1,6 +1,6 @@
|
||||
# Helpers
|
||||
|
||||
Kohana comes with many static helper functions to make certain tasks easier.
|
||||
Kohana comes with many static "helper" functions to make certain tasks easier.
|
||||
|
||||
You can make your own helpers by simply making a class and putting it in the `classes` directory, and you can also extend any helper to modify or add new functions using transparent extension.
|
||||
|
||||
|
@@ -8,7 +8,7 @@ Kohana is an open source, [object oriented](http://wikipedia.org/wiki/Object-Ori
|
||||
|
||||
Anything can be extended using the unique [filesystem](about.filesystem) design, little or no [configuration](about.configuration) is necessary, [error handling](debugging.errors) helps locate the source of errors quickly, and [debugging](debugging) and [profiling](debugging.profiling) provide insight into the application.
|
||||
|
||||
To help secure your applications, tools for [XSS removal](security.xss), [input validation](security.validation), [signed cookies](security.cookies), [form](security.forms) and [HTML](security.html) generators are all included. The [database](security.database) layer provides protection against [SQL injection](http://wikipedia.org/wiki/SQL_Injection). Of course, all official code is carefully written and reviewed for security.
|
||||
To help secure your applications, tools for [input validation](security.validation), [signed cookies](security.cookies), [form](security.forms) and [HTML](security.html) generators are all included. The [database](security.database) layer provides protection against [SQL injection](http://wikipedia.org/wiki/SQL_Injection). Of course, all official code is carefully written and reviewed for security.
|
||||
|
||||
## Contribute to the Documentation
|
||||
|
||||
|
@@ -19,15 +19,8 @@ Once your install page reports that your environment is set up correctly you nee
|
||||
|
||||

|
||||
|
||||
## Installing Kohana 3.0 From GitHub
|
||||
## Installing Kohana 3.1 From GitHub
|
||||
|
||||
The [source code](http://github.com/kohana/kohana) for Kohana 3.0 is hosted with [GitHub](http://github.com). To install Kohana using the github source code first you need to install git. Visit [http://help.github.com](http://help.github.com) for details on how to install git on your platform.
|
||||
The [source code](http://github.com/kohana/kohana) for Kohana 3.1 is hosted with [GitHub](http://github.com). To install Kohana using the github source code first you need to install git. Visit [http://help.github.com](http://help.github.com) for details on how to install git on your platform.
|
||||
|
||||
To install the last stable release of Kohana using git run these commands:
|
||||
|
||||
git clone git://github.com/kohana/kohana.git
|
||||
cd kohana/
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
[!!] For more information on using Git and Kohana see the [Working with Git](tutorials/git) tutorial.
|
||||
[!!] For more information on installing Kohana using git submodules, see the [Working with Git](tutorials/git) tutorial.
|
@@ -18,7 +18,7 @@
|
||||
- [Routing](routing)
|
||||
- [Error Handling](errors)
|
||||
- [Tips & Common Mistakes](tips)
|
||||
- [Upgrading from v2.x](upgrading)
|
||||
- [Upgrading from v3.0](upgrading)
|
||||
- Basic Usage
|
||||
- [Debugging](debugging)
|
||||
- [Loading Classes](autoloading)
|
||||
@@ -39,7 +39,6 @@
|
||||
- [Tutorials](tutorials)
|
||||
- [Hello World](tutorials/hello-world)
|
||||
- [Simple MVC](tutorials/simple-mvc)
|
||||
- [Routes & Links](tutorials/routes-and-links)
|
||||
- [Custom Error Pages](tutorials/error-pages)
|
||||
- [Content Translation](tutorials/translation)
|
||||
- [Clean URLs](tutorials/clean-urls)
|
||||
|
@@ -1 +0,0 @@
|
||||
This will discuss models, explain what should be in a model, and give *breif* examples of extending models, like using modeling systems.
|
@@ -8,6 +8,8 @@ Kolanos has created [kohana-universe](http://github.com/kolanos/kohana-universe/
|
||||
|
||||
Mon Geslani created a [very nice site](http://kohana.mongeslani.com/) that allows you to sort Github modules by activity, watchers, forks, etc. It seems to not be as comprehensive as kohana-universe.
|
||||
|
||||
Andrew Hutchings has created [kohana-modules](http://www.kohana-modules.com) which is similar to the above sites.
|
||||
|
||||
## Enabling modules
|
||||
|
||||
Modules are enabled by calling [Kohana::modules] and passing an array of `'name' => 'path'`. The name isn't important, but the path obviously is. A module's path does not have to be in `MODPATH`, but usually is. You can only call [Kohana::modules] once.
|
||||
|
@@ -53,37 +53,39 @@ You can also have a controller extend another controller to share common things,
|
||||
|
||||
## $this->request
|
||||
|
||||
Every controller has the `$this->request` property which is the [Request] object that called the controller. You can use this to get information about the current request, as well as set the response via `$this->request->response`.
|
||||
Every controller has the `$this->request` property which is the [Request] object that called the controller. You can use this to get information about the current request, as well as set the response body via `$this->response->body($ouput)`.
|
||||
|
||||
Here is a partial list of the properties and methods available to `$this->request`. These can also be accessed via `Request::instance()`, but `$this->request` is provided as a shortcut. See the [Request] class for more information on any of these.
|
||||
|
||||
Property/method | What it does
|
||||
--- | ---
|
||||
[$this->request->route](../api/Request#property:route) | The [Route] that matched the current request url
|
||||
[$this->request->directory](../api/Request#property:directory), <br /> [$this->request->controller](../api/Request#property:controller), <br /> [$this->request->action](../api/Request#property:action) | The directory, controller and action that matched for the current route
|
||||
[$this->request->route()](../api/Request#property:route) | The [Route] that matched the current request url
|
||||
[$this->request->directory()](../api/Request#property:directory), <br /> [$this->request->controller](../api/Request#property:controller), <br /> [$this->request->action](../api/Request#property:action) | The directory, controller and action that matched for the current route
|
||||
[$this->request->param()](../api/Request#param) | Any other params defined in your route
|
||||
[$this->request->response](../api/Request#property:response) | The content to return for this request
|
||||
[$this->request->status](../api/Request#property:status) | The HTTP status for the request (200, 404, 500, etc.)
|
||||
[$this->request->headers](../api/Request#property:headers) | The HTTP headers to return with the response
|
||||
[$this->request->redirect()](../api/Request#redirect) | Redirect the request to a different url
|
||||
|
||||
## $this->response
|
||||
[$this->response->body()](../api/Response#property:body) | The content to return for this request
|
||||
[$this->response->status()](../api/Response#property:status) | The HTTP status for the request (200, 404, 500, etc.)
|
||||
[$this->response->headers()](../api/Response#property:headers) | The HTTP headers to return with the response
|
||||
|
||||
|
||||
## Actions
|
||||
|
||||
You create actions for your controller by defining a public function with an `action_` prefix. Any method that is not declared as `public` and prefixed with `action_` can NOT be called via routing.
|
||||
|
||||
An action method will decide what should be done based on the current request, it *controls* the application. Did the user want to save a blog post? Did they provide the necesarry fields? Do they have permission to da that? The controller will call other classes, including models, to accomplish this. Every action should set `$this->request->response` to the [view file](mvc/views) to be sent to the browser, unless it [redirected](../api/Request#redirect) or otherwise ended the script earlier.
|
||||
An action method will decide what should be done based on the current request, it *controls* the application. Did the user want to save a blog post? Did they provide the necessary fields? Do they have permission to do that? The controller will call other classes, including models, to accomplish this. Every action should set `$this->response->body($view)` to the [view file](mvc/views) to be sent to the browser, unless it [redirected](../api/Request#redirect) or otherwise ended the script earlier.
|
||||
|
||||
A very basic action method that simply loads a [view](mvc/views) file.
|
||||
|
||||
public function action_hello()
|
||||
{
|
||||
$this->request->response = View::factory('hello/world'); // This will load views/hello/world.php
|
||||
$this->response->body(View::factory('hello/world')); // This will load views/hello/world.php
|
||||
}
|
||||
|
||||
### Parameters
|
||||
|
||||
Parameters can be accessed in two ways. The first is by calling `$this->request->param('name')` where `name` is the name defined in the route.
|
||||
Parameters are accessed by calling `$this->request->param('name')` where `name` is the name defined in the route.
|
||||
|
||||
// Assuming Route::set('example','<controller>(/<action>(/<id>(/<new>)))');
|
||||
|
||||
@@ -99,51 +101,42 @@ If that parameter is not set it will be returned as NULL. You can provide a sec
|
||||
// $id will be false if it was not supplied in the url
|
||||
$id = $this->request->param('user',FALSE);
|
||||
|
||||
The second way you can access route parameters is from the actions function definition. Any extra keys in your route (keys besides `<directory>`, `<controller>`, and `<action>`) are passed as parameters to your action *in the order they appear in the route*.
|
||||
|
||||
// Assuming Route::set('example','<controller>(/<action>(/<id>(/<new>)))');
|
||||
|
||||
public function action_foobar($id, $new)
|
||||
{
|
||||
|
||||
Note that the names do not actually matter, *only the order*. You could name the parameters anything you want in both the route and the function definition, they don't even need to match. The following code is identical in function to the previous example.
|
||||
|
||||
// Assuming Route::set('example','<controller>(/<action>(/<num>(/<word>)))');
|
||||
|
||||
public function action_foobar($foo, $bar)
|
||||
{
|
||||
|
||||
You can provide default values in the same way you do for any php function.
|
||||
|
||||
public function action_foobar($id = 0, $new = NULL)
|
||||
{
|
||||
|
||||
You can use whichever method you prefer. Using function params is quick and easy and saves on `$this->request->param()` calls, but keep in mind that if your routes ever change it could change the paramater order and break things. Therefore, it is recommended you use `$this->request->param()`. For example, assuming the following route
|
||||
|
||||
Route::set('example','<controller>(/<action>(/<id>(/<new>)))');
|
||||
|
||||
If you called "example/foobar/4/bobcat" you could access the parameters by either:
|
||||
|
||||
public function action_foobar($id, $new)
|
||||
{
|
||||
|
||||
// OR
|
||||
|
||||
public function action_foobar()
|
||||
{
|
||||
$id = $this->request->param('id');
|
||||
$new = $this->request->param('new');
|
||||
|
||||
Then, let's say sometime in the future you change your url schemes and your routes. The new route is:
|
||||
|
||||
// Note that id and new are switched
|
||||
Route::set('example','<controller>(/<action>(/<new>(/<id>)))');
|
||||
|
||||
Because the `<new>` and `<id>` keys are in a different order, you will need to fix your function definition to be `action_foobar($new, $id)` whereas the function that used `$this->request->param()` calls would continue to function as desired.
|
||||
|
||||
### Examples
|
||||
|
||||
TODO: some examples of actions
|
||||
A view action for a product page.
|
||||
|
||||
public function action_view()
|
||||
{
|
||||
$product = new Model_Product($this->request->param('id'));
|
||||
|
||||
if ( ! $product->loaded())
|
||||
{
|
||||
throw new HTTP_Exception_404('Product not found!');
|
||||
}
|
||||
|
||||
$this->response->body(View::factory('product/view')
|
||||
->set('product', $product));
|
||||
}
|
||||
|
||||
A user login action.
|
||||
|
||||
public function action_login()
|
||||
{
|
||||
$view = View::factory('user/login');
|
||||
|
||||
if ($_POST)
|
||||
{
|
||||
// Try to login
|
||||
if (Auth::instance()->login(arr::get($_POST, 'username'), arr::get($_POST, 'password')))
|
||||
{
|
||||
Request::current()->redirect('home');
|
||||
}
|
||||
|
||||
$view->errors = 'Invalid email or password';
|
||||
}
|
||||
|
||||
$this->response->body($view);
|
||||
}
|
||||
|
||||
## Before and after
|
||||
|
||||
@@ -176,10 +169,10 @@ In general, you should not have to change the `__construct()` function, as anyth
|
||||
// You should almost never need to do this, use before() instead!
|
||||
|
||||
// Be sure Kohana_Request is in the params
|
||||
public function __construct(Kohana_Request $request)
|
||||
public function __construct(Request $request, Response $response)
|
||||
{
|
||||
// You must call parent::__construct at some point in your function
|
||||
parent::__construct($request);
|
||||
parent::__construct($request, $response);
|
||||
|
||||
// Do whatever else you want
|
||||
}
|
||||
|
@@ -1 +1,35 @@
|
||||
Discuss models. What should go in a model, what shouldn't be in a model. Provide **very simple** examples using prepared statements, the query builder, as well as mention modeling libraries.
|
||||
# Models
|
||||
|
||||
From Wikipedia:
|
||||
|
||||
> The model manages the behavior and data of the application domain,
|
||||
> responds to requests for information about its state (usually from the view),
|
||||
> and responds to instructions to change state (usually from the controller).
|
||||
|
||||
Creating a simple model:
|
||||
|
||||
class Model_Post extends Model
|
||||
{
|
||||
public function do_stuff()
|
||||
{
|
||||
// This is where you do domain logic...
|
||||
}
|
||||
}
|
||||
|
||||
If you want database access, have your model extend the Model_Database class:
|
||||
|
||||
class Model_Post extends Model_Database
|
||||
{
|
||||
public function do_stuff()
|
||||
{
|
||||
// This is where you do domain logic...
|
||||
}
|
||||
|
||||
public function get_stuff()
|
||||
{
|
||||
// Get stuff from the database:
|
||||
return $this->db->query(...);
|
||||
}
|
||||
}
|
||||
|
||||
If you want CRUD/ORM capabilities, see the [ORM Module](../../guide/orm)
|
@@ -20,10 +20,10 @@ View files are stored in the `views` directory of the [filesystem](files). You c
|
||||
|
||||
public function action_about()
|
||||
{
|
||||
$this->request->response = View::factory('pages/about');
|
||||
$this->response->body(View::factory('pages/about'));
|
||||
}
|
||||
|
||||
When a view is assigned as the [Request::$response], as in the example above, it will automatically be rendered when necessary. To get the rendered result of a view you can call the [View::render] method or just type cast it to a string. When a view is rendered, the view file is loaded and HTML is generated.
|
||||
When a view is assigned as the [Response::body], as in the example above, it will automatically be rendered when necessary. To get the rendered result of a view you can call the [View::render] method or just type cast it to a string. When a view is rendered, the view file is loaded and HTML is generated.
|
||||
|
||||
public function action_index()
|
||||
{
|
||||
@@ -35,7 +35,7 @@ When a view is assigned as the [Request::$response], as in the example above, it
|
||||
// Or just type cast it to a string
|
||||
$about_page = (string) $view;
|
||||
|
||||
$this->request->response = $about_page;
|
||||
$this->response->body($about_page);
|
||||
}
|
||||
|
||||
## Variables in Views
|
||||
@@ -49,7 +49,7 @@ Once view has been loaded, variables can be assigned to it using the [View::set]
|
||||
->bind('user', $this->user);
|
||||
|
||||
// The view will have $places and $user variables
|
||||
$this->request->response = $view;
|
||||
$this->response->body($view);
|
||||
}
|
||||
|
||||
[!!] The only difference between `set()` and `bind()` is that `bind()` assigns the variable by reference. If you `bind()` a variable before it has been defined, the variable will be created with a value of `NULL`.
|
||||
@@ -64,7 +64,7 @@ You can also assign variables directly to the View object. This is identical to
|
||||
$view->user = $this->user;
|
||||
|
||||
// The view will have $places and $user variables
|
||||
$this->request->response = $view;
|
||||
$this->response->body($view);
|
||||
}
|
||||
|
||||
### Global Variables
|
||||
@@ -150,12 +150,4 @@ Of course, you can also load an entire [Request] within a view:
|
||||
|
||||
<?php echo Request::factory('user/login')->execute() ?>
|
||||
|
||||
This is an example of \[HMVC], which makes it possible to create and read calls to other URLs within your application.
|
||||
|
||||
## Differences From v2.x
|
||||
|
||||
Unlike version 2.x of Kohana, the view is not loaded within the context of
|
||||
the [Controller], so you will not be able to access `$this` as the controller
|
||||
that loaded the view. Passing the controller to the view must be done explictly:
|
||||
|
||||
$view->bind('controller', $this);
|
||||
This is an example of \[HMVC], which makes it possible to create and read calls to other URLs within your application.
|
@@ -1,15 +1,65 @@
|
||||
# Requests
|
||||
|
||||
blah
|
||||
Kohana includes a flexible HMVC request system. It supports out of the box support for internal requests and external requests.
|
||||
|
||||
## The main request
|
||||
HMVC stands for `Hierarchical Model View Controller` and basically means requests can each have MVC triads called from inside each other.
|
||||
|
||||
request::instance() gets the main request, you set the response in the bootstrap (usually), you use $request->status to send a 404 or other status, $request->headers to send headers, is_ajax, etc.
|
||||
The Request object in Kohana is HTTP/1.1 compliant.
|
||||
|
||||
## Subrequests
|
||||
## Creating Requests
|
||||
|
||||
TODO: This will talk about subrequests.
|
||||
Creating a request is very easy:
|
||||
|
||||
<http://kerkness.ca/wiki/doku.php?id=hmvc_in_kohana>
|
||||
### Internal Requests
|
||||
|
||||
<http://kerkness.ca/wiki/doku.php?id=routing:differ_request_for_internal_and_external>
|
||||
An internal request is a request calling to the internal application. It utilizes [routes](routing) to direct the application based on the URI that is passed to it. A basic internal request might look something like:
|
||||
|
||||
$request = Request::factory('welcome');
|
||||
|
||||
In this example, the URI is 'welcome'.
|
||||
|
||||
#### The initial request
|
||||
|
||||
Since Kohana uses HMVC, you can call many requests inside each other. The first request (usually called from `index.php`) is called the "initial request". You can access this request via:
|
||||
|
||||
Request::initial();
|
||||
|
||||
You should only use this method if you are absolutely sure you want the initial request. Otherwise you should use the `Request::current()` method.
|
||||
|
||||
#### Sub-requests
|
||||
|
||||
You can call a request at any time in your application by using the `Request::factory()` syntax. All of these requests will be considered sub-requests.
|
||||
|
||||
Other than this difference, they are exactly the same. You can detect if the request is a sub-request in your controller with the is_initial() method:
|
||||
|
||||
$sub_request = ! $this->request->is_initial()
|
||||
|
||||
### External Requests
|
||||
|
||||
An external request calls out to a third party website.
|
||||
|
||||
You can use this to scrape HTML from a remote site, or make a REST call to a third party API:
|
||||
|
||||
// This uses GET
|
||||
$request = Request::factory('http://www.google.com/');
|
||||
|
||||
// This uses PUT
|
||||
$request = Request::factory('http://example.com/put_api')->method(Request::PUT)->body(json_encode('the body'))->headers('Content-Type', 'application/json');
|
||||
|
||||
// This uses POST
|
||||
$request = Request::factory('http://example.com/post_api')->method(Request::POST)->post(array('foo' => 'bar', 'bar' => 'baz'));
|
||||
|
||||
## Executing Requests
|
||||
|
||||
To execute a request, use the `execute()` method on it. This will give you a [response](responses) object.
|
||||
|
||||
$request = Request::factory('welcome');
|
||||
$response = $request->execute();
|
||||
|
||||
## Request Cache Control
|
||||
|
||||
You can cache requests for fast execution by passing a cache instance in as the second parameter of factory:
|
||||
|
||||
$request = Request::factory('welcome', Cache::instance());
|
||||
|
||||
TODO
|
||||
|
@@ -78,14 +78,45 @@ TODO: example of either using directory or controller where it isn't in the rout
|
||||
|
||||
### Directory
|
||||
|
||||
## Lambda/Callback route logic
|
||||
|
||||
In 3.1, you can specify advanced routing schemes by using lambda routes. Instead of a URI, you can use an anonymous function or callback syntax to specify a function that will process your routes. Here's a simple example:
|
||||
|
||||
If you want to use reverse routing with lambda routes, you must pass the third parameter:
|
||||
|
||||
Route::set('testing', function($uri)
|
||||
{
|
||||
if ($uri == 'foo/bar')
|
||||
return array(
|
||||
'controller' => 'welcome',
|
||||
'action' => 'foobar',
|
||||
);
|
||||
},
|
||||
'foo/bar'
|
||||
);
|
||||
|
||||
As you can see in the below route, the reverse uri parameter might not make sense.
|
||||
|
||||
Route::set('testing', function($uri)
|
||||
{
|
||||
if ($uri == '</language regex/>(.+)')
|
||||
{
|
||||
Cookie::set('language', $match[1]);
|
||||
return array(
|
||||
'controller' => 'welcome',
|
||||
'action' => 'foobar'
|
||||
);
|
||||
}
|
||||
},
|
||||
'<language>/<rest_of_uri>
|
||||
);
|
||||
|
||||
If you are using php 5.2, you can still use callbacks for this behavior (this example omits the reverse route):
|
||||
|
||||
Route::set('testing', array('Class', 'method_to_process_my_uri'));
|
||||
|
||||
## Examples
|
||||
|
||||
TODO: a million billion examples, you can use the following as a guide for some routes to include:
|
||||
|
||||
<http://kerkness.ca/wiki/doku.php?id=routing:routing_basics>
|
||||
<http://kerkness.ca/wiki/doku.php?id=routing:ignoring_overflow_in_a_route>
|
||||
<http://kerkness.ca/wiki/doku.php?id=routing:building_routes_with_subdirectories>
|
||||
|
||||
There are countless other possibilities for routes. Here are some more examples:
|
||||
|
||||
/*
|
||||
@@ -154,14 +185,14 @@ There are countless other possibilities for routes. Here are some more examples:
|
||||
The `directory`, `controller` and `action` can be accessed from the [Request] as public properties like so:
|
||||
|
||||
// From within a controller:
|
||||
$this->request->action;
|
||||
$this->request->controller;
|
||||
$this->request->directory;
|
||||
$this->request->action();
|
||||
$this->request->controller();
|
||||
$this->request->directory();
|
||||
|
||||
// Can be used anywhere:
|
||||
Request::instance()->action;
|
||||
Request::instance()->controller;
|
||||
Request::instance()->directory;
|
||||
Request::current()->action();
|
||||
Request::current()->controller();
|
||||
Request::current()->directory();
|
||||
|
||||
All other keys specified in a route can be accessed via [Request::param()]:
|
||||
|
||||
@@ -169,7 +200,7 @@ All other keys specified in a route can be accessed via [Request::param()]:
|
||||
$this->request->param('key_name');
|
||||
|
||||
// Can be used anywhere:
|
||||
Request::instance()->param('key_name');
|
||||
Request::current()->param('key_name');
|
||||
|
||||
The [Request::param] method takes an optional second argument to specify a default return value in case the key is not set by the route. If no arguments are given, all keys are returned as an associative array. In addition, `action`, `controller` and `directory` are not accessible via [Request::param()].
|
||||
|
||||
|
@@ -13,9 +13,7 @@ There are a few things you'll want to do with your application before moving int
|
||||
This covers most of the global settings that would change between environments.
|
||||
As a general rule, you should enable caching and disable profiling ([Kohana::init] settings) for production sites.
|
||||
[Route::cache] can also help if you have a lot of routes.
|
||||
2. Catch all exceptions in `application/bootstrap.php`, so that sensitive data is cannot be leaked by stack traces.
|
||||
See the example below which was taken from Shadowhand's [wingsc.com source](http://github.com/shadowhand/wingsc).
|
||||
3. Turn on APC or some kind of opcode caching.
|
||||
2. Turn on APC or some kind of opcode caching.
|
||||
This is the single easiest performance boost you can make to PHP itself. The more complex your application, the bigger the benefit of using opcode caching.
|
||||
|
||||
/**
|
||||
@@ -32,34 +30,16 @@ There are a few things you'll want to do with your application before moving int
|
||||
'caching' => Kohana::$environment === Kohana::PRODUCTION,
|
||||
));
|
||||
|
||||
`index.php`:
|
||||
|
||||
/**
|
||||
* Execute the main request using PATH_INFO. If no URI source is specified,
|
||||
* the URI will be automatically detected.
|
||||
*/
|
||||
$request = Request::instance($_SERVER['PATH_INFO']);
|
||||
|
||||
try
|
||||
{
|
||||
// Attempt to execute the response
|
||||
$request->execute();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
if (Kohana::$environment === Kohana::DEVELOPMENT)
|
||||
{
|
||||
// Just re-throw the exception
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// Log the error
|
||||
Kohana::$log->add(Kohana::ERROR, Kohana::exception_text($e));
|
||||
|
||||
// Create a 404 response
|
||||
$request->status = 404;
|
||||
$request->response = View::factory('template')
|
||||
->set('title', '404')
|
||||
->set('content', View::factory('errors/404'));
|
||||
}
|
||||
// Attempt to execute the response
|
||||
$request->execute();
|
||||
|
||||
if ($request->send_headers()->response)
|
||||
{
|
||||
|
@@ -2,106 +2,122 @@
|
||||
|
||||
*This page needs to be reviewed for accuracy by the development team. Better examples would be helpful.*
|
||||
|
||||
Validation can be performed on any array using the [Validate] class. Labels, filters, rules, and callbacks can be attached to a Validate object by the array key, called a "field name".
|
||||
Validation can be performed on any array using the [Validation] class. Labels and rules can be attached to a Validate object by the array key, called a "field name".
|
||||
|
||||
labels
|
||||
: A label is a human-readable version of the field name.
|
||||
|
||||
filters
|
||||
: A filter modifies the value of an field before rules and callbacks are run.
|
||||
|
||||
rules
|
||||
: A rule is a check on a field that returns `TRUE` or `FALSE`. If a rule
|
||||
returns `FALSE`, an error will be added to the field.
|
||||
: A rule is a callback used to decide whether or not to add an error to a field
|
||||
|
||||
callbacks
|
||||
: A callback is custom method that can access the entire Validate object.
|
||||
The return value of a callback is ignored. Instead, the callback must
|
||||
manually add an error to the object using [Validate::error] on failure.
|
||||
[!!] Note that any valid [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback) can be used as a rule.
|
||||
|
||||
[!!] Note that [Validate] callbacks and [PHP callbacks](http://php.net/manual/language.pseudo-types.php#language.types.callback) are not the same.
|
||||
Using `TRUE` as the field name when adding a rule will be applied to all named fields.
|
||||
|
||||
Using `TRUE` as the field name when adding a filter, rule, or callback will by applied to all named fields.
|
||||
Creating a validation object is done using the [Validation::factory] method:
|
||||
|
||||
**The [Validate] object will remove all fields from the array that have not been specifically named by a label, filter, rule, or callback. This prevents access to fields that have not been validated as a security precaution.**
|
||||
|
||||
Creating a validation object is done using the [Validate::factory] method:
|
||||
|
||||
$post = Validate::factory($_POST);
|
||||
$post = Validation::factory($_POST);
|
||||
|
||||
[!!] The `$post` object will be used for the rest of this tutorial. This tutorial will show you how to validate the registration of a new user.
|
||||
|
||||
### Default Rules
|
||||
## Provided Rules
|
||||
|
||||
Validation also comes with several default rules:
|
||||
Kohana provides a set of useful rules in the [Valid] class:
|
||||
|
||||
Rule name | Function
|
||||
------------------------- |-------------------------------------------------
|
||||
[Validate::not_empty] | Value must be a non-empty value
|
||||
[Validate::regex] | Match the value against a regular expression
|
||||
[Validate::min_length] | Minimum number of characters for value
|
||||
[Validate::max_length] | Maximum number of characters for value
|
||||
[Validate::exact_length] | Value must be an exact number of characters
|
||||
[Validate::email] | An email address is required
|
||||
[Valid::not_empty] | Value must be a non-empty value
|
||||
[Valid::regex] | Match the value against a regular expression
|
||||
[Valid::min_length] | Minimum number of characters for value
|
||||
[Valid::max_length] | Maximum number of characters for value
|
||||
[Valid::exact_length] | Value must be an exact number of characters
|
||||
[Valid::email] | An email address is required
|
||||
[Validate::email_domain] | Check that the domain of the email exists
|
||||
[Validate::url] | Value must be a URL
|
||||
[Validate::ip] | Value must be an IP address
|
||||
[Validate::phone] | Value must be a phone number
|
||||
[Validate::credit_card] | Require a credit card number
|
||||
[Validate::date] | Value must be a date (and time)
|
||||
[Validate::alpha] | Only alpha characters allowed
|
||||
[Validate::alpha_dash] | Only alpha and hyphens allowed
|
||||
[Validate::alpha_numeric] | Only alpha and numbers allowed
|
||||
[Validate::digit] | Value must be an integer digit
|
||||
[Validate::decimal] | Value must be a decimal or float value
|
||||
[Validate::numeric] | Only numeric characters allowed
|
||||
[Validate::range] | Value must be within a range
|
||||
[Validate::color] | Value must be a valid HEX color
|
||||
[Validate::matches] | Value matches another field value
|
||||
|
||||
[!!] Any method that exists within the [Validate] class may be used as a validation rule without specifying a complete callback. For example, adding `'not_empty'` is the same as `array('Validate', 'not_empty')`.
|
||||
|
||||
## Adding Filters
|
||||
|
||||
All validation filters are defined as a field name, a method or function (using the [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback) syntax), and an array of parameters:
|
||||
|
||||
$object->filter($field, $callback, $parameter);
|
||||
|
||||
Filters modify the field value before it is checked using rules or callbacks.
|
||||
|
||||
If we wanted to convert the "username" field to lowercase:
|
||||
|
||||
$post->filter('username', 'strtolower');
|
||||
|
||||
If we wanted to remove all leading and trailing whitespace from *all* fields:
|
||||
|
||||
$post->filter(TRUE, 'trim');
|
||||
[Valid::url] | Value must be a URL
|
||||
[Valid::ip] | Value must be an IP address
|
||||
[Valid::phone] | Value must be a phone number
|
||||
[Valid::credit_card] | Require a credit card number
|
||||
[Valid::date] | Value must be a date (and time)
|
||||
[Valid::alpha] | Only alpha characters allowed
|
||||
[Valid::alpha_dash] | Only alpha and hyphens allowed
|
||||
[Valid::alpha_numeric] | Only alpha and numbers allowed
|
||||
[Valid::digit] | Value must be an integer digit
|
||||
[Valid::decimal] | Value must be a decimal or float value
|
||||
[Valid::numeric] | Only numeric characters allowed
|
||||
[Valid::range] | Value must be within a range
|
||||
[Valid::color] | Value must be a valid HEX color
|
||||
[Valid::matches] | Value matches another field value
|
||||
|
||||
## Adding Rules
|
||||
|
||||
All validation rules are defined as a field name, a method or function (using the [PHP callback](http://php.net/callback) syntax), and an array of parameters:
|
||||
|
||||
$object->rule($field, $callback, $parameter);
|
||||
$object->rule($field, $callback, array($parameter1, $parameter2));
|
||||
|
||||
If no parameters are specified, the field value will be passed to the callback. The following two rules are equivalent:
|
||||
|
||||
$object->rule($field, 'not_empty');
|
||||
$object->rule($field, 'not_empty', array(':value'));
|
||||
|
||||
Rules defined in the [Valid] class can be added by using the method name alone. The following three rules are equivalent:
|
||||
|
||||
$object->rule('number', 'phone');
|
||||
$object->rule('number', array('Valid', 'phone'));
|
||||
$object->rule('number', 'Valid::phone');
|
||||
|
||||
## Binding Variables
|
||||
|
||||
The [Validation] class allows you to bind variables to certain strings so that they can be used when defining rules. Variables are bound by calling the [Validation::bind] method.
|
||||
|
||||
$object->bind(':model', $user_model);
|
||||
// Future code will be able to use :model to reference the object
|
||||
$object->rule('username', 'some_rule', array(':model'));
|
||||
|
||||
By default, the validation object will automatically bind the following values for you to use as rule parameters:
|
||||
|
||||
- `:validation` - references the validation object
|
||||
- `:field` - references the field name the rule is for
|
||||
- `:value` - references the value of the field the rule is for
|
||||
|
||||
## Adding Errors
|
||||
|
||||
The [Validation] class will add an error for a field if any of the rules associated to it return `FALSE`. This allows many built in PHP functions to be used as rules, like `in_array`.
|
||||
|
||||
$object->rule('color', 'in_array', array(':value', array('red', 'green', 'blue')));
|
||||
|
||||
Rules added to empty fields will run, but returning `FALSE` will not automatically add an error for the field. In order for a rule to affect empty fields, you must add the error manually by calling the [Validation::error] method. In order to do this, you must pass the validation object to the rule.
|
||||
|
||||
$object->rule($field, 'the_rule', array(':validation', ':field'));
|
||||
|
||||
public function the_rule($validation, $field)
|
||||
{
|
||||
if (something went wrong)
|
||||
{
|
||||
$validation->error($field, 'the_rule');
|
||||
}
|
||||
}
|
||||
|
||||
[!!] `not_empty` and `matches` are the only rules that will run on empty fields and add errors by returning `FALSE`.
|
||||
|
||||
## Example
|
||||
|
||||
To start our example, we will perform validation on a `$_POST` array that contains user registration information:
|
||||
|
||||
$post = Validate::factory($_POST);
|
||||
$post = Validation::factory($_POST);
|
||||
|
||||
Next we need to process the POST'ed information using [Validate]. To start, we need to add some rules:
|
||||
Next we need to process the POST'ed information using [Validation]. To start, we need to add some rules:
|
||||
|
||||
$post
|
||||
->rule('username', 'not_empty')
|
||||
->rule('username', 'regex', array('/^[a-z_.]++$/iD'))
|
||||
|
||||
->rule('username', 'regex', array(':value', '/^[a-z_.]++$/iD'))
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array('6'))
|
||||
->rule('confirm', 'matches', array('password'))
|
||||
|
||||
->rule('password', 'min_length', array(':value', '6'))
|
||||
->rule('confirm', 'matches', array(':validation', 'confirm', 'password'))
|
||||
->rule('use_ssl', 'not_empty');
|
||||
|
||||
Any existing PHP function can also be used a rule. For instance, if we want to check if the user entered a proper value for the SSL question:
|
||||
|
||||
$post->rule('use_ssl', 'in_array', array(array('yes', 'no')));
|
||||
$post->rule('use_ssl', 'in_array', array(':value', array('yes', 'no')));
|
||||
|
||||
Note that all array parameters must still be wrapped in an array! Without the wrapping array, `in_array` would be called as `in_array($value, 'yes', 'no')`, which would result in a PHP error.
|
||||
|
||||
@@ -109,8 +125,6 @@ Any custom rules can be added using a [PHP callback](http://php.net/manual/langu
|
||||
|
||||
$post->rule('username', 'User_Model::unique_username');
|
||||
|
||||
[!!] Currently (v3.0.7) it is not possible to use an object for a rule, only static methods and functions.
|
||||
|
||||
The method `User_Model::unique_username()` would be defined similar to:
|
||||
|
||||
public static function unique_username($username)
|
||||
@@ -125,27 +139,6 @@ The method `User_Model::unique_username()` would be defined similar to:
|
||||
|
||||
[!!] Custom rules allow many additional checks to be reused for multiple purposes. These methods will almost always exist in a model, but may be defined in any class.
|
||||
|
||||
## Adding callbacks
|
||||
|
||||
All validation callbacks are defined as a field name and a method or function (using the [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback) syntax):
|
||||
|
||||
$object->callback($field, $callback);
|
||||
|
||||
The user password must be hashed if it validates, so we will hash it using a callback:
|
||||
|
||||
$post->callback('password', array($model, 'hash_password'));
|
||||
|
||||
This would assume that the `$model->hash_password()` method would be defined similar to:
|
||||
|
||||
public function hash_password(Validate $array, $field)
|
||||
{
|
||||
if ($array[$field])
|
||||
{
|
||||
// Hash the password if it exists
|
||||
$array[$field] = sha1($array[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
# A Complete Example
|
||||
|
||||
First, we need a [View] that contains the HTML form, which will be placed in `application/views/user/register.php`:
|
||||
@@ -188,22 +181,16 @@ Next, we need a controller and action to process the registration, which will be
|
||||
$user = Model::factory('user');
|
||||
|
||||
$post = Validate::factory($_POST)
|
||||
->filter(TRUE, 'trim')
|
||||
|
||||
->filter('username', 'strtolower')
|
||||
|
||||
->rule('username', 'not_empty')
|
||||
->rule('username', 'regex', array('/^[a-z_.]++$/iD'))
|
||||
->rule('username', 'regex', array(':value', '/^[a-z_.]++$/iD'))
|
||||
->rule('username', array($user, 'unique_username'))
|
||||
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array('6'))
|
||||
->rule('confirm', 'matches', array('password'))
|
||||
->rule('password', 'min_length', array(':value', 6))
|
||||
->rule('confirm', 'matches', array(':validation', ':field', 'password'))
|
||||
|
||||
->rule('use_ssl', 'not_empty')
|
||||
->rule('use_ssl', 'in_array', array(array('yes', 'no')))
|
||||
|
||||
->callback('password', array($user, 'hash_password'));
|
||||
->rule('use_ssl', 'in_array', array(':value', array('yes', 'no')));
|
||||
|
||||
if ($post->check())
|
||||
{
|
||||
@@ -218,7 +205,7 @@ Next, we need a controller and action to process the registration, which will be
|
||||
$errors = $post->errors('user');
|
||||
|
||||
// Display the registration form
|
||||
$this->request->response = View::factory('user/register')
|
||||
$this->response->body(View::factory('user/register'))
|
||||
->bind('post', $post)
|
||||
->bind('errors', $errors);
|
||||
}
|
||||
@@ -244,4 +231,4 @@ We will also need a user model, which will be placed in `application/classes/mod
|
||||
|
||||
}
|
||||
|
||||
That is it, we have a complete user registration example that properly checks user input!
|
||||
That is it, we have a complete user registration example that properly checks user input!
|
||||
|
@@ -6,7 +6,7 @@ The first step to preventing [XSS](http://wikipedia.org/wiki/Cross-Site_Scriptin
|
||||
|
||||
## Prevention
|
||||
|
||||
There are a few simple rules to follow to guard your application HTML against XSS. The first is to use the [Security::xss] method to clean any input data that comes from a global variable. If you do not want HTML in a variable, use [strip_tags](http://php.net/strip_tags) to remove all unwanted HTML tags from a value.
|
||||
There are a few simple rules to follow to guard your application HTML against XSS. If you do not want HTML in a variable, use [strip_tags](http://php.net/strip_tags) to remove all unwanted HTML tags from a value.
|
||||
|
||||
[!!] If you allow users to submit HTML to your application, it is highly recommended to use an HTML cleaning tool such as [HTML Purifier](http://htmlpurifier.org/) or [HTML Tidy](http://php.net/tidy).
|
||||
|
||||
|
@@ -1,54 +1,60 @@
|
||||
# Friendly Error Pages <small>written by <a href="http://mathew-davies.co.uk./">Mathew Davies</a></small>
|
||||
# Friendly Error Pages
|
||||
|
||||
By default Kohana 3 doesn't have a method to display friendly error pages like that
|
||||
seen in Kohana 2; In this short guide I will teach you how it is done.
|
||||
By default Kohana 3 doesn't have a method to display friendly error pages like that
|
||||
seen in Kohana 2; In this short guide you will learn how it is done.
|
||||
|
||||
## Prerequisites
|
||||
## Prerequisites
|
||||
|
||||
You will need `'errors' => TRUE` passed to `Kohana::init`. This will convert PHP
|
||||
You will need `'errors' => TRUE` passed to `Kohana::init`. This will convert PHP
|
||||
errors into exceptions which are easier to handle.
|
||||
|
||||
## 1. A Custom Exception
|
||||
|
||||
First off, we are going to need a custom exception class. This is so we can perform different
|
||||
actions based on it in the exception handler. I will talk more about this later.
|
||||
|
||||
_classes/http\_response\_exception.php_
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct access');
|
||||
|
||||
class HTTP_Response_Exception extends Kohana_Exception {}
|
||||
|
||||
## 2. An Improved Exception Handler
|
||||
## 1. An Improved Exception Handler
|
||||
|
||||
Our custom exception handler is self explanatory.
|
||||
|
||||
public static function exception_handler(Exception $e)
|
||||
{
|
||||
if (Kohana::DEVELOPMENT === Kohana::$environment)
|
||||
{
|
||||
Kohana_Core::exception_handler($e);
|
||||
}
|
||||
else
|
||||
{
|
||||
Kohana::$log->add(Kohana::ERROR, Kohana::exception_text($e));
|
||||
class Kohana_Exception extends Kohana_Kohana_Exception {
|
||||
|
||||
$attributes = array
|
||||
(
|
||||
'action' => 500,
|
||||
'message' => rawurlencode($e->getMessage())
|
||||
);
|
||||
|
||||
if ($e instanceof HTTP_Response_Exception)
|
||||
public static function handler(Exception $e)
|
||||
{
|
||||
if (Kohana::DEVELOPMENT === Kohana::$environment)
|
||||
{
|
||||
$attributes['action'] = $e->getCode();
|
||||
parent::handler($e);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Kohana::$log->add(Log::ERROR, parent::text($e));
|
||||
|
||||
// Error sub-request.
|
||||
echo Request::factory(Route::url('error', $attributes))
|
||||
->execute()
|
||||
->send_headers()
|
||||
->response;
|
||||
$attributes = array
|
||||
(
|
||||
'action' => 500,
|
||||
'message' => rawurlencode($e->getMessage())
|
||||
);
|
||||
|
||||
if ($e instanceof HTTP_Exception)
|
||||
{
|
||||
$attributes['action'] = $e->getCode();
|
||||
}
|
||||
|
||||
// Error sub-request.
|
||||
echo Request::factory(Route::get('error')->uri($attributes))
|
||||
->execute()
|
||||
->send_headers()
|
||||
->body();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
// Clean the output buffer if one exists
|
||||
ob_get_level() and ob_clean();
|
||||
|
||||
// Display the exception text
|
||||
echo parent::text($e);
|
||||
|
||||
// Exit with an error status
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +62,7 @@ If we are in the development environment then pass it off to Kohana otherwise:
|
||||
|
||||
* Log the error
|
||||
* Set the route action and message attributes.
|
||||
* If a `HTTP_Response_Exception` was thrown, then override the action with the error code.
|
||||
* If a `HTTP_Exception` was thrown, then override the action with the error code.
|
||||
* Fire off an internal sub-request.
|
||||
|
||||
The action will be used as the HTTP response code. By default this is: 500 (internal
|
||||
@@ -64,12 +70,12 @@ server error) unless a `HTTP_Response_Exception` was thrown.
|
||||
|
||||
So this:
|
||||
|
||||
throw new HTTP_Response_Exception(':file does not exist', array(':file' => 'Gaia'), 404);
|
||||
throw new HTTP_Exception_404(':file does not exist', array(':file' => 'Gaia'));
|
||||
|
||||
would display a nice 404 error page, where:
|
||||
|
||||
throw new Kohana_Exception('Directory :dir must be writable',
|
||||
array(':dir' => Kohana::debug_path(Kohana::$cache_dir)));
|
||||
array(':dir' => Debug::path(Kohana::$cache_dir)));
|
||||
|
||||
would display an error 500 page.
|
||||
|
||||
@@ -80,16 +86,16 @@ would display an error 500 page.
|
||||
'controller' => 'error_handler'
|
||||
));
|
||||
|
||||
## 3. The Error Page Controller
|
||||
## 2. The Error Page Controller
|
||||
|
||||
public function before()
|
||||
public function before()
|
||||
{
|
||||
parent::before();
|
||||
|
||||
$this->template->page = URL::site(rawurldecode(Request::$instance->uri));
|
||||
$this->template->page = URL::site(rawurldecode(Request::$initial->uri()));
|
||||
|
||||
// Internal request only!
|
||||
if (Request::$instance !== Request::$current)
|
||||
if (Request::$initial !== Request::$current)
|
||||
{
|
||||
if ($message = rawurldecode($this->request->param('message')))
|
||||
{
|
||||
@@ -98,71 +104,51 @@ would display an error 500 page.
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->request->action = 404;
|
||||
$this->request->action(404);
|
||||
}
|
||||
|
||||
$this->response->status((int) $this->request->action());
|
||||
}
|
||||
|
||||
1. Set a template variable "page" so the user can see what they requested. This
|
||||
1. Set a template variable "page" so the user can see what they requested. This
|
||||
is for display purposes only.
|
||||
2. If an internal request, then set a template variable "message" to be shown to
|
||||
2. If an internal request, then set a template variable "message" to be shown to
|
||||
the user.
|
||||
3. Otherwise use the 404 action. Users could otherwise craft their own error messages, eg:
|
||||
`error/404/email%20your%20login%20information%20to%20hacker%40google.com`
|
||||
|
||||
|
||||
~~~
|
||||
public function action_404()
|
||||
{
|
||||
$this->template->title = '404 Not Found';
|
||||
|
||||
// Here we check to see if a 404 came from our website. This allows the
|
||||
// webmaster to find broken links and update them in a shorter amount of time.
|
||||
if (isset ($_SERVER['HTTP_REFERER']) AND strstr($_SERVER['HTTP_REFERER'], $_SERVER['SERVER_NAME']) !== FALSE)
|
||||
{
|
||||
// Set a local flag so we can display different messages in our template.
|
||||
$this->template->local = TRUE;
|
||||
}
|
||||
|
||||
// HTTP Status code.
|
||||
$this->request->status = 404;
|
||||
}
|
||||
public function action_404()
|
||||
{
|
||||
$this->template->title = '404 Not Found';
|
||||
|
||||
public function action_503()
|
||||
{
|
||||
$this->template->title = 'Maintenance Mode';
|
||||
$this->request->status = 503;
|
||||
}
|
||||
// Here we check to see if a 404 came from our website. This allows the
|
||||
// webmaster to find broken links and update them in a shorter amount of time.
|
||||
if (isset ($_SERVER['HTTP_REFERER']) AND strstr($_SERVER['HTTP_REFERER'], $_SERVER['SERVER_NAME']) !== FALSE)
|
||||
{
|
||||
// Set a local flag so we can display different messages in our template.
|
||||
$this->template->local = TRUE;
|
||||
}
|
||||
|
||||
public function action_500()
|
||||
{
|
||||
$this->template->title = 'Internal Server Error';
|
||||
$this->request->status = 500;
|
||||
}
|
||||
~~~
|
||||
// HTTP Status code.
|
||||
$this->response->status(404);
|
||||
}
|
||||
|
||||
You will notice that each example method is named after the HTTP response code
|
||||
public function action_503()
|
||||
{
|
||||
$this->template->title = 'Maintenance Mode';
|
||||
}
|
||||
|
||||
public function action_500()
|
||||
{
|
||||
$this->template->title = 'Internal Server Error';
|
||||
}
|
||||
|
||||
You will notice that each example method is named after the HTTP response code
|
||||
and sets the request response code.
|
||||
|
||||
## 4. Handling 3rd Party Modules.
|
||||
|
||||
Some Kohana modules will make calls to `Kohana::exception_handler`. We can redirect
|
||||
calls made to it by extending the Kohana class and passing the exception to our handler.
|
||||
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
class Kohana extends Kohana_Core
|
||||
{
|
||||
/**
|
||||
* Redirect to custom exception_handler
|
||||
*/
|
||||
public static function exception_handler(Exception $e)
|
||||
{
|
||||
Error::exception_handler($e);
|
||||
}
|
||||
}
|
||||
|
||||
## 5. Conclusion
|
||||
## 3. Conclusion
|
||||
|
||||
So that's it. Now displaying a nice error page is as easy as:
|
||||
|
||||
throw new HTTP_Response_Exception('The website is down', NULL, 503);
|
||||
throw new HTTP_Exception_503('The website is down');
|
||||
|
@@ -1,8 +1,4 @@
|
||||
<http://kohanaframework.org/guide/tutorials.git>
|
||||
|
||||
Provide links to some git tutorials.
|
||||
|
||||
### Creating a New Application
|
||||
# Creating a New Application
|
||||
|
||||
[!!] The following examples assume that your web server is already set up, and you are going to create a new application at <http://localhost/gitorial/>.
|
||||
|
||||
@@ -55,8 +51,8 @@ We don't want git to track log or cache files, so add a `.gitignore` file to eac
|
||||
|
||||
Now we need the `index.php` and `bootstrap.php` files:
|
||||
|
||||
wget http://github.com/kohana/kohana/raw/master/index.php
|
||||
wget http://github.com/kohana/kohana/raw/master/application/bootstrap.php -O application/bootstrap.php
|
||||
wget https://github.com/kohana/kohana/raw/3.1/master/index.php --no-check-certificate
|
||||
wget https://github.com/kohana/kohana/raw/3.1/master/application/bootstrap.php --no-check-certificate -O application/bootstrap.php
|
||||
|
||||
Commit these changes too:
|
||||
|
||||
@@ -65,7 +61,7 @@ Commit these changes too:
|
||||
|
||||
That's all there is to it. You now have an application that is using Git for versioning.
|
||||
|
||||
### Adding Submodules
|
||||
## Adding Submodules
|
||||
To add a new submodule complete the following steps:
|
||||
|
||||
1. run the following code - git submodule add repository path for each new submodule e.g.:
|
||||
@@ -77,17 +73,17 @@ To add a new submodule complete the following steps:
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
### Updating Submodules
|
||||
## Updating Submodules
|
||||
|
||||
At some point you will probably also want to upgrade your submodules. To update all of your submodules to the latest `HEAD` version:
|
||||
|
||||
git submodule foreach 'git checkout master && git pull origin master'
|
||||
git submodule foreach 'git checkout 3.1/master && git pull origin 3.1/master'
|
||||
|
||||
To update a single submodule, for example, `system`:
|
||||
|
||||
cd system
|
||||
git checkout master
|
||||
git pull origin master
|
||||
git checkout 3.1/master
|
||||
git pull origin 3.1/master
|
||||
cd ..
|
||||
git add system
|
||||
git commit -m 'Updated system to latest version'
|
||||
@@ -95,7 +91,7 @@ To update a single submodule, for example, `system`:
|
||||
If you want to update a single submodule to a specific commit:
|
||||
|
||||
cd modules/database
|
||||
git pull origin master
|
||||
git pull origin 3.1/master
|
||||
git checkout fbfdea919028b951c23c3d99d2bc1f5bbeda0c0b
|
||||
cd ../..
|
||||
git add database
|
||||
@@ -103,11 +99,11 @@ If you want to update a single submodule to a specific commit:
|
||||
|
||||
Note that you can also check out the commit at a tagged official release point, for example:
|
||||
|
||||
git checkout 3.0.6
|
||||
git checkout 3.1.0
|
||||
|
||||
Simply run `git tag` without arguments to get a list of all tags.
|
||||
|
||||
### Removing Submodules
|
||||
## Removing Submodules
|
||||
To remove a submodule that is no longer needed complete the following steps:
|
||||
|
||||
1. open .gitmodules and remove the reference to the to submodule
|
||||
@@ -126,4 +122,22 @@ To remove a submodule that is no longer needed complete the following steps:
|
||||
|
||||
git rm --cached modules/auth
|
||||
|
||||
**Note:** Do not put a trailing slash at the end of path. If you put a trailing slash at the end of the command, it will fail.
|
||||
**Note:** Do not put a trailing slash at the end of path. If you put a trailing slash at the end of the command, it will fail.
|
||||
|
||||
## Updating Remote Repository URL
|
||||
|
||||
During the development of a project, the source of a submodule may change for any reason (you've created your own fork, the server URL changed, the repository name or path changed, etc...) and you'll have to update those changes. To do so, you'll need to perform the following steps:
|
||||
|
||||
1. edit the .gitmodules file, and change the URL for the submodules which changed.
|
||||
|
||||
2. in your source tree's root run:
|
||||
|
||||
git submodule sync
|
||||
|
||||
3. run `git init` to update the project's repository configuration with the new URLs:
|
||||
|
||||
git submodule init
|
||||
|
||||
And it's done, now you can continue pushing and pulling your submodules with no problems.
|
||||
|
||||
Source: http://jtrancas.wordpress.com/2011/02/06/git-submodule-location/
|
@@ -1,3 +0,0 @@
|
||||
<http://kohanaframework.org/guide/tutorials.urls>
|
||||
|
||||
Not sure if this is actually necessary anymore with the [routing page](routing).
|
@@ -1,292 +1,93 @@
|
||||
# Upgrading from 2.3.x
|
||||
# Migrating from 3.0.x
|
||||
|
||||
*This page needs reviewed for accuracy by the development team.*
|
||||
## Request/Response
|
||||
|
||||
Most of Kohana v3 works very differently from Kohana 2.3, here's a list of common gotchas and tips for upgrading.
|
||||
The request class has been split into a request and response class. To set the response body, you used to do:
|
||||
|
||||
## Naming conventions
|
||||
$this->request->response = 'foo';
|
||||
|
||||
The 2.x series differentiated between different 'types' of class (i.e. controller, model etc.) using suffixes. Folders within model / controller folders didn't have any bearing on the name of the class.
|
||||
This has changed to:
|
||||
|
||||
In 3.0 this approach has been scrapped in favour of the Zend framework filesystem conventions, where the name of the class is a path to the class itself, separated by underscores instead of slashes (i.e. `/some/class/file.php` becomes `Some_Class_File`).
|
||||
$this->response->body('foo');
|
||||
|
||||
See the [conventions documentation](start.conventions) for more information.
|
||||
Some properties that existed in the request class have been converted into methods:
|
||||
|
||||
## Input Library
|
||||
- Request::$controller -> Request::controller()
|
||||
- Request::$action -> Request::action()
|
||||
- Request::$directory -> Request::directory()
|
||||
- Request::$uri -> Request::uri()
|
||||
|
||||
The Input Library has been removed from 3.0 in favour of just using `$_GET` and `$_POST`.
|
||||
Request::instance() has been replaced by Request::current() and Request::initial(). Normally you'll want to use Request::current(), but if you are sure you want the *original* request (when running hmvc requests), use Request::initial().
|
||||
|
||||
### XSS Protection
|
||||
## Validation
|
||||
|
||||
If you need to XSS clean some user input you can use [Security::xss_clean] to sanitise it, like so:
|
||||
The validation class has been improved to include "context" support. Because of this, the api has changed. Also, The class has been split: core validation logic is now separate from built-in validation rules. The new core class is called `Validation` and the rules are located in the `Valid` class.
|
||||
|
||||
$_POST['description'] = security::xss_clean($_POST['description']);
|
||||
### Context
|
||||
|
||||
You can also use the [Security::xss_clean] as a filter with the [Validate] library:
|
||||
The validation class now contains "context" support. This allowed us to merge the rule() and callback() methods, and there is now simply a rule() method that handles both cases.
|
||||
|
||||
$validation = new Validate($_POST);
|
||||
Old usage:
|
||||
|
||||
$validate->filter('description', 'Security::xss_clean');
|
||||
rule('password', 'matches', array('repeat_password'))
|
||||
|
||||
### POST & GET
|
||||
New usage:
|
||||
|
||||
One of the great features of the Input library was that if you tried to access the value in one of the superglobal arrays and it didn't exist the Input library would return a default value that you could specify i.e.:
|
||||
rule('password', 'matches', array(':validation', 'password', 'repeat_password'))
|
||||
|
||||
$_GET = array();
|
||||
The third parameter now contains all parameters that get passed to the rule. If you look at Valid::matches(), you'll see:
|
||||
|
||||
// $id is assigned the value 1
|
||||
$id = Input::instance()->get('id', 1);
|
||||
public static function matches($array, $field, $match)
|
||||
|
||||
$_GET['id'] = 25;
|
||||
:validation is the first parameter, 'password' is the second (the field we want to check) and 'repeat_password' is the third (what we want to match)
|
||||
|
||||
// $id is assigned the value 25
|
||||
$id = Input::instance()->get('id', 1);
|
||||
:validation is a special "context" variable that tells the Validation class to replace with the actual validation class. You can see in this way, the matches rule is no different than how callbacks used to work, yet are more powerful. There are other context variables:
|
||||
|
||||
In 3.0 you can duplicate this functionality using [Arr::get]:
|
||||
- :validation - The validation object
|
||||
- :field - The field being compared (rule('username', 'min_length', array(':field', 4)))
|
||||
- :value - The value of the field
|
||||
|
||||
$_GET = array();
|
||||
You can use any php function as a rule if it returns a boolean value.
|
||||
|
||||
// $id is assigned the value 1
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
### Filters
|
||||
|
||||
$_GET['id'] = 42;
|
||||
Filters have been removed from the validation class. There is no specific replacement. If you were using it with ORM, there is a new mechanism for filtering in that module.
|
||||
|
||||
// $id is assigned the value 42
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
## Cookie salts
|
||||
|
||||
## ORM Library
|
||||
The cookie class now throws an exception if there isn't a salt set, and no salt is the now the default. You'll need to make sure you set the salt in your bootstrap:
|
||||
|
||||
There have been quite a few major changes in ORM since 2.3, here's a list of the more common upgrading problems.
|
||||
Cookie::$salt = 'foobar';
|
||||
|
||||
### Member variables
|
||||
Or define an extended cookie class in your application:
|
||||
|
||||
All member variables are now prefixed with an underscore (_) and are no longer accessible via `__get()`. Instead you have to call a function with the name of the property, minus the underscore.
|
||||
|
||||
For instance, what was once `loaded` in 2.3 is now `_loaded` and can be accessed from outside the class via `$model->loaded()`.
|
||||
|
||||
### Relationships
|
||||
|
||||
In 2.3 if you wanted to iterate a model's related objects you could do:
|
||||
|
||||
foreach($model->{relation_name} as $relation)
|
||||
|
||||
However, in the new system this won't work. In version 2.3 any queries generated using the Database library were generated in a global scope, meaning that you couldn't try and build two queries simultaneously. Take for example:
|
||||
|
||||
# TODO: NEED A DECENT EXAMPLE!!!!
|
||||
|
||||
This query would fail as the second, inner query would 'inherit' the conditions of the first one, thus causing pandemonia.
|
||||
In v3.0 this has been fixed by creating each query in its own scope, however this also means that some things won't work quite as expected. Take for example:
|
||||
|
||||
foreach(ORM::factory('user', 3)->where('post_date', '>', time() - (3600 * 24))->posts as $post)
|
||||
class Cookie extends Kohana_Cookie
|
||||
{
|
||||
echo $post->title;
|
||||
public static $salt = 'foobar';
|
||||
}
|
||||
|
||||
[!!] (See [the Database tutorial](tutorials.databases) for the new query syntax)
|
||||
## Controller constructor
|
||||
|
||||
In 2.3 you would expect this to return an iterator of all posts by user 3 where `post_date` was some time within the last 24 hours, however instead it'll apply the where condition to the user model and return a `Model_Post` with the joining conditions specified.
|
||||
If for some reason you are overloading your controller's constructor, it has changed to:
|
||||
|
||||
To achieve the same effect as in 2.3 you need to rearrange the structure slightly:
|
||||
public function __construct(Request $request, Response $response)
|
||||
|
||||
foreach(ORM::factory('user', 3)->posts->where('post_date', '>', time() - (36000 * 24))->find_all() as $post)
|
||||
{
|
||||
echo $post->title;
|
||||
}
|
||||
## index.php / bootstrap.php changes
|
||||
|
||||
This also applies to `has_one` relationships:
|
||||
The main change here is that the request execution has been removed from bootstrap.php and moved to index.php. This allows you to use one bootstrap when doing testing. The reason for this change is that the bootstrap should only setup the environment. It shouldn't run it.
|
||||
|
||||
// Incorrect
|
||||
$user = ORM::factory('post', 42)->author;
|
||||
// Correct
|
||||
$user = ORM::factory('post', 42)->author->find();
|
||||
## 404 Handling
|
||||
|
||||
### Has and belongs to many relationships
|
||||
Kohana now has built in exception support for 404 and other http status codes. If you were using ReflectionException to detect 404s, you should be using HTTP_Exception_404 instead. For details on how to handle 404s, see [error handling](errors).
|
||||
|
||||
In 2.3 you could specify `has_and_belongs_to_many` relationships. In 3.0 this functionality has been refactored into `has_many` *through*.
|
||||
## Form Class
|
||||
|
||||
In your models you define a `has_many` relationship to the other model but then you add a `'through' => 'table'` attribute, where `'table'` is the name of your through table. For example (in the context of posts<>categories):
|
||||
If you used Form::open(), the default behavior has changed. It used to default to the current URI, but now an empty parameter will default to "/" (your home page).
|
||||
|
||||
$_has_many = array
|
||||
(
|
||||
'categories' => array
|
||||
(
|
||||
'model' => 'category', // The foreign model
|
||||
'through' => 'post_categories' // The joining table
|
||||
),
|
||||
);
|
||||
## Logging
|
||||
|
||||
If you've set up kohana to use a table prefix then you don't need to worry about explicitly prefixing the table.
|
||||
The log message level constants now belong to the Log class. If you are referencing those constants to invoke Kohana::$log->add( ... ) you will need to change the following:
|
||||
|
||||
### Foreign keys
|
||||
|
||||
If you wanted to override a foreign key in 2.x's ORM you had to specify the relationship it belonged to, and your new foreign key in the member variable `$foreign_keys`.
|
||||
|
||||
In 3.0 you now define a `foreign_key` key in the relationship's definition, like so:
|
||||
|
||||
Class Model_Post extends ORM
|
||||
{
|
||||
$_belongs_to = array
|
||||
(
|
||||
'author' => array
|
||||
(
|
||||
'model' => 'user',
|
||||
'foreign_key' => 'user_id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
In this example we should then have a `user_id` field in our posts table.
|
||||
|
||||
|
||||
|
||||
In has_many relationships the `far_key` is the field in the through table which links it to the foreign table and the foreign key is the field in the through table which links "this" model's table to the through table.
|
||||
|
||||
Consider the following setup, "Posts" have and belong to many "Categories" through `posts_sections`.
|
||||
|
||||
| categories | posts_sections | posts |
|
||||
|------------|------------------|---------|
|
||||
| id | section_id | id |
|
||||
| name | post_id | title |
|
||||
| | | content |
|
||||
|
||||
Class Model_Post extends ORM
|
||||
{
|
||||
protected $_has_many = array(
|
||||
'sections' => array(
|
||||
'model' => 'category',
|
||||
'through' => 'posts_sections',
|
||||
'far_key' => 'section_id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Class Model_Category extends ORM
|
||||
{
|
||||
protected $_has_many = array (
|
||||
'posts' => array(
|
||||
'model' => 'post',
|
||||
'through' => 'posts_sections',
|
||||
'foreign_key' => 'section_id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Obviously the aliasing setup here is a little crazy, but it's a good example of how the foreign/far key system works.
|
||||
|
||||
### ORM Iterator
|
||||
|
||||
It's also worth noting that `ORM_Iterator` has now been refactored into `Database_Result`.
|
||||
|
||||
If you need to get an array of ORM objects with their keys as the object's pk, you need to call [Database_Result::as_array], e.g.
|
||||
|
||||
$objects = ORM::factory('user')->find_all()->as_array('id');
|
||||
|
||||
Where `id` is the user table's primary key.
|
||||
|
||||
## Router Library
|
||||
|
||||
In version 2 there was a Router library that handled the main request. It let you define basic routes in a `config/routes.php` file and it would allow you to use custom regex for the routes, however it was fairly inflexible if you wanted to do something radical.
|
||||
|
||||
## Routes
|
||||
|
||||
The routing system (now refered to as the request system) is a lot more flexible in 3.0. Routes are now defined in the bootstrap file (`application/bootstrap.php`) and the module init.php (`modules/module_name/init.php`). It's also worth noting that routes are evaluated in the order that they are defined.
|
||||
|
||||
Instead of defining an array of routes you now create a new [Route] object for each route. Unlike in the 2.x series there is no need to map one uri to another. Instead you specify a pattern for a uri, use variables to mark the segments (i.e. controller, method, id).
|
||||
|
||||
For example, in 2.x these regexes:
|
||||
|
||||
$config['([a-z]+)/?(\d+)/?([a-z]*)'] = '$1/$3/$1';
|
||||
|
||||
Would map the uri `controller/id/method` to `controller/method/id`. In 3.0 you'd use:
|
||||
|
||||
Route::set('reversed','(<controller>(/<id>(/<action>)))')
|
||||
->defaults(array('controller' => 'posts', 'action' => 'index'));
|
||||
|
||||
[!!] Each uri should have be given a unique name (in this case it's `reversed`), the reasoning behind this is explained in [the url tutorial](tutorials.urls).
|
||||
|
||||
Angled brackets denote dynamic sections that should be parsed into variables. Rounded brackets mark an optional section which is not required. If you wanted to only match uris beginning with admin you could use:
|
||||
|
||||
Rouse::set('admin', 'admin(/<controller>(/<id>(/<action>)))');
|
||||
|
||||
And if you wanted to force the user to specify a controller:
|
||||
|
||||
Route::set('admin', 'admin/<controller>(/<id>(/<action>))');
|
||||
|
||||
Also, Kohana does not use any 'default defaults'. If you want Kohana to assume your default action is 'index', then you have to tell it so! You can do this via [Route::defaults]. If you need to use custom regex for uri segments then pass an array of `segment => regex` i.e.:
|
||||
|
||||
Route::set('reversed', '(<controller>(/<id>(/<action>)))', array('id' => '[a-z_]+'))
|
||||
->defaults(array('controller' => 'posts', 'action' => 'index'))
|
||||
|
||||
This would force the `id` value to consist of lowercase alpha characters and underscores.
|
||||
|
||||
### Actions
|
||||
|
||||
One more thing we need to mention is that methods in a controller that can be accessed via the url are now called "actions", and are prefixed with 'action_'. E.g. in the above example, if the user calls `admin/posts/1/edit` then the action is `edit` but the method called on the controller will be `action_edit`. See [the url tutorial](tutorials.urls) for more info.
|
||||
|
||||
## Sessions
|
||||
|
||||
There are no longer any Session::set_flash(), Session::keep_flash() or Session::expire_flash() methods, instead you must use [Session::get_once].
|
||||
|
||||
## URL Helper
|
||||
|
||||
Only a few things have changed with the url helper - `url::redirect()` has been moved into `$this->request->redirect()` within controllers) and `Request::instance()->redirect()` instead.
|
||||
|
||||
`url::current` has now been replaced with `$this->request->uri()`
|
||||
|
||||
## Valid / Validation
|
||||
|
||||
These two classes have been merged into a single class called `Validate`.
|
||||
|
||||
The syntax has also changed a little for validating arrays:
|
||||
|
||||
$validate = new Validate($_POST);
|
||||
|
||||
// Apply a filter to all items in the arrays
|
||||
$validate->filter(TRUE, 'trim');
|
||||
|
||||
// To specify rules individually use rule()
|
||||
$validate
|
||||
->rule('field', 'not_empty')
|
||||
->rule('field', 'matches', array('another_field'));
|
||||
|
||||
// To set multiple rules for a field use rules(), passing an array of rules => params as the second argument
|
||||
$validate->rules('field', array(
|
||||
'not_empty' => NULL,
|
||||
'matches' => array('another_field')
|
||||
));
|
||||
|
||||
The 'required' rule has also been renamed to 'not_empty' for clarity's sake.
|
||||
|
||||
## View Library
|
||||
|
||||
There have been a few minor changes to the View library which are worth noting.
|
||||
|
||||
In 2.3 views were rendered within the scope of the controller, allowing you to use `$this` as a reference to the controller within the view, this has been changed in 3.0. Views now render in an empty scope. If you need to use `$this` in your view you can bind a reference to it using [View::bind]: `$view->bind('this', $this)`.
|
||||
|
||||
It's worth noting, though, that this is *very* bad practice as it couples your view to the controller, preventing reuse. The recommended way is to pass the required variables to the view like so:
|
||||
|
||||
$view = View::factory('my/view');
|
||||
|
||||
$view->variable = $this->property;
|
||||
|
||||
// OR if you want to chain this
|
||||
|
||||
$view
|
||||
->set('variable', $this->property)
|
||||
->set('another_variable', 42);
|
||||
|
||||
// NOT Recommended
|
||||
$view->bind('this', $this);
|
||||
|
||||
Because the view is rendered in an empty scope `Controller::_kohana_load_view` is now redundant. If you need to modify the view before it's rendered (i.e. to add a generate a site-wide menu) you can use [Controller::after].
|
||||
|
||||
Class Controller_Hello extends Controller_Template
|
||||
{
|
||||
function after()
|
||||
{
|
||||
$this->template->menu = '...';
|
||||
|
||||
return parent::after();
|
||||
}
|
||||
}
|
||||
- Kohana::ERROR -> Log::ERROR
|
||||
- Kohana::DEBUG -> Log::DEBUG
|
||||
- Kohana::INFO -> Log::INFO
|
||||
|
Reference in New Issue
Block a user