Upgrade to KH 3.1.3.1
This commit is contained in:
@@ -1,16 +1,105 @@
|
||||
Kohana user guide and live API documentation module
|
||||
## What needs to be done?
|
||||
|
||||
**Note to Contributors**
|
||||
Most articles are stubs, with a couple links to pages to be used as a reference when writing the page. The idea is to use the information on those links to help write the new ones. Some of the old userguide pages can probably be mostly copied, with a few improvements, others will be better to be completely rewritten. If you ever have questions, please feel free to jump in the kohana irc channel.
|
||||
|
||||
Just so you are aware, I am not merging forks of forks. As the owner of a translation language, I expect you to merge the downstream forks into your own. For instance:
|
||||
## Guidelines
|
||||
|
||||
kohana/userguide
|
||||
-- you/userguide-xx
|
||||
-- -- person/userguide-xx
|
||||
Documentation should use complete sentences, good grammar, and be as clear as possible. Use lots of example code, but make sure the examples follow the Kohana conventions and style.
|
||||
|
||||
All changes from `person/userguide-xx` must be merged into your own repo, using `git merge` or the fork queue. See [github forking](http://help.github.com/forking/) for more information about how to merge remote repositories, and note that you will need to add a remote for `person/userguide-xx` using:
|
||||
Try to commit often, with each commit only changing a file or two, rather than changing a ton of files and commiting it all at once. This will make it easier to offer feedback and merge your changes. Make sure your commit messages are clear and descriptive. Good: "Added initial draft of hello world tutorial." Bad: "working on docs".
|
||||
|
||||
git remote add person git://github.com/person/userguide-xx
|
||||
git pull person master
|
||||
If you feel a menu needs to be rearranged or a module needs new pages, please open a [bug report](http://dev.kohanaframework.org/projects/userguide3/issues/new) to discuss it.
|
||||
|
||||
Thanks for your help!
|
||||
## A brief explanation of how the userguide works:
|
||||
|
||||
The userguide uses [Markdown](http://daringfireball.net/projects/markdown/) and [Markdown Extra](http://michelf.com/projects/php-markdown/extra/) for the documentation. Here is a short intro to [Markdown syntax](http://kohanut.com/docs/using.markdown), as well as the [complete guide](http://daringfireball.net/projects/markdown/syntax), and the things [Markdown Extra adds](http://michelf.com/projects/php-markdown/extra/). Also read what the userguide adds to markdown at the end of this readme.
|
||||
|
||||
### Userguide pages
|
||||
|
||||
Userguide pages are in the module they apply to, in `guide/<module>`. Documentation for Kohana is in `system/guide/kohana` and documentation for orm is in `modules/orm/guide/orm`, etc.
|
||||
|
||||
Each module has an index page at `guide/<module>/index.md`.
|
||||
|
||||
Each module's menu is in `guide/<module>/menu.md`.
|
||||
|
||||
### Images
|
||||
|
||||
Any images used in the userguide pages must be in `media/guide/<module>/`. For example, if a userguide page has `` the image would be located at `media/guide/<module>/hello-world.jpg`. Images for the ORM module are in `modules/orm/media/guide/orm`, and images for the Kohana docs are in `system/media/guide/kohana`.
|
||||
|
||||
### API browser
|
||||
|
||||
The API browser is generated from the actual source code. The descriptions for classes, constants, properties, and methods is extracted from the comments and parsed in Markdown. For example if you look in the comment for [Kohana_Core::init](http://github.com/kohana/core/blob/c443c44922ef13421f4a/classes/kohana/core.php#L5) you can see a markdown list and table. These are parsed and show correctly in the API browser. `@param`, `@uses`, `@throws`, `@returns` and other tags are parsed as well.
|
||||
|
||||
## How to Contribute
|
||||
|
||||
### If you don't know git, or you don't feel like you are a good documentation writer:
|
||||
|
||||
Just submit a [bug report](http://dev.kohanaframework.org/projects/userguide3/issues/new) and explain what you think can be improved. If you are a good writer but don't know git, just provide some content in your bug report and we will merge it in.
|
||||
|
||||
### If you know git:
|
||||
|
||||
**Short version**: Create a ticket on redmine for your changes, fork the module whose docs you wish to improve (e.g. `git://github.com/kohana/orm.git` or `git://github.com/kohana/core.git`), checkout the appropriate branch, make changes, and then send a pull request with the ticket number.
|
||||
|
||||
**Long version:** (This still assumes you at least know your way around git, especially how submodules work.)
|
||||
|
||||
1. Create a ticket on redmine for your changes.
|
||||
|
||||
2. Fork the specific repo you want to contribute to on github. (For example go to http://github.com/kohana/core and click the fork button.)
|
||||
|
||||
3. Now go into the repo of the area of docs you want to contribute to and add your forked repo as a new remote, and push to it.
|
||||
|
||||
cd system
|
||||
|
||||
# make sure we are up to date
|
||||
git checkout 3.1/develop
|
||||
git pull
|
||||
|
||||
# add your repository as a new remote
|
||||
git remote add <your name> git@github.com:<your name>/core.git
|
||||
|
||||
# (make some changes to the docs)
|
||||
|
||||
# now commit the changes and push to your repo
|
||||
git commit
|
||||
git push <your name> 3.1/develop
|
||||
|
||||
4. Send a pull request on github containing the ticket number, and update the ticket with a link to the pull request.
|
||||
|
||||
|
||||
# What the userguide adds to markdown:
|
||||
|
||||
In addition to the features and syntax of [Markdown](http://daringfireball.net/projects/markdown/) and [Markdown Extra](http://michelf.com/projects/php-markdown/extra/) the following apply to userguide pages and api documentation:
|
||||
|
||||
### Namespacing
|
||||
|
||||
The first thing to note is that all urls are "namespaced". The name of the module is automatically added to links and image urls, you do not need to include it. For example, to link to the hello world tutorial page from another page in the Kohana userguide, you should use `[Hello World Tutorial](tutorials/hello-world)` rather than `(kohana/tutorials/hello-world)`. To link to pages in a different section of the guide, you can use `../`, for example `[Cache](../cache/usage)`.
|
||||
|
||||
### Notes
|
||||
|
||||
If you put [!!] in front of line it will be a note, put in a box with a lightbulb.
|
||||
|
||||
[!!] This is a note.
|
||||
|
||||
### Headers automatically get IDs
|
||||
|
||||
Headers are automatically assigned an id, based on the content of the header, so each header can be linked to. You can manually assign a different id using the syntax as defined in Markdown Extra. If multiple headers have the same content, like if more than one header is "Examples", only the first will get be automatically assigned an id, so you should manually assign more descriptive ids. For example:
|
||||
|
||||
### Examples {#header-id-examples}
|
||||
|
||||
### API links
|
||||
|
||||
You can make links to the api browser by wrapping any class name in brackets. You may also include a function and it will link to that function. All of the following will link to the API browser:
|
||||
|
||||
[Request]
|
||||
[Request::factory]
|
||||
[Request::factory()]
|
||||
|
||||
If you want to have parameters, only put the brackets around the class and function (not the params), and put a backslash in front of the opening parenthesis.
|
||||
|
||||
[Kohana::config]\('foobar','baz')
|
||||
|
||||
### Including Views
|
||||
|
||||
You may include a view by putting the name of the view in double curly brackets. **If the view is not found, no exception or error will be shown!** The curly brackets and view will simply be shown an the page as is.
|
||||
|
||||
{{some/view}}
|
||||
|
@@ -17,7 +17,7 @@ class Controller_Userguide extends Controller_Template {
|
||||
|
||||
public function before()
|
||||
{
|
||||
if ($this->request->action === 'media')
|
||||
if ($this->request->action() === 'media')
|
||||
{
|
||||
// Do not template media files
|
||||
$this->auto_render = FALSE;
|
||||
@@ -28,26 +28,6 @@ class Controller_Userguide extends Controller_Template {
|
||||
$this->media = Route::get('docs/media');
|
||||
$this->guide = Route::get('docs/guide');
|
||||
|
||||
if (isset($_GET['lang']))
|
||||
{
|
||||
$lang = $_GET['lang'];
|
||||
|
||||
// Load the accepted language list
|
||||
$translations = array_keys(Kohana::message('userguide', 'translations'));
|
||||
|
||||
if (in_array($lang, $translations))
|
||||
{
|
||||
// Set the language cookie
|
||||
Cookie::set('userguide_language', $lang, Date::YEAR);
|
||||
}
|
||||
|
||||
// Reload the page
|
||||
$this->request->redirect($this->request->uri);
|
||||
}
|
||||
|
||||
// Set the translation language
|
||||
I18n::$lang = Cookie::get('userguide_language', Kohana::config('userguide')->lang);
|
||||
|
||||
if (defined('MARKDOWN_PARSER_CLASS'))
|
||||
{
|
||||
throw new Kohana_Exception('Markdown parser already registered. Live documentation will not work in your environment.');
|
||||
@@ -70,92 +50,182 @@ class Controller_Userguide extends Controller_Template {
|
||||
parent::before();
|
||||
}
|
||||
|
||||
// List all modules that have userguides
|
||||
public function index()
|
||||
{
|
||||
$this->template->title = "Userguide";
|
||||
$this->template->breadcrumb = array('User Guide');
|
||||
$this->template->content = View::factory('userguide/index', array('modules' => $this->_modules()));
|
||||
$this->template->menu = View::factory('userguide/menu', array('modules' => $this->_modules()));
|
||||
|
||||
// Don't show disqus on the index page
|
||||
$this->template->hide_disqus = TRUE;
|
||||
}
|
||||
|
||||
// Display an error if a page isn't found
|
||||
public function error($message)
|
||||
{
|
||||
$this->response->status(404);
|
||||
$this->template->title = "Userguide - Error";
|
||||
$this->template->content = View::factory('userguide/error',array('message' => $message));
|
||||
|
||||
// Don't show disqus on error pages
|
||||
$this->template->hide_disqus = TRUE;
|
||||
|
||||
// If we are in a module and that module has a menu, show that
|
||||
if ($module = $this->request->param('module') AND $menu = $this->file($module.'/menu') AND Kohana::config('userguide.modules.'.$module.'.enabled'))
|
||||
{
|
||||
// Namespace the markdown parser
|
||||
Kodoc_Markdown::$base_url = URL::site($this->guide->uri()).'/'.$module.'/';
|
||||
Kodoc_Markdown::$image_url = URL::site($this->media->uri()).'/'.$module.'/';
|
||||
|
||||
$this->template->menu = Markdown($this->_get_all_menu_markdown());
|
||||
$this->template->breadcrumb = array(
|
||||
$this->guide->uri() => 'User Guide',
|
||||
$this->guide->uri(array('module' => $module)) => Kohana::config('userguide.modules.'.$module.'.name'),
|
||||
'Error'
|
||||
);
|
||||
}
|
||||
// If we are in the api browser, show the menu and show the api browser in the breadcrumbs
|
||||
else if (Route::name($this->request->route()) == 'docs/api')
|
||||
{
|
||||
$this->template->menu = Kodoc::menu();
|
||||
|
||||
// Bind the breadcrumb
|
||||
$this->template->breadcrumb = array(
|
||||
$this->guide->uri(array('page' => NULL)) => 'User Guide',
|
||||
$this->request->route()->uri() => 'API Browser',
|
||||
'Error'
|
||||
);
|
||||
}
|
||||
// Otherwise, show the userguide module menu on the side
|
||||
else
|
||||
{
|
||||
$this->template->menu = View::factory('userguide/menu',array('modules' => $this->_modules()));
|
||||
$this->template->breadcrumb = array($this->request->route()->uri() => 'User Guide','Error');
|
||||
}
|
||||
}
|
||||
|
||||
public function action_docs()
|
||||
{
|
||||
$module = $this->request->param('module');
|
||||
$page = $this->request->param('page');
|
||||
|
||||
if ( ! $page)
|
||||
// Trim trailing slash
|
||||
$page = rtrim($page, '/');
|
||||
|
||||
// If no module provided in the url, show the user guide index page, which lists the modules.
|
||||
if ( ! $module)
|
||||
{
|
||||
// Redirect to the default page
|
||||
$this->request->redirect($this->guide->uri(array('page' => Kohana::config('userguide')->default_page)));
|
||||
return $this->index();
|
||||
}
|
||||
|
||||
$file = $this->file($page);
|
||||
// If this module's userguide pages are disabled, show the error page
|
||||
if ( ! Kohana::config('userguide.modules.'.$module.'.enabled'))
|
||||
{
|
||||
return $this->error(__('That module doesn\'t exist, or has userguide pages disabled.'));
|
||||
}
|
||||
|
||||
// Prevent "guide/module" and "guide/module/index" from having duplicate content
|
||||
if ( $page == 'index')
|
||||
{
|
||||
return $this->error(__('Userguide page not found'));
|
||||
}
|
||||
|
||||
// If a module is set, but no page was provided in the url, show the index page
|
||||
if ( ! $page )
|
||||
{
|
||||
$page = 'index';
|
||||
}
|
||||
|
||||
// Find the markdown file for this page
|
||||
$file = $this->file($module.'/'.$page);
|
||||
|
||||
// If it's not found, show the error page
|
||||
if ( ! $file)
|
||||
{
|
||||
$this->error(__('Userguide page not found'));
|
||||
return;
|
||||
return $this->error(__('Userguide page not found'));
|
||||
}
|
||||
|
||||
// Namespace the markdown parser
|
||||
Kodoc_Markdown::$base_url = URL::site($this->guide->uri()).'/'.$module.'/';
|
||||
Kodoc_Markdown::$image_url = URL::site($this->media->uri()).'/'.$module.'/';
|
||||
|
||||
// Set the page title
|
||||
$this->template->title = $this->title($page);
|
||||
$this->template->title = $page == 'index' ? Kohana::config('userguide.modules.'.$module.'.name') : $this->title($page);
|
||||
|
||||
// Parse the page contents into the template
|
||||
Kodoc_Markdown::$show_toc = true;
|
||||
$this->template->content = Markdown(file_get_contents($file));
|
||||
Kodoc_Markdown::$show_toc = false;
|
||||
|
||||
// Attach the menu to the template
|
||||
$this->template->menu = Markdown(file_get_contents($this->file('menu')));
|
||||
|
||||
// Bind module menu items
|
||||
$this->template->bind('module_menus', $module_menus);
|
||||
|
||||
// Attach module-specific menu items
|
||||
$module_menus = array();
|
||||
|
||||
foreach(Kohana::modules() as $module => $path)
|
||||
{
|
||||
if ($file = $this->file('menu.'.$module))
|
||||
{
|
||||
$module_menus[$module] = Markdown(file_get_contents($file));
|
||||
}
|
||||
}
|
||||
// Attach this module's menu to the template
|
||||
$this->template->menu = Markdown($this->_get_all_menu_markdown());
|
||||
|
||||
// Bind the breadcrumb
|
||||
$this->template->bind('breadcrumb', $breadcrumb);
|
||||
|
||||
// Add the breadcrumb
|
||||
// Bind the copyright
|
||||
$this->template->copyright = Kohana::config('userguide.modules.'.$module.'.copyright');
|
||||
|
||||
// Add the breadcrumb trail
|
||||
$breadcrumb = array();
|
||||
$breadcrumb[$this->guide->uri()] = __('User Guide');
|
||||
$breadcrumb[] = $this->section($page);
|
||||
$breadcrumb[] = $this->template->title;
|
||||
$breadcrumb[$this->guide->uri(array('module' => $module))] = Kohana::config('userguide.modules.'.$module.'.name');
|
||||
|
||||
// TODO try and get parent category names (from menu). Regex magic or javascript dom stuff perhaps?
|
||||
|
||||
// Only add the current page title to breadcrumbs if it isn't the index, otherwise we get repeats.
|
||||
if ($page != 'index')
|
||||
{
|
||||
$breadcrumb[] = $this->template->title;
|
||||
}
|
||||
}
|
||||
|
||||
public function action_api()
|
||||
{
|
||||
// Enable the missing class autoloader
|
||||
// Enable the missing class autoloader. If a class cannot be found a
|
||||
// fake class will be created that extends Kodoc_Missing
|
||||
spl_autoload_register(array('Kodoc_Missing', 'create_class'));
|
||||
|
||||
// Get the class from the request
|
||||
$class = $this->request->param('class');
|
||||
|
||||
if ($class)
|
||||
{
|
||||
try
|
||||
{
|
||||
$_class = Kodoc_Class::factory($class);
|
||||
|
||||
if ( ! Kodoc::show_class($_class))
|
||||
throw new Exception(__('That class is hidden'));
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return $this->error(__('API Reference: Class not found.'));
|
||||
}
|
||||
|
||||
$this->template->title = $class;
|
||||
|
||||
$this->template->content = View::factory('userguide/api/class')
|
||||
->set('doc', Kodoc::factory($class))
|
||||
->set('route', $this->request->route);
|
||||
}
|
||||
else
|
||||
// If no class was passed to the url, display the API index page
|
||||
if ( ! $class)
|
||||
{
|
||||
$this->template->title = __('Table of Contents');
|
||||
|
||||
$this->template->content = View::factory('userguide/api/toc')
|
||||
->set('classes', Kodoc::class_methods())
|
||||
->set('route', $this->request->route);
|
||||
->set('route', $this->request->route());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create the Kodoc_Class version of this class.
|
||||
$_class = Kodoc_Class::factory($class);
|
||||
|
||||
// If the class requested and the actual class name are different
|
||||
// (different case, orm vs ORM, auth vs Auth) redirect
|
||||
if ($_class->class->name != $class)
|
||||
{
|
||||
$this->request->redirect($this->request->route()->uri(array('class'=>$_class->class->name)));
|
||||
}
|
||||
|
||||
// If this classes immediate parent is Kodoc_Missing, then it should 404
|
||||
if ($_class->class->getParentClass() AND $_class->class->getParentClass()->name == 'Kodoc_Missing')
|
||||
return $this->error('That class was not found. Check your url and make sure that the module with that class is enabled.');
|
||||
|
||||
// If this classes package has been disabled via the config, 404
|
||||
if ( ! Kodoc::show_class($_class))
|
||||
return $this->error('That class is in package that is hidden. Check the <code>api_packages</code> config setting.');
|
||||
|
||||
// Everything is fine, display the class.
|
||||
$this->template->title = $class;
|
||||
|
||||
$this->template->content = View::factory('userguide/api/class')
|
||||
->set('doc', Kodoc::factory($class))
|
||||
->set('route', $this->request->route());
|
||||
}
|
||||
|
||||
// Attach the menu to the template
|
||||
@@ -170,15 +240,12 @@ class Controller_Userguide extends Controller_Template {
|
||||
// Add the breadcrumb
|
||||
$breadcrumb = array();
|
||||
$breadcrumb[$this->guide->uri(array('page' => NULL))] = __('User Guide');
|
||||
$breadcrumb[$this->request->route->uri()] = $this->title('api');
|
||||
$breadcrumb[$this->request->route()->uri()] = 'API Browser';
|
||||
$breadcrumb[] = $this->template->title;
|
||||
}
|
||||
|
||||
public function action_media()
|
||||
{
|
||||
// Generate and check the ETag for this file
|
||||
$this->request->check_cache(sha1($this->request->uri));
|
||||
|
||||
// Get the file path from the request
|
||||
$file = $this->request->param('file');
|
||||
|
||||
@@ -188,31 +255,23 @@ class Controller_Userguide extends Controller_Template {
|
||||
// Remove the extension from the filename
|
||||
$file = substr($file, 0, -(strlen($ext) + 1));
|
||||
|
||||
if ($file = Kohana::find_file('media', $file, $ext))
|
||||
if ($file = Kohana::find_file('media/guide', $file, $ext))
|
||||
{
|
||||
// Check if the browser sent an "if-none-match: <etag>" header, and tell if the file hasn't changed
|
||||
$this->response->check_cache(sha1($this->request->uri()).filemtime($file), $this->request);
|
||||
|
||||
// Send the file content as the response
|
||||
$this->request->response = file_get_contents($file);
|
||||
$this->response->body(file_get_contents($file));
|
||||
|
||||
// Set the proper headers to allow caching
|
||||
$this->response->headers('content-type', File::mime_by_ext($ext));
|
||||
$this->response->headers('last-modified', date('r', filemtime($file)));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return a 404 status
|
||||
$this->request->status = 404;
|
||||
$this->response->status(404);
|
||||
}
|
||||
|
||||
// Set the proper headers to allow caching
|
||||
$this->request->headers['Content-Type'] = File::mime_by_ext($ext);
|
||||
$this->request->headers['Content-Length'] = filesize($file);
|
||||
$this->request->headers['Last-Modified'] = date('r', filemtime($file));
|
||||
}
|
||||
|
||||
// Display an error if a page isn't found
|
||||
public function error($message)
|
||||
{
|
||||
$this->request->status = 404;
|
||||
$this->template->title = __('User Guide').' - '.__('Error');
|
||||
$this->template->content = View::factory('userguide/error',array('message'=>$message));
|
||||
$this->template->menu = Kodoc::menu();
|
||||
$this->template->breadcrumb = array($this->guide->uri() => __('User Guide'), __('Error'));
|
||||
}
|
||||
|
||||
public function after()
|
||||
@@ -234,7 +293,9 @@ class Controller_Userguide extends Controller_Template {
|
||||
// Add scripts
|
||||
$this->template->scripts = array(
|
||||
$media->uri(array('file' => 'js/jquery.min.js')),
|
||||
$media->uri(array('file' => 'js/jquery.cookie.js')),
|
||||
$media->uri(array('file' => 'js/kodoc.js')),
|
||||
// Syntax Highlighter
|
||||
$media->uri(array('file' => 'js/shCore.js')),
|
||||
$media->uri(array('file' => 'js/shBrushPhp.js')),
|
||||
);
|
||||
@@ -248,67 +309,82 @@ class Controller_Userguide extends Controller_Template {
|
||||
|
||||
public function file($page)
|
||||
{
|
||||
if ( ! ($file = Kohana::find_file('guide', I18n::$lang.'/'.$page, 'md')))
|
||||
{
|
||||
// Use the default file
|
||||
$file = Kohana::find_file('guide', $page, 'md');
|
||||
}
|
||||
|
||||
return $file;
|
||||
return Kohana::find_file('guide', $page, 'md');
|
||||
}
|
||||
|
||||
public function section($page)
|
||||
{
|
||||
$markdown = $this->_get_all_menu_markdown();
|
||||
|
||||
|
||||
if (preg_match('~\*{2}(.+?)\*{2}[^*]+\[[^\]]+\]\('.preg_quote($page).'\)~mu', $markdown, $matches))
|
||||
{
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
public function title($page)
|
||||
{
|
||||
$markdown = $this->_get_all_menu_markdown();
|
||||
|
||||
|
||||
if (preg_match('~\[([^\]]+)\]\('.preg_quote($page).'\)~mu', $markdown, $matches))
|
||||
{
|
||||
// Found a title for this link
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
|
||||
protected function _get_all_menu_markdown()
|
||||
{
|
||||
// Only do this once per request...
|
||||
static $markdown = '';
|
||||
|
||||
|
||||
if (empty($markdown))
|
||||
{
|
||||
// Get core menu items
|
||||
$file = $this->file('menu');
|
||||
|
||||
// Get menu items
|
||||
$file = $this->file($this->request->param('module').'/menu');
|
||||
|
||||
if ($file AND $text = file_get_contents($file))
|
||||
{
|
||||
// Add spans around non-link categories. This is a terrible hack.
|
||||
//echo Kohana::debug($text);
|
||||
|
||||
//$text = preg_replace('/(\s*[\-\*\+]\s*)(.*)/','$1<span>$2</span>',$text);
|
||||
$text = preg_replace('/^(\s*[\-\*\+]\s*)([^\[\]]+)$/m','$1<span>$2</span>',$text);
|
||||
//echo Kohana::debug($text);
|
||||
$markdown .= $text;
|
||||
}
|
||||
|
||||
// Look in module specific files
|
||||
foreach(Kohana::modules() as $module => $path)
|
||||
{
|
||||
if ($file = $this->file('menu.'.$module) AND $text = file_get_contents($file))
|
||||
{
|
||||
// Concatenate markdown to produce one string containing all menu items
|
||||
$markdown .="\n".$text;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
// Get the list of modules from the config, and reverses it so it displays in the order the modules are added, but move Kohana to the top.
|
||||
protected function _modules()
|
||||
{
|
||||
$modules = array_reverse(Kohana::config('userguide.modules'));
|
||||
|
||||
if (isset($modules['kohana']))
|
||||
{
|
||||
$kohana = $modules['kohana'];
|
||||
unset($modules['kohana']);
|
||||
$modules = array_merge(array('kohana' => $kohana), $modules);
|
||||
}
|
||||
|
||||
// Remove modules that have been disabled via config
|
||||
foreach ($modules as $key => $value)
|
||||
{
|
||||
if ( ! Kohana::config('userguide.modules.'.$key.'.enabled'))
|
||||
{
|
||||
unset($modules[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
} // End Userguide
|
||||
|
@@ -10,6 +10,39 @@
|
||||
*/
|
||||
class Kohana_Kodoc {
|
||||
|
||||
/**
|
||||
* @var string PCRE fragment for matching 'Class', 'Class::method', 'Class::method()' or 'Class::$property'
|
||||
*/
|
||||
public static $regex_class_member = '((\w++)(?:::(\$?\w++))?(?:\(\))?)';
|
||||
|
||||
/**
|
||||
* Make a class#member API link using an array of matches from [Kodoc::$regex_class_member]
|
||||
*
|
||||
* @param array $matches array( 1 => link text, 2 => class name, [3 => member name] )
|
||||
* @return string
|
||||
*/
|
||||
public static function link_class_member($matches)
|
||||
{
|
||||
$link = $matches[1];
|
||||
$class = $matches[2];
|
||||
$member = NULL;
|
||||
|
||||
if (isset($matches[3]))
|
||||
{
|
||||
// If the first char is a $ it is a property, e.g. Kohana::$base_url
|
||||
if ($matches[3][0] === '$')
|
||||
{
|
||||
$member = '#property:'.substr($matches[3], 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$member = '#'.$matches[3];
|
||||
}
|
||||
}
|
||||
|
||||
return HTML::anchor(Route::get('docs/api')->uri(array('class' => $class)).$member, $link, NULL, NULL, TRUE);
|
||||
}
|
||||
|
||||
public static function factory($class)
|
||||
{
|
||||
return new Kodoc_Class($class);
|
||||
@@ -135,9 +168,9 @@ class Kohana_Kodoc {
|
||||
{
|
||||
$_class = new ReflectionClass($class);
|
||||
|
||||
if (stripos($_class->name, 'Kohana') === 0)
|
||||
if (stripos($_class->name, 'Kohana_') === 0)
|
||||
{
|
||||
// Skip the extension stuff stuff
|
||||
// Skip transparent extension classes
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -147,13 +180,13 @@ class Kohana_Kodoc {
|
||||
{
|
||||
$declares = $_method->getDeclaringClass()->name;
|
||||
|
||||
if (stripos($declares, 'Kohana') === 0)
|
||||
if (stripos($declares, 'Kohana_') === 0)
|
||||
{
|
||||
// Remove "Kohana_"
|
||||
$declares = substr($declares, 7);
|
||||
}
|
||||
|
||||
if ($declares === $_class->name)
|
||||
if ($declares === $_class->name OR $declares === "Core")
|
||||
{
|
||||
$methods[] = $_method->name;
|
||||
}
|
||||
@@ -219,7 +252,7 @@ class Kohana_Kodoc {
|
||||
}
|
||||
break;
|
||||
case 'throws':
|
||||
if (preg_match('/^(\w+)\W(.*)$/',$text,$matches))
|
||||
if (preg_match('/^(\w+)\W(.*)$/', $text, $matches))
|
||||
{
|
||||
$text = HTML::anchor(Route::get('docs/api')->uri(array('class' => $matches[1])), $matches[1]).' '.$matches[2];
|
||||
}
|
||||
@@ -229,10 +262,9 @@ class Kohana_Kodoc {
|
||||
}
|
||||
break;
|
||||
case 'uses':
|
||||
if (preg_match('/^([a-z_]+)::([a-z_]+)$/i', $text, $matches))
|
||||
if (preg_match('/^'.Kodoc::$regex_class_member.'$/i', $text, $matches))
|
||||
{
|
||||
// Make a class#method API link
|
||||
$text = HTML::anchor(Route::get('docs/api')->uri(array('class' => $matches[1])).'#'.$matches[2], $text);
|
||||
$text = Kodoc::link_class_member($matches);
|
||||
}
|
||||
break;
|
||||
// Don't show @access lines, they are shown elsewhere
|
||||
@@ -269,10 +301,7 @@ class Kohana_Kodoc {
|
||||
*/
|
||||
public static function source($file, $start, $end)
|
||||
{
|
||||
if ( ! $file)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if ( ! $file) return FALSE;
|
||||
|
||||
$file = file($file, FILE_IGNORE_NEW_LINES);
|
||||
|
||||
@@ -306,7 +335,7 @@ class Kohana_Kodoc {
|
||||
return TRUE;
|
||||
|
||||
// Get the package tags for this class (as an array)
|
||||
$packages = Arr::get($class->tags,'package',Array('None'));
|
||||
$packages = Arr::get($class->tags, 'package', array('None'));
|
||||
|
||||
$show_this = FALSE;
|
||||
|
||||
@@ -314,7 +343,7 @@ class Kohana_Kodoc {
|
||||
foreach ($packages as $package)
|
||||
{
|
||||
// If this package is in the allowed packages, set show this to true
|
||||
if (in_array($package,explode(',',$api_packages)))
|
||||
if (in_array($package, explode(',', $api_packages)))
|
||||
$show_this = TRUE;
|
||||
}
|
||||
|
||||
|
@@ -56,7 +56,7 @@ class Kohana_Kodoc_Class extends Kodoc {
|
||||
{
|
||||
foreach ($constants as $name => $value)
|
||||
{
|
||||
$this->constants[$name] = Kohana::debug($value);
|
||||
$this->constants[$name] = Debug::vars($value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +73,22 @@ class Kohana_Kodoc_Class extends Kodoc {
|
||||
while ($parent = $parent->getParentClass());
|
||||
|
||||
list($this->description, $this->tags) = Kodoc::parse($comment);
|
||||
|
||||
// If this class extends Kodoc_Missing, add a warning about possible
|
||||
// incomplete documentation
|
||||
$parent = $this->class;
|
||||
|
||||
while ($parent = $parent->getParentClass())
|
||||
{
|
||||
if ($parent->name == 'Kodoc_Missing')
|
||||
{
|
||||
$warning = "[!!] **This class, or a class parent, could not be
|
||||
found or loaded. This could be caused by a missing
|
||||
module or other dependancy. The documentation for
|
||||
class may not be complete!**";
|
||||
$this->description = Markdown($warning).$this->description;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,23 +100,34 @@ class Kohana_Kodoc_Class extends Kodoc {
|
||||
{
|
||||
$props = $this->class->getProperties();
|
||||
|
||||
sort($props);
|
||||
usort($props, array($this,'_prop_sort'));
|
||||
|
||||
foreach ($props as $key => $property)
|
||||
{
|
||||
// Only show public properties, because Reflection can't get the private ones
|
||||
if ($property->isPublic())
|
||||
{
|
||||
$props[$key] = new Kodoc_Property($this->class->name, $property->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($props[$key]);
|
||||
}
|
||||
// Create Kodoc Properties for each property
|
||||
$props[$key] = new Kodoc_Property($this->class->name, $property->name);
|
||||
}
|
||||
|
||||
return $props;
|
||||
}
|
||||
|
||||
protected function _prop_sort($a, $b)
|
||||
{
|
||||
// If one property is public, and the other is not, it goes on top
|
||||
if ($a->isPublic() AND ( ! $b->isPublic()))
|
||||
return -1;
|
||||
if ($b->isPublic() AND ( ! $a->isPublic()))
|
||||
return 1;
|
||||
|
||||
// If one property is protected and the other is private, it goes on top
|
||||
if ($a->isProtected() AND $b->isPrivate())
|
||||
return -1;
|
||||
if ($b->isProtected() AND $a->isPrivate())
|
||||
return 1;
|
||||
|
||||
// Otherwise just do alphabetical
|
||||
return strcmp($a->name, $b->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of the class properties as [Kodoc_Method] objects.
|
||||
@@ -120,22 +147,44 @@ class Kohana_Kodoc_Class extends Kodoc {
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
protected function _method_sort($a,$b)
|
||||
|
||||
/**
|
||||
* Sort methods based on their visibility and declaring class based on:
|
||||
* - methods will be sorted public, protected, then private.
|
||||
* - methods that are declared by an ancestor will be after classes
|
||||
* declared by the current class
|
||||
* - lastly, they will be sorted alphabetically
|
||||
*
|
||||
*/
|
||||
protected function _method_sort($a, $b)
|
||||
{
|
||||
// If one method is public, and the other is not, it goes on top
|
||||
if ($a->isPublic() AND ( ! $b->isPublic()))
|
||||
return -1;
|
||||
if ($b->isPublic() AND ( ! $a->isPublic()))
|
||||
return 1;
|
||||
|
||||
// If one method is protected and the other is private, it goes on top
|
||||
if ($a->isProtected() AND $b->isPrivate())
|
||||
return -1;
|
||||
if ($b->isProtected() AND $a->isPrivate())
|
||||
return 1;
|
||||
|
||||
// The methods have the same visibility, so check the declaring class depth:
|
||||
|
||||
|
||||
/*
|
||||
echo kohana::debug('a is '.$a->class.'::'.$a->name,'b is '.$b->class.'::'.$b->name,
|
||||
'are the classes the same?',$a->class == $b->class,'if they are, the result is:',strcmp($a->name,$b->name),
|
||||
'is a this class?',$a->name == $this->class->name,-1,
|
||||
'is b this class?',$b->name == $this->class->name,1,
|
||||
'otherwise, the result is:',strcmp($a->class,$b->class)
|
||||
'are the classes the same?', $a->class == $b->class,'if they are, the result is:',strcmp($a->name, $b->name),
|
||||
'is a this class?', $a->name == $this->class->name,-1,
|
||||
'is b this class?', $b->name == $this->class->name,1,
|
||||
'otherwise, the result is:',strcmp($a->class, $b->class)
|
||||
);
|
||||
*/
|
||||
|
||||
|
||||
// If both methods are defined in the same class, just compare the method names
|
||||
if ($a->class == $b->class)
|
||||
return strcmp($a->name,$b->name);
|
||||
return strcmp($a->name, $b->name);
|
||||
|
||||
// If one of them was declared by this class, it needs to be on top
|
||||
if ($a->name == $this->class->name)
|
||||
|
@@ -19,7 +19,25 @@ class Kohana_Kodoc_Markdown extends MarkdownExtra_Parser {
|
||||
* @var string base url for images
|
||||
*/
|
||||
public static $image_url = '';
|
||||
|
||||
|
||||
/**
|
||||
* Currently defined heading ids.
|
||||
* Used to prevent creating multiple headings with same id.
|
||||
* @var array
|
||||
*/
|
||||
protected $_heading_ids = array();
|
||||
|
||||
/**
|
||||
* @var string the generated table of contents
|
||||
*/
|
||||
protected static $_toc = "";
|
||||
|
||||
/**
|
||||
* Slightly less terrible way to make it so the TOC only shows up when we
|
||||
* want it to. set this to true to show the toc.
|
||||
*/
|
||||
public static $show_toc = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// doImage is 10, add image url just before
|
||||
@@ -35,11 +53,92 @@ class Kohana_Kodoc_Markdown extends MarkdownExtra_Parser {
|
||||
$this->span_gamut['doNotes'] = 100;
|
||||
|
||||
// Parse Kohana view inclusions at the very end
|
||||
$this->document_gamut['doIncludeViews'] = 100;
|
||||
$this->document_gamut['doIncludeViews'] = 99;
|
||||
|
||||
// Show table of contents for userguide pages
|
||||
$this->document_gamut['doTOC'] = 100;
|
||||
|
||||
// PHP4 makes me sad.
|
||||
parent::MarkdownExtra_Parser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the heading setext style
|
||||
*
|
||||
* Heading 1
|
||||
* =========
|
||||
*
|
||||
* @param array Matches from regex call
|
||||
* @return string Generated html
|
||||
*/
|
||||
function _doHeaders_callback_setext($matches)
|
||||
{
|
||||
if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
|
||||
return $matches[0];
|
||||
$level = $matches[3]{0} == '=' ? 1 : 2;
|
||||
$attr = $this->_doHeaders_attr($id =& $matches[2]);
|
||||
|
||||
// Only auto-generate id if one doesn't exist
|
||||
if(empty($attr))
|
||||
$attr = ' id="'.$this->make_heading_id($matches[1]).'"';
|
||||
|
||||
// Add this header to the page toc
|
||||
$this->_add_to_toc($level,$matches[1],$this->make_heading_id($matches[1]));
|
||||
|
||||
$block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
|
||||
return "\n" . $this->hashBlock($block) . "\n\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the heading atx style
|
||||
*
|
||||
* # Heading 1
|
||||
*
|
||||
* @param array Matches from regex call
|
||||
* @return string Generated html
|
||||
*/
|
||||
function _doHeaders_callback_atx($matches)
|
||||
{
|
||||
$level = strlen($matches[1]);
|
||||
$attr = $this->_doHeaders_attr($id =& $matches[3]);
|
||||
|
||||
// Only auto-generate id if one doesn't exist
|
||||
if(empty($attr))
|
||||
$attr = ' id="'.$this->make_heading_id($matches[2]).'"';
|
||||
|
||||
// Add this header to the page toc
|
||||
$this->_add_to_toc($level,$matches[2],$this->make_heading_id($matches[2]));
|
||||
|
||||
$block = "<h$level$attr>".$this->runSpanGamut($matches[2])."</h$level>";
|
||||
return "\n" . $this->hashBlock($block) . "\n\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes a heading id from the heading text
|
||||
* If any heading share the same name then subsequent headings will have an integer appended
|
||||
*
|
||||
* @param string The heading text
|
||||
* @return string ID for the heading
|
||||
*/
|
||||
function make_heading_id($heading)
|
||||
{
|
||||
$id = url::title($heading, '-', TRUE);
|
||||
|
||||
if(isset($this->_heading_ids[$id]))
|
||||
{
|
||||
$id .= '-';
|
||||
|
||||
$count = 0;
|
||||
|
||||
while (isset($this->_heading_ids[$id]) AND ++$count)
|
||||
{
|
||||
$id .= $count;
|
||||
}
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
public function doIncludeViews($text)
|
||||
{
|
||||
@@ -47,6 +146,8 @@ class Kohana_Kodoc_Markdown extends MarkdownExtra_Parser {
|
||||
{
|
||||
$replace = array();
|
||||
|
||||
$replace = array();
|
||||
|
||||
foreach ($matches as $set)
|
||||
{
|
||||
list($search, $view) = $set;
|
||||
@@ -60,7 +161,7 @@ class Kohana_Kodoc_Markdown extends MarkdownExtra_Parser {
|
||||
ob_start();
|
||||
|
||||
// Capture the exception handler output and insert it instead
|
||||
Kohana::exception_handler($e);
|
||||
Kohana_exception::handler($e);
|
||||
|
||||
$replace[$search] = ob_get_clean();
|
||||
}
|
||||
@@ -83,7 +184,7 @@ class Kohana_Kodoc_Markdown extends MarkdownExtra_Parser {
|
||||
public function doBaseURL($text)
|
||||
{
|
||||
// URLs containing "://" are left untouched
|
||||
return preg_replace('~(?<!!)(\[.+?\]\()(?!\w++://)([^#]\S*(?:\s*+".+?")?\))~', '$1'.Kodoc_Markdown::$base_url.'$2', $text);
|
||||
return preg_replace('~(?<!!)(\[.+?\]\()(?!\w++://)(?!#)(\S*(?:\s*+".+?")?\))~', '$1'.Kodoc_Markdown::$base_url.'$2', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,49 +204,14 @@ class Kohana_Kodoc_Markdown extends MarkdownExtra_Parser {
|
||||
/**
|
||||
* Parses links to the API browser.
|
||||
*
|
||||
* [Class_Name] or [Class::$property]
|
||||
* [Class_Name], [Class::method] or [Class::$property]
|
||||
*
|
||||
* @param string span text
|
||||
* @return string
|
||||
*/
|
||||
public function doAPI($text)
|
||||
{
|
||||
return preg_replace_callback('/\[([a-z_]++(?:::\$?[a-z_]++)?)\]/i', array($this, '_convert_api_link'), $text);
|
||||
}
|
||||
|
||||
public function _convert_api_link($matches)
|
||||
{
|
||||
static $route;
|
||||
|
||||
if ($route === NULL)
|
||||
{
|
||||
$route = Route::get('docs/api');
|
||||
}
|
||||
|
||||
$link = $matches[1];
|
||||
|
||||
if (strpos($link, '::'))
|
||||
{
|
||||
// Split the class and method
|
||||
list($class, $method) = explode('::', $link, 2);
|
||||
|
||||
if ($method[0] === '$')
|
||||
{
|
||||
// Class property, not method
|
||||
$method = 'property:'.substr($method, 1);
|
||||
}
|
||||
|
||||
// Add the id symbol to the method
|
||||
$method = '#'.$method;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Class with no method
|
||||
$class = $link;
|
||||
$method = NULL;
|
||||
}
|
||||
|
||||
return HTML::anchor($route->uri(array('class' => $class)).$method, $link);
|
||||
return preg_replace_callback('/\['.Kodoc::$regex_class_member.'\]/i', 'Kodoc::link_class_member', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,5 +231,34 @@ class Kohana_Kodoc_Markdown extends MarkdownExtra_Parser {
|
||||
|
||||
return $this->hashBlock('<p class="note">'.$match[1].'</p>');
|
||||
}
|
||||
|
||||
protected function _add_to_toc($level, $name, $id)
|
||||
{
|
||||
self::$_toc[] = array(
|
||||
'level' => $level,
|
||||
'name' => $name,
|
||||
'id' => $id);
|
||||
}
|
||||
|
||||
public function doTOC($text)
|
||||
{
|
||||
// Only add the toc do userguide pages, not api since they already have one
|
||||
if (self::$show_toc AND Route::name(Request::current()->route()) == "docs/guide")
|
||||
{
|
||||
$toc = View::factory('userguide/page-toc')
|
||||
->set('array', self::$_toc)
|
||||
->render()
|
||||
;
|
||||
|
||||
if (($offset = strpos($text, '<p>')) !== FALSE)
|
||||
{
|
||||
// Insert the page TOC just before the first <p>, which every
|
||||
// Markdown page should (will?) have.
|
||||
$text = substr_replace($text, $toc, $offset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
} // End Kodoc_Markdown
|
||||
|
@@ -64,7 +64,7 @@ class Kohana_Kodoc_Method extends Kodoc {
|
||||
|
||||
foreach ($this->method->getParameters() as $i => $param)
|
||||
{
|
||||
$param = new Kodoc_Method_Param(array($this->method->class,$this->method->name),$i);
|
||||
$param = new Kodoc_Method_Param(array($this->method->class, $this->method->name),$i);
|
||||
|
||||
if (isset($tags['param'][$i]))
|
||||
{
|
||||
@@ -74,7 +74,7 @@ class Kohana_Kodoc_Method extends Kodoc {
|
||||
|
||||
if (isset($matches[2]))
|
||||
{
|
||||
$param->description = $matches[2];
|
||||
$param->description = ucfirst($matches[2]);
|
||||
}
|
||||
}
|
||||
$params[] = $param;
|
||||
|
@@ -53,7 +53,7 @@ class Kohana_Kodoc_Method_Param extends Kodoc {
|
||||
|
||||
if ($this->param->isDefaultValueAvailable())
|
||||
{
|
||||
$this->default = Kohana::dump($this->param->getDefaultValue());
|
||||
$this->default = Debug::dump($this->param->getDefaultValue());
|
||||
}
|
||||
|
||||
if ($this->param->isPassedByReference())
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
/**
|
||||
* [!!] This class, or a class parent, could not be found or loaded. This could
|
||||
* be caused by a missing module or other dependancy. The documentation for
|
||||
* class will not be complete!
|
||||
* Set Kodoc_Missing::create_class as an autoloading to prevent missing classes
|
||||
* from crashing the api browser. Classes that are missing a parent will
|
||||
* extend this class, and get a warning in the API browser.
|
||||
*
|
||||
* @package Kohana/Userguide
|
||||
* @category Undocumented
|
||||
|
@@ -51,17 +51,33 @@ class Kohana_Kodoc_Property extends Kodoc {
|
||||
|
||||
if (isset($matches[2]))
|
||||
{
|
||||
$this->description = $matches[2];
|
||||
$this->description = Markdown($matches[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->property = $property;
|
||||
|
||||
if ($property->isStatic())
|
||||
|
||||
// Show the value of static properties, but only if they are public or we are php 5.3 or higher and can force them to be accessible
|
||||
if ($property->isStatic() AND ($property->isPublic() OR version_compare(PHP_VERSION, '5.3', '>=')))
|
||||
{
|
||||
$this->value = Kohana::debug($property->getValue($class));
|
||||
// Force the property to be accessible
|
||||
if (version_compare(PHP_VERSION, '5.3', '>='))
|
||||
{
|
||||
$property->setAccessible(TRUE);
|
||||
}
|
||||
|
||||
// Don't debug the entire object, just say what kind of object it is
|
||||
if (is_object($property->getValue($class)))
|
||||
{
|
||||
$this->value = '<pre>object '.get_class($property->getValue($class)).'()</pre>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->value = Debug::vars($property->getValue($class));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // End Kodoc_Property
|
||||
|
@@ -2,16 +2,30 @@
|
||||
|
||||
return array
|
||||
(
|
||||
// Default userguide page.
|
||||
'default_page' => 'about.kohana',
|
||||
|
||||
// Default the userguide language.
|
||||
'lang' => 'en-us',
|
||||
|
||||
// Enable the API browser. TRUE or FALSE
|
||||
'api_browser' => TRUE,
|
||||
|
||||
// Enable these packages in the API browser. TRUE for all packages, or a string of comma seperated packages, using 'None' for a class with no @package
|
||||
// Example: 'api_packages' => 'Kohana,Kohana/Database,Kohana/ORM,None',
|
||||
'api_packages' => TRUE,
|
||||
|
||||
// Leave this alone
|
||||
'modules' => array(
|
||||
|
||||
// This should be the path to this modules userguide pages, without the 'guide/'. Ex: '/guide/modulename/' would be 'modulename'
|
||||
'userguide' => array(
|
||||
|
||||
// Whether this modules userguide pages should be shown
|
||||
'enabled' => TRUE,
|
||||
|
||||
// The name that should show up on the userguide index page
|
||||
'name' => 'Userguide',
|
||||
|
||||
// A short description of this module, shown on the index page
|
||||
'description' => 'Documentation viewer and api generation.',
|
||||
|
||||
// Copyright message, shown in the footer for this module
|
||||
'copyright' => '© 2008–2011 Kohana Team',
|
||||
)
|
||||
)
|
||||
);
|
||||
|
@@ -1,293 +0,0 @@
|
||||
# Conventions
|
||||
|
||||
It is encouraged to follow Kohana's [coding style](http://dev.kohanaframework.org/wiki/kohana2/CodingStyle). This uses [BSD/Allman style](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) bracing, among other things.
|
||||
|
||||
## Class Names and File Location {#classes}
|
||||
|
||||
Class names in Kohana follow a strict convention to facilitate [autoloading](using.autoloading). Class names should have uppercase first letters with underscores to separate words. Underscores are significant as they directly reflect the file location in the filesystem.
|
||||
|
||||
The following conventions apply:
|
||||
|
||||
1. CamelCased class names should not be used, except when it is undesirable to create a new directory level.
|
||||
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](about.filesystem).
|
||||
|
||||
[!!] 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
|
||||
|
||||
Remember that in a class, an underscore means a new directory. Consider the following examples:
|
||||
|
||||
Class Name | File Path
|
||||
----------------------|-------------------------------
|
||||
Controller_Template | classes/controller/template.php
|
||||
Model_User | classes/model/user.php
|
||||
Database | classes/database.php
|
||||
Database_Query | classes/database/query.php
|
||||
Form | classes/form.php
|
||||
|
||||
## Coding Standards {#coding_standards}
|
||||
|
||||
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.
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
Kohana uses under_score naming, not camelCase naming.
|
||||
|
||||
#### Classes
|
||||
|
||||
// Controller class, uses Controller_ prefix
|
||||
class Controller_Apple extends Controller {
|
||||
|
||||
// Model class, uses Model_ prefix
|
||||
class Model_Cheese extends Model {
|
||||
|
||||
// Regular class
|
||||
class Peanut {
|
||||
|
||||
When creating an instance of a class, don't use parentheses if you're not passing something on to the constructor:
|
||||
|
||||
// Correct:
|
||||
$db = new Database;
|
||||
|
||||
// Incorrect:
|
||||
$db = new Database();
|
||||
|
||||
#### Functions and Methods
|
||||
|
||||
Functions should be all lowercase, and use under_scores to separate words:
|
||||
|
||||
function drink_beverage($beverage)
|
||||
{
|
||||
|
||||
#### Variables
|
||||
|
||||
All variables should be lowercase and use under_score, not camelCase:
|
||||
|
||||
// Correct:
|
||||
$foo = 'bar';
|
||||
$long_example = 'uses underscores';
|
||||
|
||||
// Incorrect:
|
||||
$weDontWantThis = 'understood?';
|
||||
|
||||
### Indentation
|
||||
|
||||
You must use tabs to indent your code. Using spaces for tabbing is strictly forbidden.
|
||||
|
||||
Vertical spacing (for multi-line) is done with spaces. Tabs are not good for vertical alignment because different people have different tab widths.
|
||||
|
||||
$text = 'this is a long text block that is wrapped. Normally, we aim for '
|
||||
. 'wrapping at 80 chars. Vertical alignment is very important for '
|
||||
. 'code readability. Remember that all indentation is done with tabs,'
|
||||
. 'but vertical alignment should be completed with spaces, after '
|
||||
. 'indenting with tabs.';
|
||||
|
||||
### String concatenation
|
||||
|
||||
Don't put spaces around the concatenation operator:
|
||||
|
||||
// Correct:
|
||||
$str = 'one'.$var.'two';
|
||||
|
||||
// Incorrect:
|
||||
$str = 'one'. $var .'two';
|
||||
$str = 'one' . $var . 'two';
|
||||
|
||||
### Single Line Statements
|
||||
|
||||
Single-line IF statements should only be used when breaking normal execution (e.g. return or continue):
|
||||
|
||||
// Acceptable:
|
||||
if ($foo == $bar)
|
||||
return $foo;
|
||||
|
||||
if ($foo == $bar)
|
||||
continue;
|
||||
|
||||
if ($foo == $bar)
|
||||
break;
|
||||
|
||||
if ($foo == $bar)
|
||||
throw new Exception('You screwed up!');
|
||||
|
||||
// Not acceptable:
|
||||
if ($baz == $bun)
|
||||
$baz = $bar + 2;
|
||||
|
||||
### Comparison Operations
|
||||
|
||||
Please use OR and AND for comparison:
|
||||
|
||||
// Correct:
|
||||
if (($foo AND $bar) OR ($b AND $c))
|
||||
|
||||
// Incorrect:
|
||||
if (($foo && $bar) || ($b && $c))
|
||||
|
||||
Please use elseif, not else if:
|
||||
|
||||
// Correct:
|
||||
elseif ($bar)
|
||||
|
||||
// Incorrect:
|
||||
else if($bar)
|
||||
|
||||
### 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.
|
||||
|
||||
switch ($var)
|
||||
{
|
||||
case 'bar':
|
||||
case 'foo':
|
||||
echo 'hello';
|
||||
break;
|
||||
case 1:
|
||||
echo 'one';
|
||||
break;
|
||||
default:
|
||||
echo 'bye';
|
||||
break;
|
||||
}
|
||||
|
||||
### Parentheses
|
||||
|
||||
There should be one space after statement name, followed by a parenthesis. The ! (bang) character must have a space on either side to ensure maximum readability. Except in the case of a bang or type casting, there should be no whitespace after an opening parenthesis or before a closing parenthesis.
|
||||
|
||||
// Correct:
|
||||
if ($foo == $bar)
|
||||
if ( ! $foo)
|
||||
|
||||
// Incorrect:
|
||||
if($foo == $bar)
|
||||
if(!$foo)
|
||||
if ((int) $foo)
|
||||
if ( $foo == $bar )
|
||||
if (! $foo)
|
||||
|
||||
### Ternaries
|
||||
|
||||
All ternary operations should follow a standard format. Use parentheses around expressions only, not around just variables.
|
||||
|
||||
$foo = ($bar == $foo) ? $foo : $bar;
|
||||
$foo = $bar ? $foo : $bar;
|
||||
|
||||
All comparisons and operations must be done inside of a parentheses group:
|
||||
|
||||
$foo = ($bar > 5) ? ($bar + $foo) : strlen($bar);
|
||||
|
||||
When separating complex ternaries (ternaries where the first part goes beyond ~80 chars) into multiple lines, spaces should be used to line up operators, which should be at the front of the successive lines:
|
||||
|
||||
$foo = ($bar == $foo)
|
||||
? $foo
|
||||
: $bar;
|
||||
|
||||
### Type Casting
|
||||
|
||||
Type casting should be done with spaces on each side of the cast:
|
||||
|
||||
// Correct:
|
||||
$foo = (string) $bar;
|
||||
if ( (string) $bar)
|
||||
|
||||
// Incorrect:
|
||||
$foo = (string)$bar;
|
||||
|
||||
When possible, please use type casting instead of ternary operations:
|
||||
|
||||
// Correct:
|
||||
$foo = (bool) $bar;
|
||||
|
||||
// Incorrect:
|
||||
$foo = ($bar == TRUE) ? TRUE : FALSE;
|
||||
|
||||
When casting type to integer or boolean, use the short format:
|
||||
|
||||
// Correct:
|
||||
$foo = (int) $bar;
|
||||
$foo = (bool) $bar;
|
||||
|
||||
// Incorrect:
|
||||
$foo = (integer) $bar;
|
||||
$foo = (boolean) $bar;
|
||||
|
||||
### Constants
|
||||
|
||||
Always use uppercase for constants:
|
||||
|
||||
// Correct:
|
||||
define('MY_CONSTANT', 'my_value');
|
||||
$a = TRUE;
|
||||
$b = NULL;
|
||||
|
||||
// Incorrect:
|
||||
define('MyConstant', 'my_value');
|
||||
$a = True;
|
||||
$b = null;
|
||||
|
||||
Place constant comparisons at the end of tests:
|
||||
|
||||
// Correct:
|
||||
if ($foo !== FALSE)
|
||||
|
||||
// Incorrect:
|
||||
if (FALSE !== $foo)
|
||||
|
||||
This is a slightly controversial choice, so I will explain the reasoning. If we were to write the previous example in plain English, the correct example would read:
|
||||
|
||||
if variable $foo is not exactly FALSE
|
||||
|
||||
And the incorrect example would read:
|
||||
|
||||
if FALSE is not exactly variable $foo
|
||||
|
||||
Since we are reading left to right, it simply doesn't make sense to put the constant first.
|
||||
|
||||
### 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 #.
|
||||
|
||||
// Correct
|
||||
|
||||
//Incorrect
|
||||
// incorrect
|
||||
# Incorrect
|
||||
|
||||
### Regular expressions
|
||||
|
||||
When coding regular expressions please use PCRE rather than the POSIX flavor. PCRE is considered more powerful and faster.
|
||||
|
||||
// Correct:
|
||||
if (preg_match('/abc/i'), $str)
|
||||
|
||||
// Incorrect:
|
||||
if (eregi('abc', $str))
|
||||
|
||||
Use single quotes around your regular expressions rather than double quotes. Single-quoted strings are more convenient because of their simplicity. Unlike double-quoted strings they don't support variable interpolation nor integrated backslash sequences like \n or \t, etc.
|
||||
|
||||
// Correct:
|
||||
preg_match('/abc/', $str);
|
||||
|
||||
// Incorrect:
|
||||
preg_match("/abc/", $str);
|
||||
|
||||
When performing a regular expression search and replace, please use the $n notation for backreferences. This is preferred over \\n.
|
||||
|
||||
// Correct:
|
||||
preg_replace('/(\d+) dollar/', '$1 euro', $str);
|
||||
|
||||
// Incorrect:
|
||||
preg_replace('/(\d+) dollar/', '\\1 euro', $str);
|
||||
|
||||
Finally, please note that the $ character for matching the position at the end of the line allows for a following newline character. Use the D modifier to fix this if needed. [More info](http://blog.php-security.org/archives/76-Holes-in-most-preg_match-filters.html).
|
||||
|
||||
$str = "email@example.com\n";
|
||||
|
||||
preg_match('/^.+@.+$/', $str); // TRUE
|
||||
preg_match('/^.+@.+$/D', $str); // FALSE
|
@@ -1,86 +0,0 @@
|
||||
# Cascading Filesystem
|
||||
|
||||
The Kohana filesystem is a heirarchy of directory structure. When a file is
|
||||
loaded by [Kohana::find_file], it is searched in the following order:
|
||||
|
||||
Application Path
|
||||
: Defined as `APPPATH` in `index.php`. The default value is `application`.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Files that are in directories higher up the include path order take precedence
|
||||
over files of the same name lower down the order, which makes it is possible to
|
||||
overload any file by placing a file with the same name in a "higher" directory:
|
||||
|
||||

|
||||
|
||||
If you have a view file called `welcome.php` in the `APPPATH/views` and
|
||||
`SYSPATH/views` directories, the one in application will be returned when
|
||||
`welcome.php` is loaded because it is at the top of the filesystem.
|
||||
|
||||
## Types of Files
|
||||
|
||||
The top level directories of the application, module, and system paths has the following
|
||||
default directories:
|
||||
|
||||
classes/
|
||||
: All classes that you want to [autoload](using.autoloading) should be stored here.
|
||||
This includes controllers, models, and all other classes. All classes must
|
||||
follow the [class naming conventions](about.conventions#classes).
|
||||
|
||||
config/
|
||||
: Configuration files return an associative array of options that can be
|
||||
loaded using [Kohana::config]. See [config usage](using.configuration) for
|
||||
more information.
|
||||
|
||||
i18n/
|
||||
: Translation files return an associative array of strings. Translation is
|
||||
done using the `__()` method. To translate "Hello, world!" into Spanish,
|
||||
you would call `__('Hello, world!')` with [I18n::$lang] set to "es-es".
|
||||
See [translation usage](using.translation) for more information.
|
||||
|
||||
messages/
|
||||
: Message files return an associative array of strings that can be loaded
|
||||
using [Kohana::message]. Messages and i18n files differ in that messages
|
||||
are not translated, but always written in the default language and referred
|
||||
to by a single key. See [message usage](using.messages) for more information.
|
||||
|
||||
views/
|
||||
: Views are plain PHP files which are used to generate HTML or other output. The view file is
|
||||
loaded into a [View] object and assigned variables, which it then converts
|
||||
into an HTML fragment. Multiple views can be used within each other.
|
||||
See [view usage](usings.views) for more information.
|
||||
|
||||
## Finding Files
|
||||
|
||||
The path to any file within the filesystem can be found by calling [Kohana::find_file]:
|
||||
|
||||
// Find the full path to "classes/cookie.php"
|
||||
$path = Kohana::find_file('classes', 'cookie');
|
||||
|
||||
// Find the full path to "views/user/login.php"
|
||||
$path = Kohana::find_file('views', 'user/login');
|
||||
|
||||
|
||||
# Vendor Extensions
|
||||
|
||||
We call extensions that are not specific to Kohana "vendor" extensions.
|
||||
For example, if you wanted to use [DOMPDF](http://code.google.com/p/dompdf),
|
||||
you would copy it to `application/vendor/dompdf` and include the DOMPDF
|
||||
autoloading class:
|
||||
|
||||
require Kohana::find_file('vendor', 'dompdf/dompdf/dompdf_config.inc');
|
||||
|
||||
Now you can use DOMPDF without loading any more files:
|
||||
|
||||
$pdf = new DOMPDF;
|
||||
|
||||
[!!] If you want to convert views into PDFs using DOMPDF, try the
|
||||
[PDFView](http://github.com/shadowhand/pdfview) module.
|
@@ -1,73 +0,0 @@
|
||||
# Request Flow
|
||||
|
||||
Every application follows the same flow:
|
||||
|
||||
1. Application starts from `index.php`.
|
||||
2. The application, module, and system paths are set.
|
||||
3. Error reporting levels are set.
|
||||
4. Install file is loaded, if it exists.
|
||||
5. The [Kohana] class is loaded.
|
||||
6. The bootstrap file, `APPPATH/bootstrap.php`, is included.
|
||||
7. [Kohana::init] is called, which sets up error handling, caching, and logging.
|
||||
8. [Kohana_Config] readers and [Kohana_Log] writers are attached.
|
||||
9. [Kohana::modules] is called to enable additional modules.
|
||||
* Module paths are added to the [cascading filesystem](about.filesystem).
|
||||
* Includes the module `init.php` file, if it exists.
|
||||
* The `init.php` file can perform additional environment setup, including adding routes.
|
||||
10. [Route::set] is called multiple times to define the [application routes](using.routing).
|
||||
11. [Request::instance] is called to start processing the request.
|
||||
1. Checks each route that has been set until a match is found.
|
||||
2. Creates the controller instance and passes the request to it.
|
||||
3. Calls the [Controller::before] method.
|
||||
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](about.mvc).
|
||||
12. The main [Request] response is displayed
|
||||
|
||||
## index.php
|
||||
|
||||
Kohana follows a [front controller] pattern, which means that all requests are sent to `index.php`. This allows a very clean [filesystem](about.filesystem) design. In `index.php`, there are some very basic configuration options available. You can change the `$application`, `$modules`, and `$system` paths and set the error reporting level.
|
||||
|
||||
The `$application` variable lets you set the directory that contains your application files. By default, this is `application`. The `$modules` variable lets you set the directory that contains module files. The `$system` variable lets you set the directory that contains the default Kohana files.
|
||||
|
||||
You can move these three directories anywhere. For instance, if your directories are set up like this:
|
||||
|
||||
www/
|
||||
index.php
|
||||
application/
|
||||
modules/
|
||||
system/
|
||||
|
||||
You could move the directories out of the web root:
|
||||
|
||||
application/
|
||||
modules/
|
||||
system/
|
||||
www/
|
||||
index.php
|
||||
|
||||
Then you would change the settings in `index.php` to be:
|
||||
|
||||
$application = '../application';
|
||||
$modules = '../modules';
|
||||
$system = '../system';
|
||||
|
||||
Now none of the directories can be accessed by the web server. It is not necessary to make this change, but does make it possible to share the directories with multiple applications, among other things.
|
||||
|
||||
[!!] There is a security check at the top of every Kohana file to prevent it from being accessed without using the front controller. However, it is more secure to move the application, modules, and system directories to a location that cannot be accessed via the web.
|
||||
|
||||
### Error Reporting
|
||||
|
||||
By default, Kohana displays all errors, including strict mode warnings. This is set using [error_reporting](http://php.net/error_reporting):
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
When you application is live and in production, a more conservative setting is recommended, such as ignoring notices:
|
||||
|
||||
error_reporting(E_ALL & ~E_NOTICE);
|
||||
|
||||
If you get a white screen when an error is triggered, your host probably has disabled displaying errors. You can turn it on again by adding this line just after your `error_reporting` call:
|
||||
|
||||
ini_set('display_errors', TRUE);
|
||||
|
||||
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.
|
@@ -1,96 +0,0 @@
|
||||
# Installation
|
||||
|
||||
1. Download the latest **stable** release from the [Kohana website](http://kohanaframework.org/).
|
||||
2. Unzip the downloaded package to create a `kohana` directory.
|
||||
3. Upload the contents of this folder to your webserver.
|
||||
4. Open `application/bootstrap.php` and make the following changes:
|
||||
- Set the default [timezone](http://php.net/timezones) for your application.
|
||||
- Set the `base_url` in the [Kohana::init] call to reflect the location of the kohana folder on your server.
|
||||
6. Make sure the `application/cache` and `application/logs` directories are writable by the web server.
|
||||
7. Test your installation by opening the URL you set as the `base_url` in your favorite browser.
|
||||
|
||||
[!!] Depending on your platform, the installation's subdirs may have lost their permissions thanks to zip extraction. Chmod them all to 755 by running `find . -type d -exec chmod 0755 {} \;` from the root of your Kohana installation.
|
||||
|
||||
You should see the installation page. If it reports any errors, you will need to correct them before continuing.
|
||||
|
||||

|
||||
|
||||
Once your install page reports that your environment is set up correctly you need to either rename or delete `install.php` in the root directory. You should then see the Kohana welcome page:
|
||||
|
||||

|
||||
|
||||
## Setting up a production environment
|
||||
|
||||
There are a few things you'll want to do with your application before moving into production.
|
||||
|
||||
1. See the [Configuration page](about.configuration) in the docs.
|
||||
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 caching](api/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.
|
||||
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.
|
||||
|
||||
[!!] 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), [Nginx](http://wiki.nginx.org/NginxHttpFcgiModule#fastcgi_param)). This is considered better practice than many alternative methods to set Kohana::$enviroment.
|
||||
|
||||
/**
|
||||
* Set the environment string by the domain (defaults to Kohana::DEVELOPMENT).
|
||||
*/
|
||||
Kohana::$environment = ($_SERVER['SERVER_NAME'] !== 'localhost') ? Kohana::PRODUCTION : Kohana::DEVELOPMENT;
|
||||
/**
|
||||
* Initialise Kohana based on environment
|
||||
*/
|
||||
Kohana::init(array(
|
||||
'base_url' => '/',
|
||||
'index_file' => FALSE,
|
||||
'profile' => Kohana::$environment !== Kohana::PRODUCTION,
|
||||
'caching' => Kohana::$environment === Kohana::PRODUCTION,
|
||||
));
|
||||
|
||||
/**
|
||||
* 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'));
|
||||
}
|
||||
|
||||
if ($request->send_headers()->response)
|
||||
{
|
||||
// Get the total memory and execution time
|
||||
$total = array(
|
||||
'{memory_usage}' => number_format((memory_get_peak_usage() - KOHANA_START_MEMORY) / 1024, 2).'KB',
|
||||
'{execution_time}' => number_format(microtime(TRUE) - KOHANA_START_TIME, 5).' seconds');
|
||||
|
||||
// Insert the totals into the response
|
||||
$request->response = str_replace(array_keys($total), $total, $request->response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Display the request response.
|
||||
*/
|
||||
echo $request->response;
|
||||
|
@@ -1,18 +0,0 @@
|
||||
# What is Kohana?
|
||||
|
||||
Kohana is an open source, [object oriented](http://wikipedia.org/wiki/Object-Oriented_Programming) [MVC](http://wikipedia.org/wiki/Model–View–Controller "Model View Controller") [web framework](http://wikipedia.org/wiki/Web_Framework) built using [PHP5](http://php.net/manual/intro-whatis "PHP Hypertext Preprocessor") by a team of volunteers that aims to be swift, secure, and small.
|
||||
|
||||
[!!] Kohana is licensed under a [BSD license](http://kohanaframework.org/license), so you can legally use it for any kind of open source, commercial, or personal project.
|
||||
|
||||
## What makes Kohana great?
|
||||
|
||||
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.
|
||||
|
||||
## Contribute to the Documentation
|
||||
|
||||
We are working very hard to provide complete documentation. To help improve the guide, please [fork the userguide](http://github.com/kohana/userguide), make your changes, and send a pull request. If you are not familiar with git, you can also submit a [feature request](http://dev.kohanaframework.org/projects/kohana3/issues) (requires registration).
|
||||
|
||||
## Help, I can't find the answer?
|
||||
If you are having trouble finding an answer here, have a look through the [unofficial wiki](http://kerkness.ca/wiki/doku.php). Your answer may also be found by searching the [forum](http://forum.kohanaphp.com/) or [stackoverflow](http://stackoverflow.com/questions/tagged/kohana) followed by asking your question on either. Additionally, you can chat with the community of developers on the freenode [#kohana](irc://irc.freenode.net/kohana) IRC channel.
|
@@ -1,7 +0,0 @@
|
||||
# (Hierarchical) Model View Controller
|
||||
|
||||
Model View Controller (Or MVC for short) is a popular design pattern that separates your data sources (Model) from the presentation/templates (View) and the request logic (Controller).
|
||||
|
||||
It makes it much easier to develop applications as the system is designed to maximise the code reuse, meaning you don't have to write as much!
|
||||
|
||||
[!!] Stub
|
@@ -1,4 +0,0 @@
|
||||
# Translation
|
||||
|
||||
[!!] This article is a stub!
|
||||
|
@@ -1,290 +0,0 @@
|
||||
# Upgrading from 2.3.x
|
||||
|
||||
Most of Kohana v3 works very differently from Kohana 2.3, here's a list of common gotchas and tips for upgrading.
|
||||
|
||||
## Naming conventions
|
||||
|
||||
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.
|
||||
|
||||
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`).
|
||||
|
||||
See the [conventions documentation](start.conventions) for more information.
|
||||
|
||||
## Input Library
|
||||
|
||||
The Input Library has been removed from 3.0 in favour of just using `$_GET` and `$_POST`.
|
||||
|
||||
### XSS Protection
|
||||
|
||||
If you need to XSS clean some user input you can use [Security::xss_clean] to sanitise it, like so:
|
||||
|
||||
$_POST['description'] = security::xss_clean($_POST['description']);
|
||||
|
||||
You can also use the [Security::xss_clean] as a filter with the [Validate] library:
|
||||
|
||||
$validation = new Validate($_POST);
|
||||
|
||||
$validate->filter('description', 'Security::xss_clean');
|
||||
|
||||
### POST & GET
|
||||
|
||||
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.:
|
||||
|
||||
$_GET = array();
|
||||
|
||||
// $id is assigned the value 1
|
||||
$id = Input::instance()->get('id', 1);
|
||||
|
||||
$_GET['id'] = 25;
|
||||
|
||||
// $id is assigned the value 25
|
||||
$id = Input::instance()->get('id', 1);
|
||||
|
||||
In 3.0 you can duplicate this functionality using [Arr::get]:
|
||||
|
||||
$_GET = array();
|
||||
|
||||
// $id is assigned the value 1
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
|
||||
$_GET['id'] = 42;
|
||||
|
||||
// $id is assigned the value 42
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
|
||||
## ORM Library
|
||||
|
||||
There have been quite a few major changes in ORM since 2.3, here's a list of the more common upgrading problems.
|
||||
|
||||
### Member variables
|
||||
|
||||
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)
|
||||
{
|
||||
echo $post->title;
|
||||
}
|
||||
|
||||
[!!] (See [the Database tutorial](tutorials.databases) for the new query syntax)
|
||||
|
||||
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.
|
||||
|
||||
To achieve the same effect as in 2.3 you need to rearrange the structure slightly:
|
||||
|
||||
foreach(ORM::factory('user', 3)->posts->where('post_date', '>', time() - (36000 * 24))->find_all() as $post)
|
||||
{
|
||||
echo $post->title;
|
||||
}
|
||||
|
||||
This also applies to `has_one` relationships:
|
||||
|
||||
// Incorrect
|
||||
$user = ORM::factory('post', 42)->author;
|
||||
// Correct
|
||||
$user = ORM::factory('post', 42)->author->find();
|
||||
|
||||
### Has and belongs to many relationships
|
||||
|
||||
In 2.3 you could specify `has_and_belongs_to_many` relationships. In 3.0 this functionality has been refactored into `has_many` *through*.
|
||||
|
||||
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):
|
||||
|
||||
$_has_many = array
|
||||
(
|
||||
'categories' => array
|
||||
(
|
||||
'model' => 'category', // The foreign model
|
||||
'through' => 'post_categories' // The joining table
|
||||
),
|
||||
);
|
||||
|
||||
If you've set up kohana to use a table prefix then you don't need to worry about explicitly prefixing the table.
|
||||
|
||||
### 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();
|
||||
}
|
||||
}
|
@@ -1,31 +0,0 @@
|
||||
1. **Erste Schritte**
|
||||
- [Was ist Kohana?](about.kohana)
|
||||
- [Regeln und Stil](about.conventions)
|
||||
- [Model-View-Controller](about.mvc)
|
||||
- [Kaskaden-Dateisystem](about.filesystem)
|
||||
- [Anfrageablauf](about.flow)
|
||||
- [Installation](about.install)
|
||||
- [Upgrading](about.upgrading)
|
||||
- [Schnittstellen<EFBFBD>bersicht](api)
|
||||
2. **Allgemeine Verwendung**
|
||||
- [Einstellungen](using.configuration)
|
||||
- [autom. Klassen-Aufruf](using.autoloading)
|
||||
- [Views und HTML](using.views)
|
||||
- [Sessions und Cookies](using.sessions)
|
||||
- [Nachrichten](using.messages)
|
||||
3. **Fehlersuche**
|
||||
- [Quelltext](debugging.code)
|
||||
- [Fehlerbehandlung](debugging.errors)
|
||||
- [Programmanalyse](debugging.profiling)
|
||||
4. **Sicherheit**
|
||||
- [XSS](security.xss)
|
||||
- [Validierung](security.validation)
|
||||
- [Cookies](security.cookies)
|
||||
- [Datenbank](security.database)
|
||||
5. **Tutorials**
|
||||
- [Hallo Welt](tutorials.helloworld)
|
||||
- [Routen, URLs und Verweise](tutorials.urls)
|
||||
- [Bereinigte URLs](tutorials.removeindex)
|
||||
- [Datenbanken](tutorials.databases)
|
||||
- [ORM](tutorials.orm)
|
||||
- [Arbeit mit Git](tutorials.git)
|
@@ -1,18 +0,0 @@
|
||||
# Debugging
|
||||
|
||||
Kohana includes several powerful 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.
|
||||
|
||||
// Display a dump of the $foo and $bar variables
|
||||
echo Kohana::debug($foo, $bar);
|
||||
|
||||
Kohana also provides a method to show the source code of a particular file using [Kohana::debug_source].
|
||||
|
||||
// Display this line of source code
|
||||
echo Kohana::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]:
|
||||
|
||||
// Displays "APPPATH/cache" rather than the real path
|
||||
echo Kohana::debug_path(APPPATH.'cache');
|
@@ -1,22 +0,0 @@
|
||||
# Error/Exception Handling
|
||||
|
||||
Kohana provides both an exception handler and an error handler that transforms errors into exceptions using PHP's [ErrorException](http://php.net/errorexception) class. Many details of the error and the internal state of the application is displayed by the handler:
|
||||
|
||||
1. Exception class
|
||||
2. Error level
|
||||
3. Error message
|
||||
4. Source of the error, with the error line highlighted
|
||||
5. A [debug backtrace](http://php.net/debug_backtrace) of the execution flow
|
||||
6. Included files, loaded extensions, and global variables
|
||||
|
||||
## Example
|
||||
|
||||
Click any of the links to toggle the display of additional information:
|
||||
|
||||
<div>{{userguide/examples/error}}</div>
|
||||
|
||||
## Disabling Error/Exception Handling
|
||||
|
||||
If you do not want to use the internal error handling, you can disable it when calling [Kohana::init]:
|
||||
|
||||
Kohana::init(array('errors' => FALSE));
|
@@ -1,20 +0,0 @@
|
||||
# Profiling
|
||||
|
||||
Kohana provides a very simple way to display statistics about your application:
|
||||
|
||||
1. Common [Kohana] method calls
|
||||
2. Requests
|
||||
3. [Database] queries
|
||||
4. Average execution times for your application
|
||||
|
||||
## Example
|
||||
|
||||
You can display or collect the current [profiler] statistics at any time:
|
||||
|
||||
<div id="kohana-profiler">
|
||||
<?php echo View::factory('profiler/stats') ?>
|
||||
</div>
|
||||
|
||||
## Preview
|
||||
|
||||
{{profiler/stats}}
|
150
includes/kohana/modules/userguide/guide/developers.md
Normal file
150
includes/kohana/modules/userguide/guide/developers.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# Distributed Source Control Management
|
||||
|
||||
Unlike SVN, git does not used a central repository. This is why git is "distributed" and SVN is
|
||||
"centralized". Although this makes git an extremely powerful system for collaborators, tracking
|
||||
changes between various collaborators can quickly become difficult as multiple forks are created.
|
||||
|
||||
Please read the following before working with this code:
|
||||
|
||||
1. [Dealing with newlines](http://github.com/guides/dealing-with-newlines-in-git)
|
||||
2. [Submitting changes from your fork](http://github.com/guides/fork-a-project-and-submit-your-modifications)
|
||||
3. [Using SSH keys with github](http://github.com/guides/how-to-not-have-to-type-your-password-for-every-push)
|
||||
|
||||
## Managing Remote Repositories
|
||||
|
||||
First, you will need to tell git about the remote repository:
|
||||
|
||||
> git remote add kohana git://github.com/kohana/kohana.git
|
||||
|
||||
This tells git about the kohana repository and gives it a name which we can use to refer to it when
|
||||
fetching changes from the repository.
|
||||
|
||||
## Developing locally
|
||||
|
||||
There are 3 branches in all the kohana repositories:
|
||||
|
||||
* **master** This branch always points to the latest release tag. In essence it points to the last stable edition of the codebase
|
||||
* **3.0.x** This is a release branch for development of the 3.0.x series, i.e. 3.0, 3.0.3, 3.0.8 etc.
|
||||
* **3.1.x** This is a release branch for development of the 3.1.x series, i.e. 3.1, 3.1.4, 3.1.14 etc.
|
||||
|
||||
To work on a specific release branch you need to check it out then check out the appropriate branches.
|
||||
Release branch names follow the same convention in both kohana/kohana and kohana/core.
|
||||
|
||||
To work on 3.0.x you'd do the following:
|
||||
|
||||
> git clone git://github.com/kohana/kohana.git
|
||||
....
|
||||
|
||||
> cd kohana
|
||||
> git submodule update --init
|
||||
....
|
||||
|
||||
> git checkout 3.0.x
|
||||
Switched to branch '3.0.x'
|
||||
> git submodule update
|
||||
|
||||
> cd system
|
||||
> git checkout 3.0.x
|
||||
# Switched to branch 3.0.x
|
||||
|
||||
It's important that you follow the last step, because unlike svn, git submodules point at a
|
||||
specific commit rather than the tip of a branch. If you cd into the system folder after
|
||||
a `git submodule update` and run `git status` you'll be told:
|
||||
|
||||
# Not currently on any branch.
|
||||
nothing to commit (working directory clean)
|
||||
|
||||
Similarly, if you want to work on modules, make sure you checkout the correct branch before you start working.
|
||||
|
||||
**IMPORTANT:** It is highly recommended that you run the unit tests whilst developing to
|
||||
ensure that any changes you make do not break the api. *See TESTING.md for more info*
|
||||
|
||||
### Creating new features
|
||||
|
||||
New features or API breaking modifications should be developed in separate branches so as to isolate them
|
||||
until they're stable and **tests have been written for the feature**.
|
||||
|
||||
The naming convention for feature branches is:
|
||||
|
||||
feature/{issue number}-{short hyphenated description}
|
||||
|
||||
// i.e.
|
||||
|
||||
feature/4045-rewriting-config-system
|
||||
|
||||
When a new feature is complete and tested it can be merged into its respective release branch using
|
||||
`git pull --no-ff`. The `--no-ff` switch is important as it tells git to always create a commit
|
||||
detailing what branch you're merging from. This makes it a lot easier to analyse a feature's history.
|
||||
|
||||
Here's a quick example:
|
||||
|
||||
> git status
|
||||
# On branch feature/4045-rewriting-everything
|
||||
|
||||
> git checkout 3.1.x
|
||||
# Switched to branch '3.1.x'
|
||||
|
||||
> git merge --no-ff feature/4045-rewriting-everything
|
||||
|
||||
**If a change you make intentionally breaks the api then please correct the relevant tests before pushing!**
|
||||
|
||||
### Bug fixing
|
||||
|
||||
If you're making a bugfix then before you start create a unit test which reproduces the bug,
|
||||
using the `@ticket` notation in the test to reference the bug's issue number
|
||||
(i.e. `@ticket 4045` for issue #4045).
|
||||
|
||||
If you run the test then the one you've just made should fail.
|
||||
|
||||
Once you've written the bugfix, run the tests again before you commit to make sure that the
|
||||
fix actually works,then commiti both the fix and the test.
|
||||
|
||||
There is no need to create separate branches for bugfixes, creating them in the main release
|
||||
branch is perfectly acceptable.
|
||||
|
||||
## Merging Changes from Remote Repositories
|
||||
|
||||
Now that you have a remote repository, you can pull changes in the remote "kohana" repository
|
||||
into your local repository:
|
||||
|
||||
> git pull kohana master
|
||||
|
||||
**Note:** Before you pull changes you should make sure that any modifications you've made locally
|
||||
have been committed.
|
||||
|
||||
Sometimes a commit you've made locally will conflict with one made in the "kohana" one.
|
||||
|
||||
There are a couple of scenarios where this might happen:
|
||||
|
||||
### The conflict is to do with a few unrelated commits and you want to keep changes made in both commits
|
||||
|
||||
You'll need to manually modify the files to resolve the conflict, see the "Resolving a merge"
|
||||
section [in the git-scm book](http://book.git-scm.com/3_basic_branching_and_merging.html) for more info
|
||||
|
||||
### You've fixed something locally which someone else has already done in the remote repo
|
||||
|
||||
The simplest way to fix this is to remove all the changes that you've made locally.
|
||||
|
||||
You can do this using
|
||||
|
||||
> git reset --hard kohana
|
||||
|
||||
### You've fixed something locally which someone else has already fixed but you also have separate commits you'd like to keep
|
||||
|
||||
If this is the case then you'll want to use a tool called rebase. First of all we need to
|
||||
get rid of the conflicts created due to the merge:
|
||||
|
||||
> git reset --hard HEAD
|
||||
|
||||
Then find the hash of the offending local commit and run:
|
||||
|
||||
> git rebase -i {offending commit hash}
|
||||
|
||||
i.e.
|
||||
|
||||
> git rebase -i 57d0b28
|
||||
|
||||
A text editor will open with a list of commits, delete the line containing the offending commit
|
||||
before saving the file & closing your editor.
|
||||
|
||||
Git will remove the commit and you can then pull/merge the remote changes.
|
@@ -1,24 +0,0 @@
|
||||
# Gestión de Errores/Excepciones
|
||||
|
||||
Kohana proporciona un gestor de errores y excepciones que transforma errores en excepciones usando la clase [ErrorException](http://php.net/errorexception) de PHP. Se muestran muchos detalles del error y del estado interno de la aplicación:
|
||||
|
||||
1. Clase de excepción
|
||||
2. Nivel del error
|
||||
3. Mensaje de error
|
||||
4. Fuente del error, con la línea del error resaltada
|
||||
5. Una [depuración hacia atrás](http://php.net/debug_backtrace) del flujo de ejecución
|
||||
6. Archivos incluídos, extensiones cargadas y variables globales
|
||||
|
||||
## Ejemplo
|
||||
|
||||
Haz clic en cualquiera de los enlaces para mostrar la información adicional:
|
||||
|
||||
<div>{{userguide/examples/error}}</div>
|
||||
|
||||
## Desactivando la Gestión de Errores/Excepciones
|
||||
|
||||
Si no quieres usar la gestión de errores interna, la puedes desactivar cuando se llama a [Kohana::init]:
|
||||
|
||||
~~~
|
||||
Kohana::init(array('errors' => FALSE));
|
||||
~~~
|
@@ -1,24 +0,0 @@
|
||||
# Depuración
|
||||
|
||||
Kohana incluye varias herramientas útiles que te ayudarán en la depuración de tus aplicaciones.
|
||||
|
||||
La más básica de ellas es [Kohana::debug]. Este método simple mostrará cualquier número de variables, similar a [var_export] o [print_r], pero usando HTML para una mejor visualización.
|
||||
|
||||
~~~
|
||||
// Mostrar el contenido de las variables $foo y $bar
|
||||
echo Kohana::debug($foo, $bar);
|
||||
~~~
|
||||
|
||||
Kohana también proporciona un método para mostrar el código fuente de una línea particular usando [Kohana::debug_source].
|
||||
|
||||
~~~
|
||||
// Mostrar esta línea del código
|
||||
echo Kohana::debug_source(__FILE__, __LINE__);
|
||||
~~~
|
||||
|
||||
Si quieres mostrar información sobre los archivos de tu aplicación sin exponer el directorio de instalación, puedes usar [Kohana::debug_path]:
|
||||
|
||||
~~~
|
||||
// Mostrar "APPPATH/cache" en vez de la ruta real
|
||||
echo Kohana::debug_file(APPPATH.'cache');
|
||||
~~~
|
@@ -1,22 +0,0 @@
|
||||
# Análisis de Rendimiento
|
||||
|
||||
Kohana proporciona una forma muy simple de mostrar estadísticas sobre tu aplicación:
|
||||
|
||||
1. Los métodos de [Kohana] más usados
|
||||
2. Peticiones
|
||||
3. Consultas a la Base de Datos ([Database])
|
||||
4. Tiempo de ejecución media de tu aplicación
|
||||
|
||||
## Ejemplo
|
||||
|
||||
En cualquier momento puedes mostrar o recolectar las estadísticas actuales del analizador ([profiler]):
|
||||
|
||||
~~~
|
||||
<div id="kohana-profiler">
|
||||
<?php echo View::factory('profiler/stats') ?>
|
||||
</div>
|
||||
~~~
|
||||
|
||||
## Vista previa
|
||||
|
||||
{{profiler/stats}}
|
@@ -1 +0,0 @@
|
||||
Esta página lista las características de Kohana v3
|
@@ -1,23 +0,0 @@
|
||||
1. **[Cómo Empezar](start)**
|
||||
- [Convenciones y Estilos](start.conventions)
|
||||
- [Instalación](start.installation)
|
||||
- [Configuración](start.configuration)
|
||||
- [Modelo Vista Controlador](start.mvc)
|
||||
- [Sistema de Archivos](start.filesystem)
|
||||
- [Autocarga](start.autoloading)
|
||||
- [Proceso de las Peticiones](start.flow)
|
||||
2. **[Tutoriales](tutorials)**
|
||||
- [Hola, Mundo](tutorials.helloworld)
|
||||
- [Rutas, URLs, y Enlaces](tutorials.urls)
|
||||
- [Bases de Datos](tutorials.databases)
|
||||
3. **[Seguridad](security)**
|
||||
- [XSS](security.xss)
|
||||
- [Validación](security.validation)
|
||||
- [Cookies](security.cookies)
|
||||
- [Bases de Datos](security.database)
|
||||
4. **[Depuración](debugging)**
|
||||
- [Gestión de Errores](debugging.errors)
|
||||
- [Análisis de Rendimiento](debugging.profiling)
|
||||
5. **[Actualizando](upgrading)**
|
||||
- [Desde 2.3](upgrading.23)
|
||||
6. **[Explorar API](api)**
|
@@ -1,3 +0,0 @@
|
||||
# Seguridad en las Cookies
|
||||
|
||||
[!!] inacabado
|
@@ -1,3 +0,0 @@
|
||||
# Seguridad en las Bases de Datos
|
||||
|
||||
[!!] inacabado
|
@@ -1,3 +0,0 @@
|
||||
# Seguridad
|
||||
|
||||
[!!] inacabado
|
@@ -1,3 +0,0 @@
|
||||
# Validación
|
||||
|
||||
[!!] inacabado
|
@@ -1,15 +0,0 @@
|
||||
# Seguridad en Cross-Site Scripting (XSS)
|
||||
|
||||
El primer paso para prevenir los ataques de [XSS](http://es.wikipedia.org/wiki/Cross-site_scripting) es saber cuando necesitas protegerte a ti mismo. El XSS sólo puede llevarse a cabo cuando se muestra dentro de contenido HTML, muchas veces vía una entrada de formulario o cuando mostramos datos de resultados de la base de datos. Cualquier variable global que contenga información desde el cliente puede ser contaminada. Esto incluye los datos de las variables $_GET, $_POST, y $_COOKIE.
|
||||
|
||||
## Prevención
|
||||
|
||||
Hay unas pocas reglas simples para proteger el HTML tu aplicación del XSS. La primera es usar el método [Security::xss] para limpiar cualquier dato de entrada que venga de una variable global. Si no necesitas HTML en una variable, usa [strip_tags](http://php.net/strip_tags) para remover todas las etiquetas HTML innecesarias del contenido.
|
||||
|
||||
[!!] Si quieres permitir a los usuarios enviar HTML en tu aplicación, es altamente recomendable usar una herramienta de limpieza de HTML como [HTML Purifier](http://htmlpurifier.org/) o [HTML Tidy](http://php.net/tidy).
|
||||
|
||||
La segunda es que siempre debemos escapar los datos cuando se insertan en el HTML. La clase [HTML] proporciona generadores para muchas de las principales etiquetas, incluyendo scripts, hojas de estilo, enlaces, imágenes, y email (mailto). Cualquier contenido no verificado debería escaparse usando [HTML::chars].
|
||||
|
||||
## Referencias
|
||||
|
||||
* [OWASP XSS Cheat Sheet](http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)
|
@@ -1,17 +0,0 @@
|
||||
# Autocarga
|
||||
|
||||
Kohana aprovecha la habilidad de PHP [autocarga](http://docs.php.net/manual/es/language.oop5.autoload.php). Esto elimina la necesidad de llamar a [include](http://php.net/include) o [require](http://php.net/require) antes de usar una clase.
|
||||
|
||||
Las clases son cargadas usando el método [Kohana::auto_load], el cual hace una simple conversión del nombre de la clase al nombre del archivo:
|
||||
|
||||
1. Las clases son colocadas en el directorio `classes/` del [sistema de archivos](start.filesystem)
|
||||
2. Cualquier caracter de barra baja es convertido a barra invertida
|
||||
2. El nombre de archivo es todo en minúsculas
|
||||
|
||||
Cuando llamamos a una clase que no ha sido cargada (por ejemplo: `Session_Cookie`), Kohana buscará en el sistema de archivos usando [Kohana::find_file] un archivo llamado `classes/session/cookie.php`.
|
||||
|
||||
## Autocargadores personalizados
|
||||
|
||||
[!!] El autocargador por defecto es activado en `application/bootstrap.php`.
|
||||
|
||||
Los cargadores de clases adicionales pueden ser añadidos usando [spl_autoload_register](http://php.net/spl_autoload_register).
|
@@ -1,94 +0,0 @@
|
||||
# Configuración General
|
||||
|
||||
[!!] por hacer, descripción de los beneficios de las propiedades estáticas para la configuración
|
||||
|
||||
## Configuración Principal
|
||||
|
||||
La primera tarea de configuración de cualquier nueva instalación de Kohana es cambiar la configuración de inicio [Kohana::init] en `application/bootstrap.php`. Los datos configurables son:
|
||||
|
||||
`boolean` errors
|
||||
: ¿Usar el gestor de errores y excepciones interno? (Por defecto `TRUE`) Establecer a `FALSE` para desactivar el gestor de errores y excepciones de Kohana.
|
||||
|
||||
`boolean` profile
|
||||
: ¿Hacer análisis de rendimiento interno? (Por defecto `TRUE`) Establecer a `FALSE` para desactivarlo. En sitios en producción debería estar desactivado para un mejor rendimiento.
|
||||
|
||||
`boolean` caching
|
||||
: ¿Cachear la localización de los archivos entre peticiones? (Por defecto `FALSE`) Establecer a `TRUE` para cachear la
|
||||
ruta absoluta de los archivos. Esto aumenta dramáticamente la velocidad de [Kohana::find_file] y puede muchas veces
|
||||
tener un impacto dramático en el desempeño. Sólo activar en sitios en producción o para su prueba.
|
||||
|
||||
`string` charset
|
||||
: Juego de caracteres usado para todas las entradas y salidas. (Por defecto `"utf-8"`) Debería ser un juego de caracteres que sea soportado por [htmlspecialchars](http://php.net/htmlspecialchars) e [iconv](http://php.net/iconv).
|
||||
|
||||
`string` base_url
|
||||
: URL base de la aplicación. (Por defecto `"/"`) Puede ser una URL completa o parcial. Por ejemplo "http://example.com/kohana/" o sólo "/kohana/" funcionan ambas por igual.
|
||||
|
||||
`string` index_file
|
||||
: El archivo PHP que inicia la aplicación. (Por defecto `"index.php"`) Establecer a `FALSE` cuando elimines el archivo index con la reescritura de la URL (mod_rewrite y similares).
|
||||
|
||||
`string` cache_dir
|
||||
: Directorio de la Cache. (Por defecto `"application/cache"`) Debe apuntar a un directorio **escribible**.
|
||||
|
||||
## Configuración de las Cookies
|
||||
|
||||
Hay varias propiedades estáticas en la clase [Cookie] que deberían establecerse, especialmente en sitios en producción.
|
||||
|
||||
`string` salt
|
||||
: Cadena que es usada para crear [cookies cifradas](security.cookies)
|
||||
|
||||
`integer` expiration
|
||||
: Tiempo de expiración en segundos
|
||||
|
||||
`string` path
|
||||
: Ruta URL para restringir dónde pueden ser accedidas las cookies
|
||||
|
||||
`string` domain
|
||||
: Dominio URL para restringir dónde pueden ser accedidas las cookies
|
||||
|
||||
`boolean` secure
|
||||
: Permitir que las cookies sólo sean accedidas por HTTPS
|
||||
|
||||
`boolean` httponly
|
||||
: Permitir que las cookies sólo sean accedidas por HTTP (también desactiva el acceso por Javascript)
|
||||
|
||||
# Archivos de Configuración
|
||||
|
||||
La configuración se establece en archivos PHP planos, del estilo de:
|
||||
|
||||
~~~
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'setting' => 'value',
|
||||
'options' => array(
|
||||
'foo' => 'bar',
|
||||
),
|
||||
);
|
||||
~~~
|
||||
|
||||
Si el archivo de configuración anterior se llamaba `myconf.php`, puedes acceder a él usando:
|
||||
|
||||
~~~
|
||||
$config = Kohana::config('myconf');
|
||||
$options = $config['options'];
|
||||
~~~
|
||||
|
||||
[Kohana::config] también proporciona una forma corta para acceder a valores individuales del array de configuración usando "rutas con puntos".
|
||||
|
||||
Obtener el array "options":
|
||||
|
||||
~~~
|
||||
$options = Kohana::config('myconf.options');
|
||||
~~~
|
||||
|
||||
Obtener el valor de "foo" del array "options":
|
||||
|
||||
~~~
|
||||
$foo = Kohana::config('myconf.options.foo');
|
||||
~~~
|
||||
|
||||
Los arrays de configuración también pueden ser accedidos como objetos, si prefieres ese método:
|
||||
|
||||
~~~
|
||||
$options = Kohana::config('myconf')->options;
|
||||
~~~
|
@@ -1,26 +0,0 @@
|
||||
# Convenciones
|
||||
|
||||
## Nombre de las clases y la localización del archivo
|
||||
|
||||
Los nombres de las clases en Kohana siguen una forma estricta para facilitar la [autocarga](start.autoloading).
|
||||
|
||||
Los nombres de las clases deben tener la primera letra mayúscula con barra baja para separar palabras. Las barras bajas son significativas ya que directamente reflejan la localización del archivo en el sistema de archivos.
|
||||
|
||||
Clase Archivo
|
||||
|
||||
Controller_Template classes/controller/template.php
|
||||
Model_User classes/model/user.php
|
||||
Model_Auth_User classes/model/auth/user.php
|
||||
Auth classes/auth.php
|
||||
|
||||
Los nombres de las clases del estilo de PrimeraMayuscula no deberían ser usadas.
|
||||
|
||||
Todos los nombres de los archivos de las clases y los directorios van en minúscula.
|
||||
|
||||
Todas las clases deben ir en el directorio `classes`. Esto debe ser así en cualquier nivel del [sistema de archivos en cascada](start.filesystem).
|
||||
|
||||
Kohana 3 no diferencia entre *tipos* de clases de la misma forma en que Kohana 2.x y otros frameworks lo hacen. No hay diferencia entre una clase tipo 'helper' o una de tipo 'library' - en Kohana 3 cualquier clase puede implementar cualquier interface que necesite o ser estática totalmente (estilo helper), o instanciable, o una mezcla (por ejemplo singleton).
|
||||
|
||||
## Estilo de Código
|
||||
|
||||
Se recomienda seguir el estilo de código usado en Kohana. Usamos el [estilo BSD/Allman](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style). ([Descripción más pormenorizada](http://dev.kohanaphp.com/wiki/kohana2/CodingStyle) del estilo de código preferido por Kohana)
|
@@ -1,13 +0,0 @@
|
||||
# Sistema de Archivos en Cascada
|
||||
|
||||
El sistema de archivos de Kohana se compone de una única estructura de directorios que es repetida a lo largo de todos los directorios, lo que llamamos la ruta de inclusión, que sigue el orden:
|
||||
|
||||
1. application
|
||||
2. modules, según el orden en que sean añadidos
|
||||
3. system
|
||||
|
||||
Los archivos que se encuentran en directorios superiores en la lista de las rutas de inclusión tienen preferencia sobre los archivos del mismo nombre pero que están más abajo, lo cual hace posible sobrecargar cualquier archivo colocando otro archivo con el mismo nombre en un directorio superior:
|
||||
|
||||

|
||||
|
||||
Si tiene un archivo de Vista llamado layout.php en los directorios application/views y system/views, será devuelto el que se encuentra bajo application cuando se busque por layout.php ya que se encuentra más arriba en la lista de inclusión ordenada. Si elimina ese archivo de application/views, el que se encuentra en system/views será devuelto cuando lo busquemos.
|
@@ -1,21 +0,0 @@
|
||||
# Proceso de las Peticiones
|
||||
|
||||
Cada aplicación sigue el siguiente proceso:
|
||||
|
||||
1. La aplicación empieza desde el archivo `index.php`
|
||||
2. Incluye `APPPATH/bootstrap.php`
|
||||
3. bootstrap.php llama a [Kohana::modules] con la lista de módulos usados
|
||||
1. Genera una matriz con las rutas para el sistema de archivos en cascada
|
||||
2. Comprueba cada módulo para ver si tiene un init.php, y si lo tiene, lo carga
|
||||
* Cada init.php puede definir una serie de rutas a usar, que son cargadas cuando el archivo init.php es incluido
|
||||
4. [Request::instance] es llamada para procesar la petición
|
||||
1. Comprueba cada ruta hasta que se encuentra una coincidencia
|
||||
2. Carga el controlador y le pasa la petición
|
||||
3. Llama al método [Controller::before]
|
||||
4. Llama a la acción del controlador
|
||||
5. Llama al método [Controller::after]
|
||||
5. Muestra la respuesta a la petición ([Request])
|
||||
|
||||
La acción del controlador puede ser cambiada por el método [Controller::before] en base a los parámetros de la petición.
|
||||
|
||||
[!!] inacabado
|
@@ -1,19 +0,0 @@
|
||||
# Instalación
|
||||
|
||||
1. Descarga la última versión **estable** de la [web de Kohana](http://kohanaphp.com/)
|
||||
2. Descomprime el archivo descargado para crear un directorio `kohana`
|
||||
3. Sube el contenido de esta carpeta a tu servidor
|
||||
4. Abre `application/bootstrap.php` y haz los cambios siguientes:
|
||||
- Establece la [zona horaria](http://php.net/timezones) por defecto para tu aplicación
|
||||
- Establece `base_url` en la llamada a [Kohana::init] para reflejar la localización de la carpeta de kohana en tu servidor
|
||||
6. Comprueba que los directorios `application/cache` y `application/logs` tienen permisos de escritura para todos con `chmod application/{cache,logs} 0777`
|
||||
7. Comprueba tu instalación abriendo la url que has establecido en `base_url` en tu navegador favorito
|
||||
|
||||
[!!] Dependiendo de tu plataforma, los subdirectorios de la instalación podrían haber perdido sus permisos debido a la descompresión zip. Para cambiarle los permisos a todos ejecutar `find . -type d -exec chmod 0755 {} \;` desde la raíz de la instalación de Kohana.
|
||||
|
||||
Deberías ver la página de instalación. Si reporta algún error, debes corregirlo antes de continuar.
|
||||
|
||||

|
||||
|
||||
Una vez que la página de instalación reporta que tu entorno está correcto, debes renombrar o borrar el archivo `install.php` del directorio raíz. Entonces deberías ver la página de bienvenida de Kohana (el texto `hello, world!`).
|
||||
|
@@ -1,11 +0,0 @@
|
||||
# ¿Qué es Kohana?
|
||||
|
||||
Kohana es un [framework web](http://es.wikipedia.org/wiki/Framework_para_aplicaciones_web) [MVC](http://es.wikipedia.org/wiki/Modelo_Vista_Controlador "Modelo Vista Controlador") de código abierto y [orientado a objetos](http://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos) realizado para [PHP5](http://docs.php.net/manual/es/intro-whatis.php "Preprocesador de Hipertexto PHP") por un equipo de voluntarios, y destaca por ser rápido, seguro y ligero.
|
||||
|
||||
[!!] Kohana está licenciado bajo una [licencia BSD](http://kohanaphp.com/license), así que puede legalmente usarlo para cualquier tipo de proyecto de código abierto, comercial, o personal.
|
||||
|
||||
## ¿Qué hace potente a Kohana?
|
||||
|
||||
Cualquier cosa puede ser extendida usando el [sistema de archivos](start.filesystem) de diseño único, poco o nada hay que cambiar en la [configuración](start.configuration), la [gestión de errores](debugging.errors) ayuda a localizar los errores de código rápidamente, y la [depuración](debugging) y [profiling](debugging.profiling) informan sobre la aplicación en sí.
|
||||
|
||||
Para que sus aplicaciones sean más seguras, se incluyen herramientas para [eliminar el XSS](security.xss), [validar de los datos de entrada](security.validation), [cookies](security.cookies), [formularios](security.forms) y [HTML](security.html). La capa de la [base de datos](security.database) proporciona protección de [inyección de código SQL](http://es.wikipedia.org/wiki/Inyecci%C3%B3n_SQL). Por supuesto, todo el código oficial ha sido cuidadosamente escrito y revisado pensando en la seguridad.
|
@@ -1,5 +0,0 @@
|
||||
# Modelo Vista Controlador
|
||||
|
||||
Modelo Vista Controlador (o MVC) es un patrón de diseño popular que separa el origen de tus datos (Modelo) de la presentación/plantillas (Vista) y la lógica de la petición (Controlador).
|
||||
|
||||
Esto hace mucho más fácil desarrollar aplicaciones y el sistema es diseñado para maximizar la reutilización de código, lo que se traduce en que ¡no tendrás que escribir mucho!
|
@@ -1,3 +0,0 @@
|
||||
# Bases de Datos
|
||||
|
||||
[!!] inacabado
|
@@ -1,106 +0,0 @@
|
||||
# Hola, Mundo
|
||||
|
||||
Muchos frameworks proporcionan algún ejemplo de tipo hola mundo, de forma que ¡sería muy grosero por nuestra parte romper esa tradición!
|
||||
|
||||
Empezaremos creando un hola mundo muy básico, y luego lo ampliaremos para seguir con los principios del patrón MVC.
|
||||
|
||||
## Lo esencial
|
||||
|
||||
En primer lugar, tenemos que crear un controlador que kohana usará para manejar la petición
|
||||
|
||||
Crea el archivo `application/classes/controller/hello.php` en tu directorio **application** y copia dentro el siguiente código:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No Direct Script Access');
|
||||
|
||||
Class Controller_Hello extends Controller
|
||||
{
|
||||
function action_index()
|
||||
{
|
||||
echo 'hello, world!';
|
||||
}
|
||||
}
|
||||
|
||||
Veamos lo que ocurre:
|
||||
|
||||
`<?php defined('SYSPATH') OR die('No Direct Script Access');`
|
||||
: Deberías reconocer la primera etiqueta como la etiqueta de apertura de php (en caso contrario probablemente deberías [aprender php](http://php.net)). Lo que sigue es una pequeña comprobación que se asegura que este archivo está siendo incluído por kohana. Esto impide que se acceda directamente a este archivo desde la url.
|
||||
|
||||
`Class Controller_Hello extends Controller`
|
||||
: Esta línea declara nuestro controlador, cada clase de tipo controlador tiene que llevar el prefijo `Controller_` y una barra baja delimita la ruta a la carpeta donde se encuentra el controlador (mirar [Convenciones y Estilos](start.conventions) para más información). Cada controlador debe también extender la clase básica `Controller` la cual proporciona una estrcutura estándar para los controladores.
|
||||
|
||||
|
||||
`function action_index()`
|
||||
: Define la acción "index" de nuestro controlador. Kohana intentará llamar a esta acción si el usuario no ha especificado una. (mirar [Rutas, URLs y Enlaces](tutorials.urls))
|
||||
|
||||
`echo 'hello, world!';`
|
||||
: ¡Y esta es la línea que muestra la famosa frase!
|
||||
|
||||
Ahora si abres el navegador y vas a http://your/kohana/website/index.php/hello podrás ver algo como esto:
|
||||
|
||||

|
||||
|
||||
## Eso ha sido bueno, pero podemos hacerlo mejor
|
||||
|
||||
Lo que hicimos en la sección anterior fue un buen ejemplo de lo fácil que es crear una aplicación *extremadamente* básica en kohana (de hecho, ¡es tan básica que no se debe hacer de nuevo!)
|
||||
|
||||
Si alguna vez has oído hablar del patrón MVC probablemente te habrás dado cuenta que imprimir contenido al navegador con `echo` en un controlador va totalmente en contra de los principios de este patrón de diseño.
|
||||
|
||||
La forma correcta de hacerlo con un framework MVC es usar _vistas_ para manejar la presentación de tu aplicación, y dejar hacer al controlador lo que mejor hace - ¡Controlar el flujo de la petición!
|
||||
|
||||
Cambiamos ligeramente el controlador original -
|
||||
|
||||
<?php defined('SYSPATH') OR die('No Direct Script Access');
|
||||
|
||||
Class Controller_Hello extends Controller_Template
|
||||
{
|
||||
public $template = 'site';
|
||||
|
||||
function action_index()
|
||||
{
|
||||
$this->template->message = 'hello, world!';
|
||||
}
|
||||
}
|
||||
|
||||
`extends Controller_Template`
|
||||
: Ahora estamos extendiendo el controlador de plantillas, el cual es más conveniente para usar vistas en nuestro controlador.
|
||||
|
||||
`public $template = 'site';`
|
||||
: El controlador de plantillas necesita conocer que plantilla queremos usar. Automáticamente cargará la vista definida en esta variable y le asignará el objeto de tipo vista.
|
||||
|
||||
`$this->template->message = 'hello, world!';`
|
||||
: `$this->template` es una referencia al objeto tipo vista de nuestra plantilla del sitio. Lo que estamos haciendo es asignar a una variable de la vista llamada "message" el valor de "hello, world!"
|
||||
|
||||
Ahora intentamos ejecutar nuestro código...
|
||||
|
||||
<div>{{userguide/examples/hello_world_error}}</div>
|
||||
|
||||
Por alguna razón kohana lanza una excepción y no muestra nuestro sorprendente mensaje.
|
||||
|
||||
Si miramos dentro del mensaje de error podemos ver que la librería View no es capaz de encontrar la plantilla de nuestro sitio, probablemente porque no ha sido creada todavía - ¡*ouch*!
|
||||
|
||||
Vamos y creamos el archivo de vista `application/views/site.php` para nuestro mensaje -
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>We've got a message for you!</title>
|
||||
<style type="text/css">
|
||||
body {font-family: Georgia;}
|
||||
h1 {font-style: italic;}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1><?php echo $message; ?></h1>
|
||||
<p>We just wanted to say it! :)</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Si luego refrescamos la página podremos ver el fruto de nuestra labor -
|
||||
|
||||

|
||||
|
||||
## En resumen
|
||||
|
||||
En este tutorial has aprendido cómo crear un controlador y usar una vista para separar la lógica de la presentación.
|
||||
|
||||
Esto es obviamente una introducción muy básica al trabajo con kohana y no entra de lleno en el potencial que tienes cuando desarrollas aplicaciones con él.
|
@@ -1,7 +0,0 @@
|
||||
# Tutoriales
|
||||
|
||||
[!!] inacabado
|
||||
|
||||
- [Hola, Mundo](tutorials.helloworld)
|
||||
- [Rutas, URLs, y Enlaces](tutorials.urls)
|
||||
- [Bases de Datos](tutorials.databases)
|
@@ -1,3 +0,0 @@
|
||||
# Rutas, URLs, y Enlaces
|
||||
|
||||
[!!] inacabado
|
@@ -1,5 +0,0 @@
|
||||
# Actualizando
|
||||
|
||||
Obviamente te gustaría actualizar tu código desde la versión 2 a la 3, y para hacer esta transición más fácil hemos recopilado algunos de los principales cambios desde la versión
|
||||
|
||||
* [Kohana 2.3](upgrading.23)
|
@@ -1 +0,0 @@
|
||||
This page lists the features of Kohana v3
|
@@ -1,17 +0,0 @@
|
||||
# Auto-chargement de classes
|
||||
|
||||
Kohana tire partie de la fonctionnalité PHP d'[auto-chargement de classes](http://php.net/manual/fr/language.oop5.autoload.php) permettant de s'affranchir des inclusions manuelles avec [include](http://de.php.net/manual/fr/function.include.php) ou [require](http://de.php.net/manual/fr/function.require.php).
|
||||
|
||||
Les classes sont chargées via la méthode [Kohana::auto_load], qui à partir du nom d'une classe, retrouve le fichier associé:
|
||||
|
||||
1. Les classes sont placées dans le répertoire `classes/` de l'[arborescence de fichiers](about.filesystem)
|
||||
2. Les caractères underscore '_' sont convertis en slashes '/'
|
||||
2. Les noms de fichier doivent être en minuscule
|
||||
|
||||
Lors de l'appel à une classe non chargée (eg: `Session_Cookie`), Kohana recherchera dans son arboresence via la méthode [Kohana::find_file] le fichier `classes/session/cookie.php`.
|
||||
|
||||
## Auto-chargement tiers
|
||||
|
||||
[!!] Le mécanisme par défaut d'auto-chargement de classes est défini dans le fichier `application/bootstrap.php`.
|
||||
|
||||
Des mécanismes d'auto-chargement supplémentaires peuvent être ajoutés en utilisant [spl_autoload_register](http://php.net/spl_autoload_register).
|
@@ -1,95 +0,0 @@
|
||||
# Configuration Générale
|
||||
|
||||
[!!] todo, description of benefits of static properties for configuration
|
||||
|
||||
## Configuration du noyau
|
||||
|
||||
La toute première configuration à modifier lors d'une installation de kohana est de changer les paramètres d'initlalisation [Kohana::init] dans le fichier `application/bootstrap.php`. Ces paramètres sont:
|
||||
|
||||
`boolean` errors
|
||||
: Utilisation de la gestion des erreurs et des exceptions? (Défaut `TRUE`) Affecter à `FALSE` pour désactiver
|
||||
la gestion des erreurs et exceptions.
|
||||
|
||||
`boolean` profile
|
||||
: Activer le benchmarking interne? (Défault `TRUE`) Affecter à `FALSE` pour désactiver le benchmarking interne.
|
||||
A desactiver en production pour obtenir de meilleures performances.
|
||||
|
||||
`boolean` caching
|
||||
: Mettre en cache les chemins des fichiers entre les requêtes? (Défault `FALSE`) Affecter à `TRUE` pour mettre en cache
|
||||
les chemins absolus. Ceci peut améliorer drastiquement les performances de la méthode [Kohana::find_file].
|
||||
|
||||
`string` charset
|
||||
: Jeu de caractères à utiliser pour toutes les entrées et sorties. (Défault `"utf-8"`) Affecter un jeu de caractères supporté aussi bien par [htmlspecialchars](http://fr.php.net/htmlspecialchars) que [iconv](http://fr.php.net/iconv).
|
||||
|
||||
`string` base_url
|
||||
: URL racine de l'application. (Défault `"/"`) Peut être une URL complète ou partielle. Par exemple "http://example.com/kohana/" ou "/kohana/" fonctionneraient.
|
||||
|
||||
`string` index_file
|
||||
: Le fichier PHP qui démarre l'application. (Défault `"index.php"`) Affecter à `FALSE` pour enlever le fichier index de l'URL en utilisant l'URL Rewriting.
|
||||
|
||||
`string` cache_dir
|
||||
: Répertoire de stockage du cache. (Défault `"application/cache"`) Doit pointer vers un répertoire **inscriptible**.
|
||||
|
||||
## Paramètres des Cookies
|
||||
|
||||
Il y a plusieurs propriétés statiques dans la classe [Cookie] qui doivent être paramétrées, particuliérement sur les sites en production.
|
||||
|
||||
`string` salt
|
||||
: La chaîne d'aléa (salt) unique utilisée pour [signer les cookies](security.cookies)
|
||||
|
||||
`integer` expiration
|
||||
: La durée d'expiration par défaut
|
||||
|
||||
`string` path
|
||||
: Restreindre l'accès aux cookies par rapport au chemin spécifié
|
||||
|
||||
`string` domain
|
||||
: Restreindre l'accès aux cookies par rapport au domaine spécifié
|
||||
|
||||
`boolean` secure
|
||||
: N'autoriser les cookies qu'en HTTPS
|
||||
|
||||
`boolean` httponly
|
||||
: N'autorise l'accès aux cookies que via HTTP (désactive aussi l'accès javascript)
|
||||
|
||||
# Fichiers de configuration
|
||||
|
||||
La configuration de Kohana est faite dans des fichiers à plat PHP, qui ressemblent à l'exemple ci-dessous:
|
||||
|
||||
~~~
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'setting' => 'value',
|
||||
'options' => array(
|
||||
'foo' => 'bar',
|
||||
),
|
||||
);
|
||||
~~~
|
||||
|
||||
Supposons que le fichier ci-dessus soit appelé `myconf.php`, il est alors possible d'y accèder de la manière suivante:
|
||||
|
||||
~~~
|
||||
$config = Kohana::config('myconf');
|
||||
$options = $config['options'];
|
||||
~~~
|
||||
|
||||
[Kohana::config] fournit aussi un raccourci pour accèder à des clés spécifiques des tableaux de configuration en utilisant des chemins spérarés par le caractère point.
|
||||
|
||||
Récupérer le tableau "options":
|
||||
|
||||
~~~
|
||||
$options = Kohana::config('myconf.options');
|
||||
~~~
|
||||
|
||||
Récupérer la valeur de la clé "foo" du tableau "options":
|
||||
|
||||
~~~
|
||||
$foo = Kohana::config('myconf.options.foo');
|
||||
~~~
|
||||
|
||||
Les tableaux de configuration peuvent aussi être parcourus comme des objets comme suit:
|
||||
|
||||
~~~
|
||||
$options = Kohana::config('myconf')->options;
|
||||
~~~
|
@@ -1,26 +0,0 @@
|
||||
# Conventions et style de codage
|
||||
|
||||
## Nom de classe et emplacement des fichiers
|
||||
|
||||
Les noms de classe dans Kohana suivent des règles strictes pour faciliter l'[auto-chargement de classes](about.autoloading).
|
||||
|
||||
Ils doivent avoir la première lettre en majuscule, et les mots doivent être séparés par des underscores. Les underscores sont très importants car ils déterminent le chemin d'accès au fichier.
|
||||
|
||||
Nom de classe | Chemin
|
||||
----------------------|-------------------------------
|
||||
Controller_Template | classes/controller/template.php
|
||||
Model_User | classes/model/user.php
|
||||
Database | classes/database.php
|
||||
Database_Query | classes/database/query.php
|
||||
|
||||
Les noms de classe ne doivent pas utiliser de syntaxe CamelCase sauf si vous ne souhaitez pas créer un nouveau niveau de répertoire.
|
||||
|
||||
Tous les noms de fichier et répertoire sont en minuscule.
|
||||
|
||||
Toutes les classes doivent être dans le répertoire `classes`. Elles peuvent néanmoins être sur plusieurs niveaux de répertoire de l'[arborescence](about.filesystem).
|
||||
|
||||
Kohana 3 ne différencie pas les *types* de classe comme le fait Kohana 2.x. Il n'y a pas de distinction entre une classe 'helper' ou une 'librairie' – avec Kohana 3 toute classe peut implémenter l'interface que vous souhaitez, qu'elle soit statique (helper), instanciable, ou mixte (e.g. singleton).
|
||||
|
||||
## Style de codage
|
||||
|
||||
Il est vivement conseillé de suivre les [styles de codage](http://dev.kohanaphp.com/wiki/kohana2/CodingStyle) de Kohana c'est-à-dire le [style BSD/Allman](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) pour les accolades, entre autres choses.
|
@@ -1,13 +0,0 @@
|
||||
# Arborescence de fichiers en cascade
|
||||
|
||||
L'arborescence de fichiers de Kohana est construite autour d'une structure de répertoires unique qui est dupliquée dans tous les répertoires formant ce que l'on appelle l'"include path". Cette structure est composée des répertoires suivants et dans cet ordre:
|
||||
|
||||
1. application
|
||||
2. modules, dans l'ordre dans lequel ils ont été ajoutés
|
||||
3. system
|
||||
|
||||
Les fichiers qui sont dans les répertoires les plus haut de l'"include path" sont prioritaires par rapport aux fichiers de même noms dans des répertoires plus bas. Cela rend possible la surcharge de nimporte quel fichier en plaçant un fichier de même nom dans un répertoire de niveau supérieur:
|
||||
|
||||

|
||||
|
||||
Par exemple, si vous avez un fichier appelé layout.php dans les répertoires application/views et system/views, alors celui contenu dans le répertoire application sera retourné lors de l'appel à layout.php du fait qu'il est plus haut dans l'"include path". Si vous supprimez le fichier de application/views, alors c'est celui contenu dans system/views qui sera alors retourné.
|
@@ -1,21 +0,0 @@
|
||||
# Processus de traitement des requêtes
|
||||
|
||||
Toutes les applications suivent le même processus:
|
||||
|
||||
1. L'application commence depuis `index.php`
|
||||
2. Inclut `APPPATH/bootstrap.php`
|
||||
3. L'initialisation (bootstrap) appelle [Kohana::modules] avec une liste de modules à utiliser
|
||||
1. Génére un tableau de chemins utilisés par l'arborescence en cascade
|
||||
2. Vérifie la présence du fichier init.php dans chaque module. Si il existe
|
||||
* Chaque fichier init.php peut définir un ensemble de routes à utiliser, elles sont chargées lorsque le fichier init.php est inclut
|
||||
4. [Request::instance] est appelé pour traiter la requête
|
||||
1. Vérifie toutes les routes jusqu'à ce que l'une d'entres elles concorde
|
||||
2. Charge le controleur et lui transmet la requête
|
||||
3. Appelle la méthode [Controller::before]
|
||||
4. Appelle l'action du controleur
|
||||
5. Appelle la méthode [Controller::after]
|
||||
5. Affiche la réponse à la requête
|
||||
|
||||
L'action du controleur peut etre changée suivant ses paramètres de la par [Controller::before].
|
||||
|
||||
[!!] Stub
|
@@ -1,20 +0,0 @@
|
||||
# Installation
|
||||
|
||||
1. Téléchargez la dernière version **stable** depuis [le site web Kohana](http://kohanaphp.com/)
|
||||
2. Dézippez l'archive téléchargée pour créer le répertoire `kohana`
|
||||
3. Uploadez le contenu de ce répertoire sur votre serveur web
|
||||
4. Ouvrez `application/bootstrap.php` et effectuez les changements suivants:
|
||||
- Affecter la [timezone](http://php.net/timezones) par défaut de votre application
|
||||
- Affecter `base_url` dans l'appel à [Kohana::init] afin de faire comprendre à votre serveur ou est situé le répertoire kohana uploadé à l'étape précédente
|
||||
6. Vérifiez que les répertoires `application/cache` et `application/logs` sont inscriptibles en tapant la commande `chmod application/{cache,logs} 0777` (Linux).
|
||||
7. Testez votre installation en tapant l'URL que vous avez spécifiée dans `base_url` dans votre navigateur préféré
|
||||
|
||||
[!!] Suivant votre plateforme, l'extraction de l'archive peut avoir changé les permissions sur les sous répertoires. Rétablissez-les avec la commande suivante: `find . -type d -exec chmod 0755 {} \;` depuis la racine de votre installation Kohana.
|
||||
|
||||
Vous devriez alors voir la page d'installation contenant un rapport d'installation. Si une erreur est affichée, vous devez la corriger pour pouvoir continuer.
|
||||
|
||||

|
||||
|
||||
Une fois que votre rapport d'installation vous informe que votre environnement est correctement configuré, vous devez soit renommer, soit supprimer le fichier `install.php`. Vous devriez alors voir apparaitre la page de bienvenue de Kohana:
|
||||
|
||||

|
@@ -1,11 +0,0 @@
|
||||
# Kohana... Kesako?
|
||||
|
||||
Kohana est un [framework web](http://wikipedia.org/wiki/Web_Framework) [PHP5](http://php.net/manual/intro-whatis "PHP Hypertext Preprocessor") open source, [orienté objet](http://wikipedia.org/wiki/Object-Oriented_Programming), adoptant le design pattern [MVC](http://wikipedia.org/wiki/Model–View–Controller "Model View Controller"). Il vise à être rapide, sécurisé et léger.
|
||||
|
||||
[!!] Kohana est licencié sous [licence BSD](http://kohanaphp.com/license), donc vous pouvez légalement l'utiliser pour tout projet open source, commercial ou personnel.
|
||||
|
||||
## Pourquoi Kohana est-il différent?
|
||||
|
||||
Tout peut être surchargé et étendu grâce à son [arborescence de fichiers en cascade](about.filesystem), il y a très peu de [configuration](about.configuration) nécessaire, la [gestion des erreurs](debugging.errors) aide à la localisation rapide de la source des erreurs, et enfin le [debugging](debugging) et le [profiling](debugging.profiling) vous fournissent les statistiques et informations nécessaires sur votre application.
|
||||
|
||||
Pour vous aider dans la sécurisation de votre application, Kohana fournit des protections contre les attaques [XSS](security.xss), des méthodes de [filtrage et de validation des données d'entrées](security.validation), de [signature des cookies](security.cookies), de sécurisation de vos [formulaires](security.forms) et de génération [HTML](security.html). La couche [base de données](security.database) fournit des protections contre l'[injection SQL](http://wikipedia.org/wiki/SQL_Injection). Et bien évidemment, le code officiel est écrit et revu consciencieusement.
|
@@ -1,5 +0,0 @@
|
||||
# Modèle Vue Controleur
|
||||
|
||||
Modèle Vue Controleur (ou MVC) est un design pattern populaire visant à séparer les sources de données (Modèle) de la présentation (Vue) et de l'enchainement logique de traitement de la requête (Controleur).
|
||||
|
||||
Il rend plus facile le développement d'application modulaires et réutilisables.
|
@@ -1,290 +0,0 @@
|
||||
# Mise à jour depuis 2.x
|
||||
|
||||
Kohana v3 fonctionne très différemment de Kohana 2.x, néanmoins vous trouverez ci-dessous une liste d'astuces qui pourront vous aider dans votre tâche de mise à jour.
|
||||
|
||||
## Conventions de nommage
|
||||
|
||||
La série 2.x différentie les 'types' de classes (i.e. controleur, modele etc.) en utilisant des suffixes. Dans la série 3.0, cette approche a été abandonnée au profit des conventions du framework Zend c'est-à-dire que les noms de classe sont les chemins vers les classes elles-mêmes. Les répertoires du chemin sont séparés par le caractère underscore au lieu du slashe (i.e. `/some/class/file.php` devient `Some_Class_File`).
|
||||
|
||||
Pour plus d'informations consultez la documentatation sur les [conventions de nommage](start.conventions).
|
||||
|
||||
## Librairie Input
|
||||
|
||||
La librairie Input a été supprimée en faveur de l'utilisation directe des variables `$_GET` et `$_POST`.
|
||||
|
||||
### Protection XSS
|
||||
|
||||
Si vous avez besoin de nettoyer des données contre des attaques XSS, vous pouvez utiliser [Security::xss_clean] de la manière suivante:
|
||||
|
||||
$_POST['description'] = security::xss_clean($_POST['description']);
|
||||
|
||||
Vous pouvez aussi utiliser [Security::xss_clean] en tant que filtre via la librairie [Validate]:
|
||||
|
||||
$validation = new Validate($_POST);
|
||||
|
||||
$validate->filter('description', 'Security::xss_clean');
|
||||
|
||||
### POST & GET
|
||||
|
||||
Une des fonctionnalités très intéressante de la librairie Input était que lors de la tentative de lecture d'une variable superglobale, si celle-ci n'existait pas, il était possible de spécifier la valeur par défaut retournée i.e.:
|
||||
|
||||
$_GET = array();
|
||||
|
||||
// On assigne à $id la valeur 1
|
||||
$id = Input::instance()->get('id', 1);
|
||||
|
||||
$_GET['id'] = 25;
|
||||
|
||||
// On assigne à $id la valeur 25
|
||||
$id = Input::instance()->get('id', 1);
|
||||
|
||||
En 3.0 cette fonctionnalité est rendue par la méthode [Arr::get]:
|
||||
|
||||
$_GET = array();
|
||||
|
||||
// On assigne à $id la valeur 1
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
|
||||
$_GET['id'] = 42;
|
||||
|
||||
// On assigne à $id la valeur 42
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
|
||||
## Librairie ORM
|
||||
|
||||
De nombreux changements majeurs ont été faits sur la librairie ORM depuis la série 2.x, et voici quelques-uns des problèmes les plus courants que vous pourrez rencontrer:
|
||||
|
||||
### Variables de classe
|
||||
|
||||
Toutes les variables de classe sont désormais préfixées par un underscore (_) et ne sont plus accessibles via `__get()`. A la place, vous devez appeler une méthode portant le nom de la propriété sans le caractère underscore.
|
||||
|
||||
Par exemple, la propriété `loaded` en 2.x devient désormais `_loaded` et est accessible depuis l'extérieur via `$model->loaded()`.
|
||||
|
||||
### Relations
|
||||
|
||||
En 2.x, l'itération sur les objets liés à un modèle se faisait comme suit:
|
||||
|
||||
foreach($model->{relation_name} as $relation)
|
||||
|
||||
Cependant avec la nouvelle librarie 3.0 cela ne fonctionnera pas. En effet en version 2.3, toutes les requêtes sont générées avec une portée globale, c'est-à-dire qu'il est impossible de construire 2 requêtes simultanément. Par exemple:
|
||||
|
||||
# TODO: NEED A DECENT EXAMPLE!!!!
|
||||
|
||||
La requête échouera car la seconde requête hérite des conditions de la première et fausse donc les filtres.
|
||||
|
||||
En 3.0 ce problème a été corrigé car chaque requête à sa propre portée. Cela signifie aussi que certains de vos anciens codes ne fonctionneront plus. Prenez par exemple:
|
||||
|
||||
foreach(ORM::factory('user', 3)->where('post_date', '>', time() - (3600 * 24))->posts as $post)
|
||||
{
|
||||
echo $post->title;
|
||||
}
|
||||
|
||||
[!!] (Voir [le tutorial sur la Base de Données](tutorials.databases) pour la nouvelle syntaxe des requêtes)
|
||||
|
||||
En 2.3 on reçoit un itérateur sur tous les posts de l'utilisateur d'id 3 et dont la date est dans l'intervalle spécifié. Au lieu de ça, la condition 'where' sera appliquée au modèle 'user' et la requête retournera un objet `Model_Post` avec les conditions de jointure comme spécifié.
|
||||
|
||||
Pour obtenir le même résultat qu'en 2.x, en 3.0 la structure de la requête doit être modifiée:
|
||||
|
||||
foreach(ORM::factory('user', 3)->posts->where('post_date', '>', time() - (36000 * 24))->find_all() as $post)
|
||||
{
|
||||
echo $post->title;
|
||||
}
|
||||
|
||||
Cela s'applique aussi aux relations `has_one`:
|
||||
|
||||
// Incorrect
|
||||
$user = ORM::factory('post', 42)->author;
|
||||
// Correct
|
||||
$user = ORM::factory('post', 42)->author->find();
|
||||
|
||||
### Relations Has and belongs to many
|
||||
|
||||
En 2.x vous pouvez spécifier des relations `has_and_belongs_to_many`. En 3.0 cette fonctionnalité a été renommée en `has_many` *through*.
|
||||
|
||||
Dans vos modèles vous définissez une relation `has_many` avec les autres modèles et vous ajoutez un attribut `'through' => 'table'`, où `'table'` est le nom de la table de jointure. Par exemple dans la relation posts<>catégories:
|
||||
|
||||
$_has_many = array
|
||||
(
|
||||
'categories' => array
|
||||
(
|
||||
'model' => 'category', // Le modèle étranger
|
||||
'through' => 'post_categories' // La table de jointure
|
||||
),
|
||||
);
|
||||
|
||||
Si vous avez configuré Kohana pour utiliser une prefixe de table vous n'avez pas besoin d'explicitement préfixer la table.
|
||||
|
||||
### Clés étrangères
|
||||
|
||||
En 2.x, pour surcharger une clé étrangère vous deviez spécifier la relation auquelle elle appartenait et ajouter votre nouvelle clé étrangère dans la propriété `$foreign_keys`.
|
||||
|
||||
En 3.0 il faut juste définir une clé `foreign_key` dans la définition de la relation comme suit:
|
||||
|
||||
Class Model_Post extends ORM
|
||||
{
|
||||
$_belongs_to = array
|
||||
(
|
||||
'author' => array
|
||||
(
|
||||
'model' => 'user',
|
||||
'foreign_key' => 'user_id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Dans cet exemple on doit aussi avoir un champ `user_id` dans la table 'posts'.
|
||||
|
||||
|
||||
|
||||
Dans les relations has_many le champ `far_key` est le champ de la table de jointure qui le lie à la table étrangère et la clé étrangère est le champ de la table de jointure qui lie la table du modèle courant ("this") avec la table de jointure.
|
||||
|
||||
Considérez la configuration suivante où les "Posts" appartiennent à plusieurs "Categories" via `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',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Bien sûr l'exemple d'aliasing présenté ci-dessus est un peu exagéré, mais c'est un bon exemple de fonctionnement des clés foreign/far.
|
||||
|
||||
### Itérateur ORM
|
||||
|
||||
Il est important aussi de noter que `ORM_Iterator` a été renommé en `Database_Result`.
|
||||
|
||||
Si vous avez besoin de récupérer un tableau d'objets ORM dont la clé est la clé étrangère de l'objet, vous devez utiliser [Database_Result::as_array], e.g.
|
||||
|
||||
$objects = ORM::factory('user')->find_all()->as_array('id');
|
||||
|
||||
où `id` est la clé primaire de la table user.
|
||||
|
||||
## Librairie Router
|
||||
|
||||
En version 2.x il existe une librairie Router qui se charge du traitement des requêtes. Cela permet de définir des routes basiques dans le fichier`config/routes.php` et d'utiliser des expressions régulières mais au détriment de la flexibilité.
|
||||
|
||||
## Routes
|
||||
|
||||
Le sytème de routage est plus flexible en 3.0. Les routes sont maintenant définies dans le fichier bootstrap (`application/bootstrap.php`) et dans le cas des modules dans init.php (`modules/module_name/init.php`). Les routes sont évaluées dans l'ordre dans lequel elles sont définies.
|
||||
|
||||
Aulieu de définir un tableau de routes, désormais on crée un objet [Route] pour chacunes des routes. Contraitement à la version 2.x, il n'est pas nécessaire d'associer une URI à une autre. Au lieu de ça, il faut spécifier un pattern pour une URI en utilisation des variables pour marquer les segments (i.e. controller, method, id).
|
||||
|
||||
Par exemple, en 2.x on créé une route sous forme d'expression régulière comme suit:
|
||||
|
||||
$config['([a-z]+)/?(\d+)/?([a-z]*)'] = '$1/$3/$1';
|
||||
|
||||
Cette route associe l'URI `controller/id/method` à `controller/method/id`.
|
||||
|
||||
En 3.0 on utilise:
|
||||
|
||||
Route::set('reversed','(<controller>(/<id>(/<action>)))')
|
||||
->defaults(array('controller' => 'posts', 'action' => 'index'));
|
||||
|
||||
[!!] Chaque URI doit avoir un nom unique (dans l'exemple ci-dessus c'est `reversed`). La raison de ce choix est expliquée dans le [tutorial sur les URLs](tutorials.urls).
|
||||
|
||||
Les chevrons sont utilisés pour définir des sections dynamiques qui doivent être transformées en variables. Les parenthèses dénotent une section optionnelle. Si vous ne souhaitez matcher que les URIs commençant par admin, vous pouvez utiliser:
|
||||
|
||||
Rouse::set('admin', 'admin(/<controller>(/<id>(/<action>)))');
|
||||
|
||||
Et si vous voulez forcer l'utilisateur à spécifier un controleur:
|
||||
|
||||
Route::set('admin', 'admin/<controller>(/<id>(/<action>))');
|
||||
|
||||
De plus Kohana 3.0 ne définit pas de routes par défaut. Si votre action (méthode) par défaut est 'index', alors vous devez le spécifier comme tel. Cela se fait via la méthode [Route::defaults]. Si vous voulez utiliser des expressions régulières pour des segments de votre URI alors il suffit de passer un tableau associatif `segment => regex` i.e.:
|
||||
|
||||
Route::set('reversed', '(<controller>(/<id>(/<action>)))', array('id' => '[a-z_]+'))
|
||||
->defaults(array('controller' => 'posts', 'action' => 'index'))
|
||||
|
||||
Cette route force la valeur de `id` à être en minuscule et composée uniquement de caractères alphabétiques et du caractère underscore.
|
||||
|
||||
### Actions
|
||||
|
||||
Une dernière chose importante à noter est que toute méthode accessible d'un controleur (càd via l'URI) sont appelées "actions", et sont préfixées de 'action_'. Dans l'exemple ci-dessus, `admin/posts/1/edit` appelle l'action `edit` mais la méthode rééllement apelée dans le controleur est `action_edit`. Pour plus d'informations voir [le tutorial sur les URLs](tutorials.urls).
|
||||
|
||||
## Sessions
|
||||
|
||||
Les méthodes Session::set_flash(), Session::keep_flash() et Session::expire_flash() n'existent plus. A la place la méthode [Session::get_once] peut être utilisée.
|
||||
|
||||
## Helper URL
|
||||
|
||||
Seules des modifications mineures ont été apportées sur l'helper URL. `url::redirect()` est désormais fait via `$this->request->redirect()` dans les controleurs et via `Request::instance()->redirect()` ailleurs.
|
||||
|
||||
`url::current` a été remplacé par `$this->request->uri()`.
|
||||
|
||||
## Validation
|
||||
|
||||
La syntaxe a subit quelque modifications. Pour valider un tableau il faut maintenant faire:
|
||||
|
||||
$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')
|
||||
));
|
||||
|
||||
La règle 'required' a été renommée en 'not_empty' pour plus de clarté.
|
||||
|
||||
## Librairie View
|
||||
|
||||
En 2.x, les vues sont rendues dans la portée d'un controleur, vous permettant ainsi d'utiliser `$this` dans la vue comme référence vers le controleur.
|
||||
En 3.0 les vues sont rendues sans aucune portée. Si vous souhaitez utiliser `$this` dans vos vues alors vous devez l'affecter par référence avec [View::bind]:
|
||||
|
||||
$view->bind('this', $this)
|
||||
|
||||
Néanmoins c'est une mauvaise pratique car cela couple votre vue avec le controleur limitant ainsi la réutilisation du code. Il est vivement recommandé de ne passer que les variables requises par la vue:
|
||||
|
||||
$view = View::factory('my/view');
|
||||
|
||||
$view->variable = $this->property;
|
||||
|
||||
// ou par chainage
|
||||
|
||||
$view
|
||||
->set('variable', $this->property)
|
||||
->set('another_variable', 42);
|
||||
|
||||
// NON Recommandé
|
||||
$view->bind('this', $this);
|
||||
|
||||
Etant donné qu'une vue n'a pas de portée, la méthode `Controller::_kohana_load_view` est redondante. Si vous avez besoin de modifier la vue avant qu'elle ne soit rendue (par exemple pour ajouter un menu global à toutes vos pages) vous pouvez utiliser [Controller::after].
|
||||
|
||||
Class Controller_Hello extends Controller_Template
|
||||
{
|
||||
function after()
|
||||
{
|
||||
$this->template->menu = '...';
|
||||
|
||||
return parent::after();
|
||||
}
|
||||
}
|
@@ -1,24 +0,0 @@
|
||||
# Debugging du code
|
||||
|
||||
Kohana fournit plusieurs outils puissants pour debugger vos applications.
|
||||
|
||||
Le plus basique d'entre eux est [Kohana::debug]. Cette méthode permet d'afficher toutes variables à la manière de [var_export] ou [print_r], mais en utilisant HTML pour ajouter du formatage supplémentaire.
|
||||
|
||||
~~~
|
||||
// Affiche le contenu (dump) des variables $foo et $bar
|
||||
echo Kohana::debug($foo, $bar);
|
||||
~~~
|
||||
|
||||
Kohana fournit aussi une méthode pour afficher le code source d'un fichier en particulier en appelant [Kohana::debug_source].
|
||||
|
||||
~~~
|
||||
// Affiche cette ligne de code source
|
||||
echo Kohana::debug_source(__FILE__, __LINE__);
|
||||
~~~
|
||||
|
||||
Enfin si vous voulez afficher des informations sur les chemins de votre application sans afficher/exposer le chemin d'installation vous pouvez utiliser [Kohana::debug_path]:
|
||||
|
||||
~~~
|
||||
// Affiche "APPPATH/cache" plutot que le chemin réél
|
||||
echo Kohana::debug_file(APPPATH.'cache');
|
||||
~~~
|
@@ -1,24 +0,0 @@
|
||||
# Gestion des Erreurs/Exceptions
|
||||
|
||||
Kohana fournit des mécanismes de gestion des exceptions et d'erreurs qui transforment les erreurs en exceptions en utilisant les classes PHP prévues à cet effet [ErrorException](http://php.net/errorexception). De nombreux détails sur l'application ainsi que son état sont affichées :
|
||||
|
||||
1. Classe de l'Exception
|
||||
2. Niveau de l'erreur
|
||||
3. Message de l'erreur
|
||||
4. Source de l'erreur, avec la ligne contenant l'erreur surlignée
|
||||
5. Une [trace de debug](http://php.net/debug_backtrace) du processus d'exécution
|
||||
6. Les fichiers inclus, les extensions chargées et les variables globales
|
||||
|
||||
## Exemple
|
||||
|
||||
Cliquez sur l'un des liens ci-dessous pour afficher/masquer des informations additionnelles:
|
||||
|
||||
<div>{{userguide/examples/error}}</div>
|
||||
|
||||
## Désactiver le support des Exceptions
|
||||
|
||||
Si vous ne voulez pas utiliser le mécanisme interne de gestion des exceptions et des erreurs, vous pouvez le désactiver via [Kohana::init]:
|
||||
|
||||
~~~
|
||||
Kohana::init(array('errors' => FALSE));
|
||||
~~~
|
@@ -1,22 +0,0 @@
|
||||
# Profiling
|
||||
|
||||
Kohana fournit de façon très facile les statistiques de vos applications:
|
||||
|
||||
1. Appels de méthodes [Kohana] communes
|
||||
2. Requêtes URI
|
||||
3. Requêtes de [base de données](tutorials.databases)
|
||||
4. Temps moyen d'execution de votre application
|
||||
|
||||
## Affichage/Récupération des statistiques
|
||||
|
||||
Vous pouvez afficher ou récupérer les statistiques courantes à tout moment en faisant:
|
||||
|
||||
~~~
|
||||
<div id="kohana-profiler">
|
||||
<?php echo View::factory('profiler/stats') ?>
|
||||
</div>
|
||||
~~~
|
||||
|
||||
## Exemple
|
||||
|
||||
{{profiler/stats}}
|
@@ -1 +0,0 @@
|
||||
Cette page liste les fonctionnalités clés de Kohana v3.
|
@@ -1,26 +0,0 @@
|
||||
1. **Bien débuter**
|
||||
- [Qu'est-ce que Kohana?](about.kohana)
|
||||
- [Conventions et style](about.conventions)
|
||||
- [Installation](about.install)
|
||||
- [Mise à jour depuis 2.x](about.upgrading)
|
||||
- [Configuration](about.configuration)
|
||||
- [Modèle Vue Controleur](about.mvc)
|
||||
- [Arborescence de fichier](about.filesystem)
|
||||
- [Auto-chargement](about.autoloading)
|
||||
- [Enchainement des Requetes](about.flow)
|
||||
- [Explorateur API](api)
|
||||
2. **Tutoriaux**
|
||||
- [Hello, World](tutorials.helloworld)
|
||||
- [Routes, URLs, et Liens](tutorials.urls)
|
||||
- [Base de données](tutorials.databases)
|
||||
- [ORM](tutorials.orm)
|
||||
- [Travailler avec Git](tutorials.git)
|
||||
3. **Securité**
|
||||
- [XSS](security.xss)
|
||||
- [Validation](security.validation)
|
||||
- [Cookies](security.cookies)
|
||||
- [Base de données](security.database)
|
||||
4. **Debugging**
|
||||
- [Code](debugging.code)
|
||||
- [Gestion des erreurs](debugging.errors)
|
||||
- [Profiling](debugging.profiling)
|
@@ -1,3 +0,0 @@
|
||||
# Sécurité des Cookies
|
||||
|
||||
[!!] stub
|
@@ -1,3 +0,0 @@
|
||||
# Sécurité de la Base de données
|
||||
|
||||
[!!] stub
|
@@ -1,241 +0,0 @@
|
||||
# Validation
|
||||
|
||||
La validation peut être effectuée sur tous les tableaux en utilisant la classe [Validate]. Les labels, filtres, règles et callbacks peuvent être attachés à un objet Validate via un tableau de clé, appellées "champs" (field name).
|
||||
|
||||
labels
|
||||
: Un label est la version lisible (par un humain) d'un nom de champ.
|
||||
|
||||
filters
|
||||
: Un filtre modifie la valeur d'un champs avant que les règles et callbacks ne soient exécutées.
|
||||
|
||||
rules
|
||||
: Une règle est une vérification sur un champ qui retourne `TRUE` ou `FALSE`. Si une règle retourne `FALSE`, une erreur sera ajoutée à ce champ.
|
||||
|
||||
callbacks
|
||||
: Une callback est une méthode spécifique ayant accès à l'ensemble de l'objet Validate.
|
||||
La valeur retournée par une callback est ignorée. A la place, en cas d'erreur une callback doit manuellement ajouter une erreur à un champ en utilisant [Validate::error].
|
||||
|
||||
[!!] A noter que les callbacks [Validate] et les [callbacks PHP](http://php.net/manual/language.pseudo-types.php#language.types.callback) ne sont pas pareils.
|
||||
|
||||
Utiliser `TRUE` comment nom de champ lors de l'ajout d'un filtre, règle ou callback a pour effet de l'appliquer à tous les champs.
|
||||
|
||||
**L'objet [Validate] supprimera tous les champs du tableau qui n'ont pas explicitement été utilisés via un label, un filtre, une règle ou une callback. Ceci pour empêcher tout accès à un champ qui n'a pas été validé et ajouter ainsi une protection de sécurité supplémentaire.**
|
||||
|
||||
La création d'un objet de validation est faite en utilsiant la méthode [Validate::factory]:
|
||||
|
||||
$post = Validate::factory($_POST);
|
||||
|
||||
[!!] L'objet `$post` sera utilisé pour le reste de ce tutorial dans lequel sera illustré la validation de l'inscription d'un nouveal utilisateur.
|
||||
|
||||
### Règles par défaut
|
||||
|
||||
La validation supporte les règles par défaut suivantes:
|
||||
|
||||
Nom de la règle | Description
|
||||
------------------------- |-------------------------------------------------
|
||||
[Validate::not_empty] | La valeur ne doit pas être vide
|
||||
[Validate::regex] | La valeur respecte l'expression réguliére spécifiée
|
||||
[Validate::min_length] | La valeur respecte un nombre minimum de caractères
|
||||
[Validate::max_length] | La valeur respecte un nombre maximum de caractères
|
||||
[Validate::exact_length] | La valeur fait exactement le nombre de caractéres spécifiés
|
||||
[Validate::email] | La valeur doit respecter un format d'email
|
||||
[Validate::email_domain] | Le domaine de l'email existe
|
||||
[Validate::url] | La valeur entrée doit respecter un format d'URL
|
||||
[Validate::ip] | La valeur entrée doit respecter un format d'adresse IP
|
||||
[Validate::phone] | La valeur entrée doit respecter un format d'un uméro de téléphone
|
||||
[Validate::credit_card] | La valeur entrée doit respecter un format de numéro de carte de crédit
|
||||
[Validate::date] | La valeur entrée doit respecter un format de date (et heure)
|
||||
[Validate::alpha] | Seuls les caractères alphabétiques sont autorisés
|
||||
[Validate::alpha_dash] | Seuls les caractères alphabétiques et le caractère tiret '-' sont autorisés
|
||||
[Validate::alpha_numeric] | Seuls les caractères alphabétiques et numériques sont autorisés
|
||||
[Validate::digit] | La valeur doit être un chiffre
|
||||
[Validate::decimal] | La valeur doit être décimale ou flottante
|
||||
[Validate::numeric] | Seuls les caractères numériques sont autorisés
|
||||
[Validate::range] | La valeur doit être dans l'intervalle spécifié
|
||||
[Validate::color] | La valeur entrée doit respecter un format de couleur hexadécimal
|
||||
[Validate::matches] | La valeur doit correspondre à la valeur d'un autre champ
|
||||
|
||||
[!!] Toute méthode existante de la classe [Validate] peut être utilisée directement sans utiliser une déclaration de callback compléte. Par exemple, ajouter la règle `'not_empty'` est la même chose que `array('Validate', 'not_empty')`.
|
||||
|
||||
## Ajouter des filtres
|
||||
|
||||
Tous les filtres de validation sont définis par un nom de champ, une méthode ou une fonction (en utilisant la syntaxe des [callbacks PHP](http://php.net/manual/language.pseudo-types.php#language.types.callback)), ainsi q'un tableau de paramètres:
|
||||
|
||||
$object->filter($field, $callback, $parameter);
|
||||
|
||||
Les filtres modifient la valeur d'un filtre avant leur vérification par les règles et callbacks définies.
|
||||
|
||||
Par exemple pour convertir un nom d'utilisateur en minuscule, alors il suffit d'écrire:
|
||||
|
||||
$post->filter('username', 'strtolower');
|
||||
|
||||
Autre exemple, si l'on souhaite enlever les caratères vides au début et en fin de chaine de tous les champs, alors il faut écrire:
|
||||
|
||||
$post->filter(TRUE, 'trim');
|
||||
|
||||
## Ajouter des règles
|
||||
|
||||
Toutes les règles de validation sont définies par un nom de champ, une méthode ou une fonction (en utilisant la syntaxe des [callbacks PHP](http://php.net/manual/language.pseudo-types.php#language.types.callback)), ainsi q'un tableau de paramètres:
|
||||
|
||||
$object->rule($field, $callback, $parameter);
|
||||
|
||||
Pour commencer notre exemple, nous allons commencer par valider le tableau `$_POST` contenant des informations d'inscription d'un utilisateur.
|
||||
|
||||
Pour cela nous avons besoin de traiter les informations POSTées en utilisant [Validate]. Commencons par ajouter quelque régles:
|
||||
|
||||
$post
|
||||
->rule('username', 'not_empty')
|
||||
->rule('username', 'regex', array('/^[a-z_.]++$/iD'))
|
||||
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array('6'))
|
||||
->rule('confirm', 'matches', array('password'))
|
||||
|
||||
->rule('use_ssl', 'not_empty');
|
||||
|
||||
Toute fonction PHP existante peut aussi être utilisée comme une règle. Par exemple si l'on souhaite vérifier que l'utilisateur a entré une valeur correcte pour une question, on peut écrire:
|
||||
|
||||
$post->rule('use_ssl', 'in_array', array(array('yes', 'no')));
|
||||
|
||||
A noter que les tableaux de paramètres doivent quand même être insérés dans un tableau! Si vous ne mettez pas ce tableau, `in_array` serait appelée via `in_array($value, 'yes', 'no')`, ce qui aboutirait à une erreur PHP.
|
||||
|
||||
Toute régle spécifique peut être ajoutée en utilisant une [callback PHP](http://php.net/manual/language.pseudo-types.php#language.types.callback):
|
||||
|
||||
$post->rule('username', array($model, 'unique_username'));
|
||||
|
||||
La méthode `$model->unique_username()` ressemblerait alors à:
|
||||
|
||||
public function unique_username($username)
|
||||
{
|
||||
// Vérifie si le nom d'utilisateur existe déjà dans la base de données
|
||||
return ! DB::select(array(DB::expr('COUNT(username)'), 'total'))
|
||||
->from('users')
|
||||
->where('username', '=', $username)
|
||||
->execute()
|
||||
->get('total');
|
||||
}
|
||||
|
||||
[!!] Vous pouvez définir vos propres régles pour faire des vérifications additionnelles. Ces régles peuvent être réutilisés à plusieurs fins. Ces méthodes vont presque toujours exister au sein d'un modèle mais peuvent être définies dans nimporte quelle classe.
|
||||
|
||||
## Ajouter des callbacks
|
||||
|
||||
Toutes les callbacks de validation sont définies par un nom de champ et une méthode ou une fonction (en utilisant la syntaxe des [callbacks PHP](http://php.net/manual/language.pseudo-types.php#language.types.callback)):
|
||||
|
||||
$object->callback($field, $callback);
|
||||
|
||||
[!!] Contrairement aux filtres et aux régles, aucun paramètre n'est passé à une callback.
|
||||
|
||||
Le mot de passe utilisateur doit être hashé parès validaiton, nous allons donc le faire avec une callback:
|
||||
|
||||
$post->callback('password', array($model, 'hash_password'));
|
||||
|
||||
Cela implique la création de la méthode `$model->hash_password()` de la manière suivante:
|
||||
|
||||
public function hash_password(Validate $array, $field)
|
||||
{
|
||||
if ($array[$field])
|
||||
{
|
||||
// Hasher le mot de passe s'il existe
|
||||
$array[$field] = sha1($array[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
# Un exemple complet
|
||||
|
||||
TOut d'abord nous avons besoin d'une [Vue] contenant le formulaire HTML que l'on placera dans `application/views/user/register.php`:
|
||||
|
||||
<?php echo Form::open() ?>
|
||||
<?php if ($errors): ?>
|
||||
<p class="message">Des erreurs ont été trouvées, veuillez vérifier les informations entrées.</p>
|
||||
<ul class="errors">
|
||||
<?php foreach ($errors as $message): ?>
|
||||
<li><?php echo $message ?></li>
|
||||
<?php endforeach ?>
|
||||
<?php endif ?>
|
||||
|
||||
<dl>
|
||||
<dt><?php echo Form::label('username', 'Nom d'utilisateur') ?></dt>
|
||||
<dd><?php echo Form::input('username', $post['username']) ?></dd>
|
||||
|
||||
<dt><?php echo Form::label('password', 'Mot de passe') ?></dt>
|
||||
<dd><?php echo From::password('password') ?></dd>
|
||||
<dd class="help">Le mot de passe doit contenir au moins 6 caractères.</dd>
|
||||
<dt><?php echo Form::label('confirm', 'Confirmer le mot de passe') ?></dt>
|
||||
<dd><?php echo Form::password('confirm') ?></dd>
|
||||
|
||||
<dt><?php echo Form::label('use_ssl', 'Utiliser une sécurité supplémentaire?') ?></dt>
|
||||
<dd><?php echo Form::select('use_ssl', array('yes' => 'Toujours', 'no' => 'Seulement si nécessaire'), $post['use_ssl']) ?></dd>
|
||||
<dd class="help">Pour des raisons de sécurité, SSL est toujours utilisé pour les paiements.</dd>
|
||||
</dl>
|
||||
|
||||
<?php echo Form::submit(NULL, 'S\'inscrire') ?>
|
||||
<?php echo Form::close() ?>
|
||||
|
||||
[!!] Cette exemple utilise le helper [Form]. L'utiliser au lieu d'écrire du code HTML vous assure que tous les objets du formulaire vont traiter correctement les caractères HTML. Si vous souhaitez écrire le code HTML directement, veillez à utiliser [HTML::chars] pour filtrer/échaper les informations entrées par les utilisateurs.
|
||||
|
||||
Ensuite nous avons besoin d'un controleur et d'une action pour traiter l'inscription des utilisaeurs, fichier qu'on placera dans `application/classes/controller/user.php`:
|
||||
|
||||
class Controller_User extends Controller {
|
||||
|
||||
public function action_register()
|
||||
{
|
||||
$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', array($user, 'unique_username'))
|
||||
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array('6'))
|
||||
->rule('confirm', 'matches', array('password'))
|
||||
|
||||
->rule('use_ssl', 'not_empty')
|
||||
->rule('use_ssl', 'in_array', array(array('yes', 'no')))
|
||||
|
||||
->callback('password', array($user, 'hash_password'));
|
||||
|
||||
if ($post->check())
|
||||
{
|
||||
// Les données ont éta validées, on inscrit l'utilisateur
|
||||
$user->register($post);
|
||||
|
||||
// Toujours rediriger l'utilisateur après une validation de formulaire réussie afin de ne pas avoir les avertissement de rafraichissement
|
||||
$this->request->redirect('user/profile');
|
||||
}
|
||||
|
||||
// La validation a échoué, récupérons les erreurs
|
||||
$errors = $post->errors('user');
|
||||
|
||||
// Affiche le formulaire d'inscription
|
||||
$this->request->response = View::factory('user/register')
|
||||
->bind('post', $post)
|
||||
->bind('errors', $errors);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Nous avons aussi besoin d'un modèle qui sera placé dans `application/classes/model/user.php`:
|
||||
|
||||
class Model_User extends Model {
|
||||
|
||||
public function register($array)
|
||||
{
|
||||
// Créé un nouvel utilisateur dans la base de données
|
||||
$id = DB::insert(array_keys($array))
|
||||
->values($array)
|
||||
->execute();
|
||||
|
||||
// Sauvegarde l'identifiant de l'utilisateur dans un cookie
|
||||
cookie::set('user', $id);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
C'est tout! Nous avons désormais un formulaire d'inscritpion opérationnel et qui vérifie les informations entrées.
|
@@ -1,17 +0,0 @@
|
||||
# Cross-Site Scripting (XSS)
|
||||
|
||||
La première étape pour se prémunir des attaques de type [XSS](http://wikipedia.org/wiki/Cross-Site_Scripting) est de savoir quand il faut le faire. Les attaques XSS ne peuvent être déclenchées que lors de l'affichage de contenu HTML au travers de formulaires ou de données issues de la base de données. Toute variable globale contenant des informations clientes peut être un vecteur d'attaques XSS. Cela inclut les données `$_GET`, `$_POST`, et `$_COOKIE`.
|
||||
|
||||
## Prévention
|
||||
|
||||
Il existe des règles simples à suivre pour prémunir vos applications de ces attaques.
|
||||
|
||||
La première est d'utiliser systématiquement la méthode [Security::xss] pour nettoyer des données d'une variable globale. De plus si vous ne souhaitez pas avoir de HTML dans vos variables, utilisez la méthode [strip_tags](http://php.net/strip_tags) pour supprimer les balises HTML.
|
||||
|
||||
[!!] Si vous autorisez les utilisateurs à entrer des données HTML dans votre application, il est vivement recommandé d'utiliser une librairie de nettoyage HTML comme [HTML Purifier](http://htmlpurifier.org/) ou [HTML Tidy](http://php.net/tidy).
|
||||
|
||||
La seconde est de toujours échapper les données insérées dans vos pages HTML. La classe [HTML] fournit des générateurs pour de nombreuses balises HTML, incluant scripts et feuilles de style, liens, ancres, images et email. Tout contenu sans confiance doit être échappé avec [HTML::chars].
|
||||
|
||||
## Références
|
||||
|
||||
* [OWASP XSS Cheat Sheet](http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)
|
@@ -1,242 +0,0 @@
|
||||
# Base de données {#top}
|
||||
|
||||
Kohana 3.0 intégre un robuste module permettant de travailler avec les base de données. Par défauut, le module supporte [MySQL](http://php.net/mysql) et [PDO](http://php.net/pdo).
|
||||
|
||||
Le module base de données est inclus par défaut dans votre installation de Kohana 3.0 mais n'est pas activé. Pour l'activer, éditez le fichier `application/bootstrap.php` et modifiez l'appel à [Kohana::modules] pour y inclure le module base de données:
|
||||
|
||||
Kohana::modules(array(
|
||||
...
|
||||
'database' => MODPATH.'database',
|
||||
...
|
||||
));
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Aprés activation du module, il vous faut préciser les paramètres de configuration permettant à votre application de se connecter à la base de données. Un exemple de fichier de configuration peut être trouvé sous `modules/database/config/database.php`.
|
||||
|
||||
La structure d'un groupe de configuration pour une base de données, appelé instance, est de cette forme:
|
||||
|
||||
string INSTANCE_NAME => array(
|
||||
'type' => string DATABASE_TYPE,
|
||||
'connection' => array CONNECTION_ARRAY,
|
||||
'table_prefix' => string TABLE_PREFIX,
|
||||
'charset' => string CHARACTER_SET,
|
||||
'profiling' => boolean QUERY_PROFILING,
|
||||
),
|
||||
|
||||
[!!] Plusieurs instances différentes de ces configurations peuvent être définies dans le fichier de configuration.
|
||||
|
||||
La compréhension de l'ensemble de ces paramètres est importante:
|
||||
|
||||
INSTANCE_NAME
|
||||
: nom personnalisé de l'instance. Il est obligatoire d'avoir au moins une instance appelée "default".
|
||||
|
||||
DATABASE_TYPE
|
||||
: type de base de données. Valeurs acceptées: "mysql" et "pdo".
|
||||
|
||||
CONNECTION_ARRAY
|
||||
: options de connection spécifiques au type de base de données choisis. Ces options sont explicités [plus bas](#connection_settings).
|
||||
|
||||
TABLE_PREFIX
|
||||
: prefixe qui sera ajouté à tous les noms de table par le [constructeur de requêtes](#query_building).
|
||||
|
||||
QUERY_PROFILING
|
||||
: activer le [profiling](debugging.profiling) des requêtes.
|
||||
|
||||
### Exemple
|
||||
|
||||
L'exemple ci-dessous est composé de 2 connections MySQL, la première locale et l'autre distante:
|
||||
|
||||
return array
|
||||
(
|
||||
'default' => array
|
||||
(
|
||||
'type' => 'mysql',
|
||||
'connection' => array(
|
||||
'hostname' => 'localhost',
|
||||
'username' => 'dbuser',
|
||||
'password' => 'mypassword',
|
||||
'persistent' => FALSE,
|
||||
'database' => 'my_db_name',
|
||||
),
|
||||
'table_prefix' => '',
|
||||
'charset' => 'utf8',
|
||||
'profiling' => TRUE,
|
||||
),
|
||||
'remote' => array(
|
||||
'type' => 'mysql',
|
||||
'connection' => array(
|
||||
'hostname' => '55.55.55.55',
|
||||
'username' => 'remote_user',
|
||||
'password' => 'mypassword',
|
||||
'persistent' => FALSE,
|
||||
'database' => 'my_remote_db_name',
|
||||
),
|
||||
'table_prefix' => '',
|
||||
'charset' => 'utf8',
|
||||
'profiling' => TRUE,
|
||||
),
|
||||
);
|
||||
|
||||
### Options de connection {#connection_settings}
|
||||
|
||||
Chacun des types de base de données possède des options différentes de connection.
|
||||
|
||||
#### MySQL
|
||||
|
||||
Les options de connection MySQL sont les suivantes:
|
||||
|
||||
Type | Option | Description | Valeur par défaut
|
||||
----------|------------|----------------------------|--------------------------
|
||||
`string` | hostname | Hôte hébergeant la base | `localhost`
|
||||
`integer` | port | Numéro de port | `NULL`
|
||||
`string` | socket | Socket UNIX | `NULL`
|
||||
`string` | username | Utilisateur | `NULL`
|
||||
`string` | password | Mot de passe | `NULL`
|
||||
`boolean` | persistent | Connections persistantes | `FALSE`
|
||||
`string` | database | Nom de base de la base | `kohana`
|
||||
|
||||
#### PDO
|
||||
|
||||
Les options de connection PDO sont les suivantes:
|
||||
|
||||
Type | Option | Description | Valeur par défaut
|
||||
----------|------------|----------------------------|--------------------------
|
||||
`string` | dsn | Source PDO | `localhost`
|
||||
`string` | username | Utilisateur | `NULL`
|
||||
`string` | password | Mot de passe | `NULL`
|
||||
`boolean` | persistent | Connections persistantes | `FALSE`
|
||||
|
||||
!! Si vous utilisez PDO et n'êtes pas sûr de la valeur du `dsn`, veuillez consulter [PDO::__construct](http://php.net/pdo.construct).
|
||||
|
||||
## Connections et Instances {#connections}
|
||||
|
||||
Chaque groupe de configuration est accessible en tant qu'instance de base de données. On accède à une instance en appelant [Database::instance]:
|
||||
|
||||
$default = Database::instance();
|
||||
$remote = Database::instance('remote');
|
||||
|
||||
Pour se déconnecter de la base de données, il suffit de détruire l'objet correspondant:
|
||||
|
||||
unset($default, Database::$instances['default']);
|
||||
|
||||
Si vous souhaitez déconnecter l'ensemble des instances d'un coup alors écrivez:
|
||||
|
||||
Database::$instances = array();
|
||||
|
||||
## Ecrire des requêtes {#making_queries}
|
||||
|
||||
Il existe 2 manières d'écrire des requêtes dans Kohana. La manière la plus simple est d'utiliser le [constructeur de requête](Query_Builder), via [DB::query]. Ces requêtes sont appelées des "requêtes préparées" ou prepared statements et permettent l'échappement automatique des paramètres de la requête.
|
||||
|
||||
La seconde manière est d'appeler directement les méthodes voulues.
|
||||
|
||||
[!!] Toutes les requêtes sont executées via la méthode `execute`, qui prend en paramètre un objet base de données ou un nom d'instance. Pour plus d'informations, consultez [Database_Query::execute].
|
||||
|
||||
### Requêtes préparées
|
||||
|
||||
L'utilisation de requêtes préparées permet d'écrire des requetes SQL manuellement tout en échappant les paramètres de la requête automatiquement permettant ainsi de se prémunir contre les [injections SQL](http://wikipedia.org/wiki/SQL_Injection). La création d'une requête est simple:
|
||||
|
||||
$query = DB::query(Database::SELECT, 'SELECT * FROM users WHERE username = :user');
|
||||
|
||||
La méthode [DB::query] créé un objet [Database_Query] et permet un chainage des méthodes. La requête contient un paramètre `:user` que l'on peut assigner comme suit:
|
||||
|
||||
$query->param(':user', 'john');
|
||||
|
||||
[!!] Les noms de paramètre peuvent être nimporte quelle chaine de caractères puisqu'elles sont remplacées en utilisant la fonction [strtr](http://php.net/strtr). Il est vivement recommandé de ne **pas** utiliser de signe dollars ($) pour éviter toute confusion.
|
||||
|
||||
Si vous souhaitez afficher la requête SQL qui va être exécutée, il vous suffit de caster l'objet en chaine de caractères comme suit:
|
||||
|
||||
echo Kohana::debug((string) $query);
|
||||
// Affichera:
|
||||
// SELECT * FROM users WHERE username = 'john'
|
||||
|
||||
Vous pouvez aussi ré-assigner `:user` ultérieurement en appelant [Database_Query::param]:
|
||||
|
||||
$query->param(':user', $_GET['search']);
|
||||
|
||||
[!!] Pour assigner plusieurs paramètres à la fois, vous pouvez utiliser [Database_Query::parameters].
|
||||
|
||||
Une fois chacuns des paramètres de votre requête assignés, l'exécution de la requête se fait via:
|
||||
|
||||
$query->execute();
|
||||
|
||||
Enfin, il est aussi possible d'assigner un paramètre à une [variable passée par référence](http://php.net/language.references.whatdo). Cela peut s'avérer très utile lors de l'exécution de la même requête plusieurs fois avec des paramètres différents:
|
||||
|
||||
$query = DB::query(Database::INSERT, 'INSERT INTO users (username, password) VALUES (:user, :pass)')
|
||||
->bind(':user', $username)
|
||||
->bind(':pass', $password);
|
||||
|
||||
foreach ($new_users as $username => $password)
|
||||
{
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
Dans l'exemple ci-dessus, les variables `$username` and `$password` sont changées à chacune des itérations de la boucle `foreach`. Cela s'avére très puissant et peut vous permettre d'alléger votre code.
|
||||
|
||||
### Construction de requêtes {#query_building}
|
||||
|
||||
La création dynamique de requêtes en utilisant des objets et des méthodes de classe permet de créér des requêtes sans avoir de connaissances sur le langage SQL. Le constructeur se charge d'échapper les noms de table et colonnes mais aussi les valeurs des paramètres des requêtes.
|
||||
|
||||
[!!] A ce jour, Kohana ne dispose pas de moyens de combiner les requêtes préparées et la construction dynamique de requêtes.
|
||||
|
||||
#### SELECT
|
||||
|
||||
Chaque type de requête en base de données est représenté par une classe, chacunes possédant ses propres méthodes. Par exemple, pour créér une requête SELECT, utilisez [DB::select]:
|
||||
|
||||
$query = DB::select()->from('users')->where('username', '=', 'john');
|
||||
|
||||
Par défault, [DB::select] sélectionnera toutes les colonnes (`SELECT * ...`), mais vous pouvez aussi spécifier ces colonnes:
|
||||
|
||||
$query = DB::select('username', 'password')->from('users')->where('username', '=', 'john');
|
||||
|
||||
L'exemple ci-dessus illustre aussi la puissance du chainage de méthodes qui permet en une seule ligne de spécifier les paramètres de sélection, la table et les critères de filtrage via la méthode `where`. De la même manière que précédemment, si vous souhaitez afficher la requête SQL qui va être exécutée, il vous suffit de caster l'objet en chaine de caractères comme suit:
|
||||
|
||||
echo Kohana::debug((string) $query);
|
||||
// Affichera:
|
||||
// SELECT `username`, `password` FROM `users` WHERE `username` = 'john'
|
||||
|
||||
Notez que tout est échappé correctement et c'est là l'un des grands avantages de l'utilisation du constructeur de requêtes.
|
||||
|
||||
La création d'alias `AS` se fait comme ci-dessous:
|
||||
|
||||
$query = DB::select(array('username', 'u'), array('password', 'p'))->from('users');
|
||||
// Requête exécutée:
|
||||
// SELECT `username` AS `u`, `password` AS `p` FROM `users`
|
||||
|
||||
#### INSERT
|
||||
|
||||
Pour insérer des enregistrements dans la base de données il faut utiliser [DB::insert]:
|
||||
|
||||
$query = DB::insert('users', array('username', 'password'))->values(array('fred', 'p@5sW0Rd'));
|
||||
// Requête exécutée:
|
||||
// INSERT INTO `users` (`username`, `password`) VALUES ('fred', 'p@5sW0Rd')
|
||||
|
||||
#### UPDATE
|
||||
|
||||
La modification d'un enregistrement en base se fait via [DB::update]:
|
||||
|
||||
$query = DB::update('users')->set(array('username' => 'jane'))->where('username', '=', 'john');
|
||||
// Requête exécutée:
|
||||
// UPDATE `users` SET `username` = 'jane' WHERE `username` = 'john'
|
||||
|
||||
#### DELETE
|
||||
|
||||
Pour supprimer un enregistrement, il faut utiliser [DB::delete]:
|
||||
|
||||
$query = DB::delete('users')->where('username', 'IN', array('john', 'jane'));
|
||||
// Requête exécutée:
|
||||
// DELETE FROM `users` WHERE `username` IN ('john', 'jane')
|
||||
|
||||
#### Fonctions spécifiques {#database_functions}
|
||||
|
||||
Il est commun d'utiliser des fonctions spécifiques de base de données telles que `COUNT`. Le constructeur de requête vous permet de les utiliser de 2 manières. La première est la suivante:
|
||||
|
||||
$query = DB::select(array('COUNT("username")', 'total_users'))->from('users');
|
||||
|
||||
Ca ressemble beaucoup à l'aliasing `AS` mais notez que le nom de colonne est entouré de doubles quotes. A chaque fois qu'un nom de colonne est entouré de doubles quotes, alors **seules** les parties entourées seront échappées. Cette requête générerait le SQL suivant:
|
||||
|
||||
SELECT COUNT(`username`) AS `total_users` FROM `users`
|
||||
|
||||
#### Expressions complexes
|
||||
|
||||
De temps à autre on a besoin d'écrire des requêtes contenant des expressions complexes. Dans ce cas, cette expression sera créé via [DB::expr]. Une expression est prise telle quelle par la méthode et de ce fait aucun échappement n'est fait.
|
@@ -1,117 +0,0 @@
|
||||
# Travailler avec Git
|
||||
|
||||
Kohana utilise [git](http://git-scm.com/) comme système de gestion de versions et [github](http://github.com/kohana) pour l'aspect collaboratif. Ce tutorial présente comment utiliser git et github pour mettre en place une application simple.
|
||||
|
||||
## Structure initiale
|
||||
|
||||
[!!] Ce tutorial prend comme prérequis le fait que votre serveur web est déjà mis en place et que vous être dans l'étape de création d'une nouvelle application située à <http://localhost/gitorial/>.
|
||||
|
||||
En utilisant votre console, placez vous dans le répertoire `gitorial` et exécutez `git init`. Cela créera la structure du dépôt git.
|
||||
|
||||
Ensuite, nous allons créér un [sous-module](http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html) pour le répertoire `system`. Allez à l'URL <http://github.com/kohana/core> et copiez l'URL de clonage:
|
||||
|
||||

|
||||
|
||||
Maintenant utilisez cette URL pour créér le sous-module `system`:
|
||||
|
||||
~~~
|
||||
git submodule add git://github.com/kohana/core.git system
|
||||
~~~
|
||||
|
||||
[!!] Cela créera un lien vers la version stable en développement. La version stable en développement est sûre à utiliser pour vos environnements de production et possède la même API que la version stable en téléchargement à laquelle sont ajoutés les correctifs de bugs.
|
||||
|
||||
A partir de là vous pouvez ajouter les modules que vous souhiatez, par exemple le module [Base de données](http://github.com/kohana/database):
|
||||
|
||||
~~~
|
||||
git submodule add git://github.com/kohana/database.git modules/database
|
||||
~~~
|
||||
|
||||
Une fois les sous-modules ajoutés, vous devez les initialiser:
|
||||
|
||||
~~~
|
||||
git submodule init
|
||||
~~~
|
||||
|
||||
Enfin il faut les commiter:
|
||||
|
||||
~~~
|
||||
git commit -m 'Added initial submodules'
|
||||
~~~
|
||||
|
||||
L'étape suivante consiste en la création de la structure des répertoires de votre application kohana. Le minimum requis est:
|
||||
|
||||
~~~
|
||||
mkdir -p application/classes/{controller,model}
|
||||
mkdir -p application/{config,views}
|
||||
mkdir -m 0777 -p application/{cache,logs}
|
||||
~~~
|
||||
|
||||
Si vous lancez la commande linux `find application` vous devez voir:
|
||||
|
||||
~~~
|
||||
application
|
||||
application/cache
|
||||
application/config
|
||||
application/classes
|
||||
application/classes/controller
|
||||
application/classes/model
|
||||
application/logs
|
||||
application/views
|
||||
~~~
|
||||
|
||||
Puisque l'on ne souhaite pas que les changements sur les logs et les mises en cache soient pris en compte, il faut ajouter un fichier `.gitignore` à chacun de ces répertoires. Cela aura pour effet d'ignorer tous les fichiers non cachés du répertoire:
|
||||
|
||||
~~~
|
||||
echo '[^.]*' > application/{logs,cache}/.gitignore
|
||||
~~~
|
||||
|
||||
[!!] Git ignore les répertoires vides, donc le fait d'ajouter le fichier `.gitignore` vous assure que git prendra en compte le répertoire mais pas les fichiers qu'il contient.
|
||||
|
||||
Ensuite il faut récupérer les fichiers `index.php` et `bootstrap.php`:
|
||||
|
||||
~~~
|
||||
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
|
||||
~~~
|
||||
|
||||
Commiter tous les changements:
|
||||
|
||||
~~~
|
||||
git add application
|
||||
git commit -m 'Added initial directory structure'
|
||||
~~~
|
||||
|
||||
C'est tout! Vous avez désormais une application gérée sous Git.
|
||||
|
||||
## Mettre à jour les sous-modules
|
||||
|
||||
Tôt ou tard vous allez sûrement avoir besoin de mettre à jour vos sous-modules. Pour mettre à jour l'ensemble de vos sous-modules à la version la plus récente `HEAD`, entrez:
|
||||
|
||||
~~~
|
||||
git submodule foreach
|
||||
~~~
|
||||
|
||||
Pour mettre à jour un seul sous-module, par exemple `system`, entrez:
|
||||
|
||||
~~~
|
||||
cd system
|
||||
git checkout master
|
||||
git fetch
|
||||
git merge origin/master
|
||||
cd ..
|
||||
git add system
|
||||
git commit -m 'Updated system to latest version'
|
||||
~~~
|
||||
|
||||
Enfin si vous souhaitez mettre à jour un sous-module par rapport à une révision particulière, entrez:
|
||||
|
||||
~~~
|
||||
cd modules/database
|
||||
git fetch
|
||||
git checkout fbfdea919028b951c23c3d99d2bc1f5bbeda0c0b
|
||||
cd ../..
|
||||
git add database
|
||||
git commit -m 'Updated database module'
|
||||
~~~
|
||||
|
||||
|
@@ -1,103 +0,0 @@
|
||||
# Hello, World
|
||||
|
||||
Tout framework digne de ce nom possède un exemple d'application "Hello World", alors ne dérogeons pas à la régle!
|
||||
|
||||
On commencera donc par décrire un "hello word" très très basique puis on détaillera les principes MVC appliqués à l'exemple.
|
||||
|
||||
## Au commencement il n'y avait rien...
|
||||
|
||||
La première chose à faire est de créer un controleur de telle sorte que Kohana puisse traiter une requête.
|
||||
|
||||
Créér le fichier `application/classes/controller/hello.php` dans votre répertoire application et ajoutez-y le code suivant:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No Direct Script Access');
|
||||
|
||||
Class Controller_Hello extends Controller
|
||||
{
|
||||
function action_index()
|
||||
{
|
||||
echo 'hello, world!';
|
||||
}
|
||||
}
|
||||
|
||||
Voyons ce que signifient ces quelques lignes:
|
||||
|
||||
`<?php defined('SYSPATH') OR die('No Direct Script Access');`
|
||||
: Vous devez sûrement reconnâitre le tag d'ouverture php (si ce n'est pas le cas alors il vous faut d'abord probablement vous [familiariser avec php](http://php.net)). Ce qui suit est un test permettant de s'assurer que le fichier est bien inclus par Kohana et lui seul. Cela permet d'interdire tout accès au fichier directement depuis une URL.
|
||||
|
||||
`Class Controller_Hello extends Controller`
|
||||
: Cette ligne déclare notre controleur, chaque controleur doit être préfixé de `Controller_` et exprime un chemin vers le fichier ci-dessus où les répertoires sont séparés par des underscores (voir [Conventions et styles](about.conventions) pour plus d'informations). Chaque contrôleur doit hériter du controleur de base `Controller` qui fournit la structure standard de tout controleur.
|
||||
|
||||
`function action_index()`
|
||||
: Cette ligne définit l'action "index" de notre controleur. Kohana essaiera d'appeler cette méthode si l'utilisateur n'en a spécifié aucune. (Voir [Routes, URLs et Liens](tutorials.urls))
|
||||
|
||||
`echo 'hello, world!';`
|
||||
: Enfin cette dernière ligne magique affichera sous vos yeux ébahis le message souhaité!
|
||||
|
||||
Une fois le controleur créé, ouvrez voter navigateur préféré et rendez-vous à l'adresse `http://loaclhost/kohana/index.php/hello` et constatez le résultat:
|
||||
|
||||

|
||||
|
||||
## C'était pas mal, mais on peut faire mieux
|
||||
|
||||
Le chapitre précédent présente à quel point il est facile de créer une application extrêmement basique avec Kohana. Jusque-là tout va bien.
|
||||
|
||||
Si vous avez déjà entendu parler du concept MVC alors vous vous disez sans doute qu'afficher du contenu dans un controleur va à l'encontre du principe MVC.
|
||||
|
||||
La manière appropriée de coder avec un framework MVC est d'utiliser des _vues_ pour tout ce qui est lié à la présentation/forme de votre application et de laisser au controleur l'enchainement logique du traitement des requêtes.
|
||||
|
||||
Changeons donc le controleur:
|
||||
|
||||
<?php defined('SYSPATH') OR die('No Direct Script Access');
|
||||
|
||||
Class Controller_Hello extends Controller_Template
|
||||
{
|
||||
public $template = 'site';
|
||||
|
||||
function action_index()
|
||||
{
|
||||
$this->template->message = 'hello, world!';
|
||||
}
|
||||
}
|
||||
|
||||
`extends Controller_Template`
|
||||
: nous héritons désormais du controleur template qui rend plus facile l'utilisation de vues au sein d'un controleur.
|
||||
|
||||
`public $template = 'site';`
|
||||
: le controleur template doit connaitre le template que vous souhaitez utiliser. Il chargera alors automatiquement la vue en question et lui assignera l'objet Vue créé.
|
||||
|
||||
`$this->template->message = 'hello, world!';`
|
||||
: `$this->template` est une référence vers l'objet Vue du template de notre site. Ce que l'on fait ici est assigner à la vue la variable "message" dont la valeur est "hello, world!".
|
||||
|
||||
Maintenant actualisez votre navigateur...
|
||||
|
||||
<div>{{userguide/examples/hello_world_error}}</div>
|
||||
|
||||
Kohana vous affiche une erreur au lieu du message fascinant qu'il devrait afficher. En regardant de plus près le message d'erreur on peut voir que la librairie View n'a pas été capable de trouver notre template, probablement parceque nous ne l'avons pas encore créé!
|
||||
|
||||
Créons donc notre vue en créant le fichier `application/views/site.php` avec le texte suivant:
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>We've got a message for you!</title>
|
||||
<style type="text/css">
|
||||
body {font-family: Georgia;}
|
||||
h1 {font-style: italic;}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1><?php echo $message; ?></h1>
|
||||
<p>We just wanted to say it! :)</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Maintenant si vous ré-actualisez, vous devriez voir apparaitre ce qu'il faut:
|
||||
|
||||

|
||||
|
||||
## A moi la gloire et l'argent!
|
||||
|
||||
Dans ce tutorial on a abordé comment créer un controleur et utiliser une vue pour séparer la logique de la présentation.
|
||||
|
||||
Evidemment l'exemple choisi est une introduction basique à Kohana et n'effleure même pas les possibilités infinies de Kohana ;).
|
@@ -1,121 +0,0 @@
|
||||
# ORM {#top}
|
||||
|
||||
Kohana 3.0 inclus un module [ORM](http://en.wikipedia.org/wiki/Object-relational_mapping) puissant utilisant le pattern active record et l'introspection de base de données pour déterminer les informations sur les colonnes d'un modèle.
|
||||
|
||||
Bien que le module ORM soit inclus par défaut dans vos installations de Kohana 3.0, il est désactivé par défaut. Pour l'activer modifiez le fichier `application/bootstrap.php` et ajoutez à l'appel [Kohana::modules] le module ORM:
|
||||
|
||||
Kohana::modules(array(
|
||||
...
|
||||
'orm' => MODPATH.'orm',
|
||||
...
|
||||
));
|
||||
|
||||
## Configuration {#configuration}
|
||||
|
||||
Pour pouvoir utiliser l'ORM, il faut tout d'abord faire hériter vos modèles de la classe ORM comme suit:
|
||||
|
||||
class Model_User extends ORM
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
Dans l'exemple ci-dessus, le modele cherchera une table `users` dans la base de données par défaut.
|
||||
|
||||
### Propriétés d'un modèle ORM
|
||||
|
||||
Les propriétés suivantes peuvent être utilisées pour configurer chacuns de vos modèles:
|
||||
|
||||
Type | Option | Description | Valeur par défaut
|
||||
----------|-----------------|--------------------------------------| -------------------------
|
||||
`string` | _table_name | Nom de la table |
|
||||
`string` | _db | Nom de la base de données |`default`
|
||||
`string` | _primary_key | Colonne contenant la clé primaire |`id`
|
||||
`string` | _primary_val | Colonne contenant la valeur primaire |`name`
|
||||
|
||||
## Utiliser l'ORM
|
||||
|
||||
### Charger un enregistrement
|
||||
|
||||
Pour créér une instance d'un modèle, il faut utiliser la méthode [ORM::factory] ou passer directement par le constructeur:
|
||||
|
||||
$user = ORM::factory('user');
|
||||
// ou
|
||||
$user = new Model_User();
|
||||
|
||||
Les 2 méthodes ci-dessus peuvent prendre en argument la valeur de la clé primaire de l'élément que l'on souhaite charger:
|
||||
|
||||
// Charge l'utilisateur d'ID 5
|
||||
$user = ORM::factory('user', 5);
|
||||
|
||||
[ORM::loaded] permet de savoir si un modèle donné a été chargé avec succès.
|
||||
|
||||
### Rechercher un enregistrement
|
||||
|
||||
L'ORM supporte la plupart des méthodes [Base de données](tutorials.databases) pour affiner les recherches sur les données du modèle. Pour avoir une liste complète, référez vous à la propriété `_db_methods`. Les enregistrements sont récupérés lors de l'appel à [ORM::find] ou [ORM::find_all].
|
||||
|
||||
// Le code ci-dessous récupère le premier utilisateur actif prénommé Bob
|
||||
$user = ORM::factory('user')
|
||||
->where('active', '=', TRUE)
|
||||
->where('name', '=', 'Bob')
|
||||
->find();
|
||||
|
||||
// Le code ci-dessous récupère tous les utilisateur actifs Bob
|
||||
$users = ORM::factory('user')
|
||||
...
|
||||
->find_all();
|
||||
|
||||
Lors de la récupération d'une liste de modèles par la méthode [ORM::find_all], le parcours des éléments se fait comme pour les résultats de base de données:
|
||||
|
||||
foreach ($users as $user)
|
||||
{
|
||||
...
|
||||
}
|
||||
|
||||
### Accès aux propriétés d'un Modèle
|
||||
|
||||
Toutes les propriétés d'un modèle sont accessibles en utilisant les méthodes magiques `__get` et `__set`.
|
||||
|
||||
$user = ORM::factory('user', 5);
|
||||
|
||||
// Affiche le nom de l'utilisateur
|
||||
echo $user->name;
|
||||
|
||||
// Change le nom de l'utilisateur
|
||||
$user->name = 'Bob';
|
||||
|
||||
Pour stocker des informations/propriétés qui n'ont pas de correspondances dans la table (c'est-à-dire aucune colonnes du même nom que la propriété), il faut utiliser la propriété `_ignored_columns`:
|
||||
|
||||
class Model_User extends ORM
|
||||
{
|
||||
...
|
||||
protected $_ignored_columns = array('field1', 'field2', ...)
|
||||
...
|
||||
}
|
||||
|
||||
### Créér et sauvegarder des enregistrements
|
||||
|
||||
La méthode [ORM::save] est utilisée aussi bien pour créer et sauvegarder de nouveaux enregistrements que pour mettre à jour des enregistrements existants.
|
||||
|
||||
// Création d'un enregistrement
|
||||
$user = ORM::factory('user');
|
||||
$user->name = 'New user';
|
||||
$user->save();
|
||||
|
||||
// Mise à jour d'un enregistrement
|
||||
$user = ORM::factory('user', 5);
|
||||
$user->name = 'User 2';
|
||||
$user->save();
|
||||
|
||||
Vous pouvez mettre à jour plusieurs enregistrements à la fois en utilisant la méthode [ORM::save_all]:
|
||||
|
||||
$user = ORM::factory('user');
|
||||
$user->name = 'Bob';
|
||||
|
||||
// Change le nom de tous les utilisateurs actifs à Bob
|
||||
$user->where('active', '=', TRUE)->save_all();
|
||||
|
||||
[ORM::saved] permet de vérifier si le modèle a bien été sauvegardé.
|
||||
|
||||
### Supprimer des enregistrements
|
||||
|
||||
La suppression d'enregistrements se fait avec [ORM::delete] et [ORM::delet_all]. Ces méthodes fonctionnement de manière similaire à celles de sauvegarde détaillées plus haut à l'exception du fait que [ORM::delete] peut prendre en argument l'`id` de l'enregistrment à supprimer.
|
@@ -1,163 +0,0 @@
|
||||
# Routes, URLs et Liens
|
||||
|
||||
Ce chapitre fournit les bases permettant de comprendre la logique de traitement des requêtes, de la génération des URLs et des liens.
|
||||
|
||||
## Routage
|
||||
|
||||
Comment évoqué dans le chapitre [processus de traitement des requêtes](about.flow), une requête est traitée par la classe [Request] qui tente de trouver une [Route] correspondante et charge les méthodes appropriées du controleur qui permettront de traiter la requete.
|
||||
|
||||
Si vous regardez le fichier `APPPATH/bootstrap.php` vous pouvez voir le code ci-dessous qui est exécuté juste avant que la requête ne soit traitée par [Request::instance]:
|
||||
|
||||
Route::set('default', '(<controller>(/<action>(/<id>)))')
|
||||
->defaults(array(
|
||||
'controller' => 'welcome',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
Ce code crée une route appelée `default` dont l'URI doit avoir le format `(<controller>(/<action>(/<id>)))`. Les éléments entourés par `<>` sont des *clés* et ceux entourés par `()` définissent les parties *optionnelles* de l'URI. Dans le code ci-dessus , l'URI entière est optionnelles ce qui signifie que même une URI vide serait traitée en utilisant les valeurs par défaut spécifiées dans la route. Cela se traduirait par le chargement de la classe `Controller_Welcome` et l'exécution de sa méthode `action_index` pour traiter la requête.
|
||||
|
||||
A noter que les routes de Kohana peuvent contenir tous caractères exceptés `()<>`. Dans la route ci-dessus le caractère `/` est utilisé comme séparateur mais tant que l'expression matche l'URI demandée il n'y a aucune restriction sur le format des routes.
|
||||
|
||||
### Répertoires
|
||||
|
||||
Par soucis d'organisation, il est commun de vouloir organiser certains de vos controleurs dans des sous-répertoires. Par exemple pour grouper votre section d'administration (tout vos controleurs d'administration) de votre site dans un sous-répertoire admin:
|
||||
|
||||
Route::set('admin', 'admin(/<controller>(/<action>(/<id>)))')
|
||||
->defaults(array(
|
||||
'directory' => 'admin',
|
||||
'controller' => 'home',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
Cette route indique qu'il faut que l'URI commence obligatoirement par `admin` pour matcher. Le sous-répertoire est statiquement assigné à `admin` dans les paramètres par défaut. De cette manière, la requête `admin/users/create` chargera la classe `Controller_Admin_Users` et appellera la méthode `action_create`.
|
||||
|
||||
### Expressions régulières
|
||||
|
||||
Le système de routage de Kohana utilise des expressions régulière compatible Perl. Par défaut les clés (entourées par `<>`) sont matchées par l'expression `[a-zA-Z0-9_]++` mais vous pouvez définir vos propres expressions pour chacunes des clés en passant un tableau associatif de clés et d'expressions comme paramètre additionnel de la méthode [Route::set].
|
||||
|
||||
Par exemple, imaginons qu'en plus d'une section administration, votre site contient une section blog dont les controleurs sont situés dans un sous-répertoire blog. Alors vous pouvez soit écrire 2 routes distinctes ou bien tout simplement faire:
|
||||
|
||||
Route::set('sections', '<directory>(/<controller>(/<action>(/<id>)))',
|
||||
array(
|
||||
'directory' => '(admin|blog)'
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'home',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
Cette route vous permet donc d'avoir 2 sections, 'admin' et 'blog' et d'organiser les controleurs dans des sous-répertoires distincts.
|
||||
|
||||
### Exemples de routes
|
||||
|
||||
Les possibilités sont bien sûres infinies, néanmoins voici quelques exemples courants:
|
||||
|
||||
/*
|
||||
* Raccourcis d'authentification
|
||||
*/
|
||||
Route::set('auth', '<action>',
|
||||
array(
|
||||
'action' => '(login|logout)'
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'auth'
|
||||
));
|
||||
|
||||
/*
|
||||
* Feeds multi-formats
|
||||
* 452346/comments.rss
|
||||
* 5373.json
|
||||
*/
|
||||
Route::set('feeds', '<user_id>(/<action>).<format>',
|
||||
array(
|
||||
'user_id' => '\d+',
|
||||
'format' => '(rss|atom|json)',
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'feeds',
|
||||
'action' => 'status',
|
||||
));
|
||||
|
||||
/*
|
||||
* Pages statiques
|
||||
*/
|
||||
Route::set('static', '<path>.html',
|
||||
array(
|
||||
'path' => '[a-zA-Z0-9_/]+',
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'static',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
/*
|
||||
* Vous n'aimez pas les slashes?
|
||||
* EditGallery:bahamas
|
||||
* Watch:wakeboarding
|
||||
*/
|
||||
Route::set('gallery', '<action>(<controller>):<id>',
|
||||
array(
|
||||
'controller' => '[A-Z][a-z]++',
|
||||
'action' => '[A-Z][a-z]++',
|
||||
))
|
||||
->defaults(array(
|
||||
'controller' => 'Slideshow',
|
||||
));
|
||||
|
||||
/*
|
||||
* Recherche rapide
|
||||
*/
|
||||
Route::set('search', ':<query>', array('query' => '.*'))
|
||||
->defaults(array(
|
||||
'controller' => 'search',
|
||||
'action' => 'index',
|
||||
));
|
||||
|
||||
Les Routes sont évaluées dans l'odre dans lequel elles sont définies. C'est pour cette raison que la route par défaut est définie à la fin de sorte que les routes spécifiques soient testées avant.
|
||||
|
||||
De plus cela implique qu'il faut faire attention si vous définissez des routes après le chargement des modules, car les routes incluses dans ceux-ci pourrait entrer en conflit.
|
||||
|
||||
### Paramétres des requêtes
|
||||
|
||||
Le répertoire (directory), le controleur (controller) et l'action sont accessibles à travers l'instance [Request] d'une des 2 manières suivantes:
|
||||
|
||||
$this->request->action;
|
||||
Request::instance()->action;
|
||||
|
||||
Toutes les autres clés spécifiées dans vos routes sont accessibles en utilisant:
|
||||
|
||||
$this->request->param('key_name');
|
||||
|
||||
La méthode [Request::param] peut prendre un second paramètre optionnel permettant de spécifier une valeur par défaut à retourner au cas où la clé n'est pas affectée par la route. Si aucun argument n'est passé, toutes les clés sont passés sous forme d'un tableau associatif.
|
||||
|
||||
### Convention
|
||||
|
||||
La convention est de placer toutes vos routes dans le fichier `MODPATH/<module>/init.php` si elles concernent un module et sinon, si elles sont spécifiques à l'application, il faut tout simplement les ajouter au fichier `APPPATH/bootstrap.php` au-dessus de la route par défaut. Bien sûr cela ne vous empêche pas de les inclure depuis un fichier externe ou de les générer dynamiquement.
|
||||
|
||||
## URLs
|
||||
|
||||
Outre les capacités puissantes de gestion des routes de Kohana, Kohana fournit aussi des méthodes de génération d'URLs pour vos routes. Vous pouvez bien sûr spécifier des URIs en utilisant [URL::site] pour créer une URL complète:
|
||||
|
||||
URL::site('admin/edit/user/'.$user_id);
|
||||
|
||||
Cependant, Kohana fournit aussi une méthode permettant de générer les URIs à partir de la définition des routes que vous avez écrites. C'est extrêmement utile si vos routes sont amenées à changer car vous n'aurez pas à remodifier votre code partout où vous avez spécifié des URIs comme ci-dessus. Voici un exemple de génération dynamique qui correspond à la route `feeds` définie dans la liste d'exemples plus haut:
|
||||
|
||||
Route::get('feeds')->uri(array(
|
||||
'user_id' => $user_id,
|
||||
'action' => 'comments',
|
||||
'format' => 'rss'
|
||||
));
|
||||
|
||||
Imaginez que plus tard vous décidez de changer la définition de la route en `feeds/<user_id>(/<action>).<format>`. Avec le code ci-dessus l'URI générée est toujours valide après ce changement! Lorsqu'une partie de l'URI est entourée de paranthèses et qu'elle représente une clé qui n'est pas fournie dans la génération de l'URI et qui n'a pas de valeur par défaut alors cette partie est enlevée de l'URI. C'est le cas de la partie `(/<id>)` de la route par défaut; elle ne sera pas incluse dans l'URI générée si l'id n'est pas fourni.
|
||||
|
||||
Une autre méthode pratique est [Request::uri] qui fait la même chose que la précédente méthode excepté qu'elle utilise la route courante. Si la route courante est la route par défaut dont l'URI est `users/list`, il est possible d'écrire le code suivant pour générer des URIs au format `users/view/$id`:
|
||||
|
||||
$this->request->uri(array('action' => 'view', 'id' => $user_id));
|
||||
|
||||
Au sein d'une vue il est préferrable d'utiliser:
|
||||
|
||||
Request::instance()->uri(array('action' => 'view', 'id' => $user_id));
|
||||
|
||||
## Liens
|
||||
|
||||
[!!] links stub
|
@@ -1,18 +0,0 @@
|
||||
# Autoloading - טעינה אוטומטית
|
||||
|
||||
Kohana יודע לנצל את יכולת הטעינה אוטומטית של PHP [autoloading](http://php.net/manual/language.oop5.autoload.php).
|
||||
עובדה זו מבטלת את הצורך בשימוש ב [include](http://php.net/include) או [require](http://php.net/require) לפני השימוש בבקר.
|
||||
|
||||
הבקרים (Classes) נטענים על ידי מטודת [Kohana::auto_load], אשר יודעת לעשות את ההמרה משם בקר לשם קובץ:
|
||||
|
||||
1. בקרים צריכים להיות ממוקמים בתוך תקיית `classes/` השייכים ל [filesystem](about.filesystem)
|
||||
2. כל קו תחתי בשם הבקר יהפוך לסלאש '/' ויחפש בתת תקיות בהתאם
|
||||
3. שם הקובץ צריך להיות כתוב באותיות קטנות
|
||||
|
||||
כאשר קוראים לבקר שלא נטען (לדוגמא: `Session_Cookie`) קוהנה תחפש בעזרת פקודת [Kohana::find_file] את הקובץ `classes/session/cookie.php`.
|
||||
|
||||
## Custom Autoloaders - טעינה אוטומטית מותאמת אישית
|
||||
|
||||
[!!] הגדרת ברירת המחדל של הטעינה האוטומטית נמצאת בקובץ `application/bootstrap.php`.
|
||||
|
||||
בקרים נוספים ניתן להוסיף ע"י שימוש ב [spl_autoload_register](http://php.net/spl_autoload_register).
|
@@ -1,99 +0,0 @@
|
||||
# General Configuration - הגדרות כלליות
|
||||
|
||||
[!!] Finish translating... (todo: description of benefits of static properties for configuration)
|
||||
|
||||
## Core Configuration - הגדרות בסיסיות
|
||||
|
||||
ההגדרה הראשונה אותה יש לבצע בכל התקנה של קוהנה היא שינוי ההגדרות של [Kohana::init] ב `application/bootstrap.php`.
|
||||
ההגדרות הן:
|
||||
|
||||
שגיאות:
|
||||
האם להשתמש בטיפול שגיאות ויוצאי דופן פנימי של הקוהנה
|
||||
ערך ברירת מחדל - True, יש לשנות ל FLASE במידה ולא מעוניינים
|
||||
|
||||
פרופיל:
|
||||
האם להשתמש בדף הפרופיל הסטטיסטי
|
||||
ערך ברירת מחדל - True
|
||||
יש לשנות ל FALSE במידה ולא מעוניינים - מומלץ שלא להשתמש באפשרות זו בגרסה הסופית על מנת להסתיר מידע רגיש וטעינה מהירה יותר של הדפים
|
||||
|
||||
caching - זכרון מטמון
|
||||
האם לשמור בזכרון מטמון את המיקום של הקבצים בין בקשות?
|
||||
ערך ברירת מחדל - True, יש לשנות ל FALSE במידה ולא מעוניינים
|
||||
פעולה זו מגבירה באופן דרמטי את מהירות הטעינת דפים [Kohana::find_file] ולכן יכולה להיות בעלת השפעה גדולה על רמת הביצועים הכללית של האפליקציה.
|
||||
חשוב להשתמש באופצייה זו רק בגרסה הסופית או בשביל נסיונות.
|
||||
|
||||
`string` charset
|
||||
: Character set used for all input and output. (Default `"utf-8"`) Should be a character set that is supported by both [htmlspecialchars](http://php.net/htmlspecialchars) and [iconv](http://php.net/iconv).
|
||||
|
||||
`string` base_url
|
||||
: Base URL for the application. (Default `"/"`) Can be a complete or partial URL. For example "http://example.com/kohana/" or just "/kohana/" would both work.
|
||||
|
||||
`string` index_file
|
||||
: The PHP file that starts the application. (Default `"index.php"`) Set to `FALSE` when you remove the index file from the URL with URL rewriting.
|
||||
|
||||
`string` cache_dir
|
||||
: Cache file directory. (Default `"application/cache"`) Must point to a **writable** directory.
|
||||
|
||||
## Cookie Settings
|
||||
|
||||
There are several static properties in the [Cookie] class that should be set, particularly on production websites.
|
||||
|
||||
`string` salt
|
||||
: Unique salt string that is used to enable [signed cookies](security.cookies)
|
||||
|
||||
`integer` expiration
|
||||
: Default expiration lifetime in seconds
|
||||
|
||||
`string` path
|
||||
: URL path to restrict cookies to be accessed
|
||||
|
||||
`string` domain
|
||||
: URL domain to restrict cookies to be accessed
|
||||
|
||||
`boolean` secure
|
||||
: Only allow cookies to be accessed over HTTPS
|
||||
|
||||
`boolean` httponly
|
||||
: Only allow cookies to be accessed over HTTP (also disables Javascript access)
|
||||
|
||||
# Configuration Files
|
||||
|
||||
Configuration is done in plain PHP files, which look similar to:
|
||||
|
||||
~~~
|
||||
<?php defined('SYSPATH') or die('No direct script access.');
|
||||
|
||||
return array(
|
||||
'setting' => 'value',
|
||||
'options' => array(
|
||||
'foo' => 'bar',
|
||||
),
|
||||
);
|
||||
~~~
|
||||
|
||||
If the above configuration file was called `myconf.php`, you could acess it using:
|
||||
|
||||
~~~
|
||||
$config = Kohana::config('myconf');
|
||||
$options = $config['options'];
|
||||
~~~
|
||||
|
||||
[Kohana::config] also provides a shortcut for accessing individual keys from configuration arrays using "dot paths".
|
||||
|
||||
Get the "options" array:
|
||||
|
||||
~~~
|
||||
$options = Kohana::config('myconf.options');
|
||||
~~~
|
||||
|
||||
Get the "foo" key from the "options" array:
|
||||
|
||||
~~~
|
||||
$foo = Kohana::config('myconf.options.foo');
|
||||
~~~
|
||||
|
||||
Configuration arrays can also be accessed as objects, if you prefer that method:
|
||||
|
||||
~~~
|
||||
$options = Kohana::config('myconf')->options;
|
||||
~~~
|
@@ -1,18 +0,0 @@
|
||||
# Cascading Filesystem - מערכת קבצים מדורגת
|
||||
|
||||
מערכת הקבצים של Kohana בנוייה ממבנה בסיסי יחיד אשר משוכפל לכל התקיות הנמצאות בנתיב המכונה
|
||||
include path. להלן צורת המבנה:
|
||||
|
||||
1. application - אפליקציה
|
||||
2. modules, in order added - מודולים, לפי סדר ההופעה
|
||||
3. system - מערכת
|
||||
|
||||
קבצים הנמצאים בתקיות שמעל ה include path מקבלים קדימות על קבצים עם שם זהה, עובדה המאפשרת
|
||||
לטעון ולדרוס פעולות קבצים על ידי טעינה של קבצים זהים לקבצים הקיימים, רק במיקום גבוה יותר יחסית. לדוגמא:
|
||||
|
||||

|
||||
|
||||
אם יש מצב בו יש לנו קובץ מבט (view) בשם layout.php הממוקם בתקייה application/views וגם קיים בתקייה system/views
|
||||
הקובץ הממוקם בתקייה application יהיה זה שיוחזר ברגע שננסה לגשת ל layout.php
|
||||
בגלל שהוא נמצא גבוה יותר בסדר האינקלוד (include path order).
|
||||
ואם נמחוק את הקובץ הנמצא בתקייה application/views, אז הקובץ שיוחזר יהיה הקובץ השני שממוקם ב system/views.
|
@@ -1,22 +0,0 @@
|
||||
# Request Flow - זרימת תהליך בקשה מהשרת
|
||||
|
||||
כל אפליקציה שרצה על קוהנה עוברת תהליך זהה בעת ביצוע בקשה של טעינת דף מהשרת
|
||||
|
||||
1. האפליקציה נטענת ע"י הרצת הדף הראשי `index.php`
|
||||
2. מכלילה בתוכה את הדף `APPPATH/bootstrap.php`
|
||||
3. ה bootstrap קורא ל [Kohana::modules] עם רשימה של המודולים שבשימוש
|
||||
1. נוצר מערך עם הנתיבים של כל התקיות והקבצים המכילים את המודול
|
||||
2. בדיקה האם למודול יש קובץ init.php ובמידה וכן לטעון אותו
|
||||
* כל קובץ init.php יכול לכלול בתוכו routes (ניתובים) חדשים אשר נטענים למערכת
|
||||
4. [Request::instance] רץ על מנת לבצע את הקריאה
|
||||
1. בדיקה מול ה routes הקיימים על מנת למצוא את המתאים
|
||||
2. טעינה של בקר (controller) והעברת הבקשה אליו
|
||||
3. קריאה לפונקציה [Controller::before] של הבקר המתאים
|
||||
4. קריאה לפעולה של הבקר לפי ה route
|
||||
5. קריאה לפונקציה [Controller::after] של הבקר המתאים
|
||||
5. הצגה של התוצאה
|
||||
|
||||
|
||||
יש אפשרות לשנות את אופן פעולת הבקר עצמו על ידי הפונקציה [Controller::before] בהסתמך על המשתנים בבקשה
|
||||
|
||||
[!!] Stub
|
@@ -1,21 +0,0 @@
|
||||
# מה זה Kohana?
|
||||
|
||||
Kohana היא מערכת בקוד פתוח,
|
||||
[תשתית פיתוח לרשת](http://wikipedia.org/wiki/Web_Framework)
|
||||
[מונחה עצמים](http://wikipedia.org/wiki/Object-Oriented_Programming) [MVC](http://wikipedia.org/wiki/Model-View-Controller "Model View Controller")
|
||||
שנבנתה בשימוש עם
|
||||
[PHP5](http://php.net/manual/intro-whatis "PHP Hypertext Preprocessor")
|
||||
ע"י צוות מתנדבים שמטרתה להיות מהירה, מאובטחת, וקטנה.
|
||||
|
||||
[!!] Kohana רשומה תחת רישיון ה [BSD license](http://kohanaframework.org/license), אי לכך באפשרותך לעשות כל שימוש באם הוא קוד פתוח, מסחרי, או פרוייקט אישי בלי שום מגבלות משפטיות.
|
||||
|
||||
## מה עושה את Kohana כל-כך מצויין?
|
||||
|
||||
|
||||
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.
|
||||
|
||||
## המדריך הזה מעפן!
|
||||
|
||||
We are working very hard to provide complete documentation. If you are having trouble finding an answer, check the [unofficial wiki](http://kerkness.ca/wiki/doku.php). If you would like to add or change something in the guide, please [fork the userguide](http://github.com/kohana/userguide), make your changes, and send a pull request. If you are not familar with git, you can also submit a [feature request](http://dev.kohanaframework.org/projects/kohana3/issues) (requires registration).
|
@@ -1,29 +0,0 @@
|
||||
# מודל Model View Controller
|
||||
|
||||
תבנית Model-View-Controller (בקיצור MVC) היא תבנית עיצוב בהנדסת תוכנה המשמשת להפשטת יישום כלשהו. התבנית מתארת טכניקה לחלוקת היישום לשלושה חלקים, מודל, מבט ובקר, המחוברים ביניהם בצימוד רפוי מונחה אירועים. בדרך זו, התלות הדדית בין ממשק המשתמש לשאר חלקי התוכנה פוחתת, ואת החלקים השונים ניתן לפתח באופן בלתי-תלוי. בנוסף, קל יותר לתחזק את התוכנה וכן לעשות שימוש חוזר בחלקי היישום שהופרדו.
|
||||
|
||||
#תיאור התבנית
|
||||
|
||||
מקובל לחלק יישום תוכנה למספר שכבות נפרדות: שכבת התצוגה (ממשק משתמש), שכבת התחום העסקי (לעתים נקראת גם "שכבת הלוגיקה העסקית") ושכבת הגישה לנתונים. בתבנית MVC, שכבת התצוגה מחולקת בנוסף למבט ובקר. יש המחשיבים את התבנית כתבנית עיצוב, אך בהשוואה לתבניות עיצוב אחרות, MVC עוסקת במבנים בקנה מידה בינוני-גדול ולכן נחשבת גם כתבנית ארכיטקטורה.
|
||||
|
||||
מודל
|
||||
המודל הוא יצוג מסוים, מוכוון תחום עסקי, של המידע עליו פועל היישום. המודל, למרות הדעה הרווחת, אינו שם אחר לשכבת התחום העסקי והוא נפרד ממנה. תבנית MVC אינה מזכירה במפורש את שכבת הגישה לנתונים, מכיוון ששכבה זו היא מתחת למודל, או נעטפת על ידו.
|
||||
|
||||
מבט
|
||||
תפקידו להמיר את נתוני המודל לייצוג המאפשר למשתמש לבצע פעולת גומלין כלשהי. לרוב מדובר על המרה לממשק משתמש כלשהו. תבנית MVC משמשת רבות ביישומי Web, בהם המבט הוא דף HTML והקוד האוסף מידע דינמי לדף.
|
||||
|
||||
בקר
|
||||
תפקידו לעבד ולהגיב לאירועים המתרחשים במבט, לרוב, כתגובה לפעולה של המשתמש. בעיבוד האירועים, הבקר עשוי לשנות את המידע במודל, באמצעות שפעול שירותים המוגדרים בו. בקרים מורכבים מתבססים לרוב על יישום של תבנית Command.
|
||||
|
||||
|
||||
#אופן הפעולה
|
||||
|
||||
ניתן ליישם את תבנית העיצוב MVC בדרכים רבות, אך לרוב היא מיושמת כך:
|
||||
|
||||
- הבקר נרשם כ-Event Handler או Callback במבט, בדרך כלל סמוך ליצירת הבקר. כלומר, יישום של שיטת היפוך הפיקוח (IoC). משמע, הבקר יקבל פיקוח כאשר יתרחש אירוע קלט בממשק המשתמש.
|
||||
- המשתמש מבצע פעולת גומלין כלשהי עם הממשק. לדוגמה, מקליק על כפתור 'הוסף מוצר לעגלה'.
|
||||
- הבקר שנרשם על המבט מקבל פיקוח ומשפעל שירותים המוגדרים במודל, כדי לשקף את הפעולה שביצע המשתמש. לדוגמה, עדכון 'עגלת הקניות' של המשתמש בפריט נוסף.
|
||||
- המבט מקבל בצורה עקיפה את החוכמת התצוגה שלו מהבקר, בדרך כלל באמצעות יישום של תבנית Strategy.
|
||||
- המבט משתמש במודל כדי ליצור את ממשק המשתמש. לדוגמה, המבט מפיק רשימה של הפריטים בעגלה, כפי שאלה מיוצגים כרגע במודל. בין השניים אין קשר הדוק, והמודל אינו מודע לכך שהמבט ניגש למידע המאוחסן בו.
|
||||
- לעתים, המודל עשוי להודיע על שינויים המתחוללים בו לצדדים שלישיים נוספים, בדרך כלל באמצעות יישום של תבנית Observer.
|
||||
- ממשק המשתמש ממתין לפעולות נוספות של המשתמש, וכשאלה מתרחשות, התהליך חוזר על עצמו.
|
@@ -1,24 +0,0 @@
|
||||
# Debugging - דיבוג
|
||||
|
||||
קוהנה כוללת מספר כלים חזקים על מנת לעזור לך לדבג את האפליקציה שלך.
|
||||
הכלי הבסיסי הוא [Kohana::debug].
|
||||
כלי זה יציג את כל המשתנים או משתנה מסויים מכל סוג שהוא, בדומה ל [var_export](http://php.net/var_export) או [print_r](http://php.net/print_r), רק שקוהנה יודעת להשתמש ב HTML להצגה נוחה יותר
|
||||
|
||||
~~~
|
||||
// הצג נתונים אודות המשתנים $foo ו- $bar
|
||||
echo Kohana::debug($foo, $bar);
|
||||
~~~
|
||||
|
||||
קוהנה גם מאפשרת בקלות לצפות בקוד המקור של קובץ מסויים ע"י שימוש ב [Kohana::debug_source].
|
||||
|
||||
~~~
|
||||
// הצגה של שורה מסויימת מקובץ מסויים
|
||||
echo Kohana::debug_source(__FILE__, __LINE__);
|
||||
~~~
|
||||
|
||||
במידה ואתה מעוניין להציג מידע על האפליקציה מבלי לחשוף את התקיית התקנה, ניתן להשתמש ב [Kohana::debug_path]:
|
||||
|
||||
~~~
|
||||
// מציג "APPPATH/cache" במקום הנתיב האמיתי
|
||||
echo Kohana::debug_file(APPPATH.'cache');
|
||||
~~~
|
@@ -1,29 +0,0 @@
|
||||
# Error/Exception Handling - טיפול בשגיאות וחריגים
|
||||
|
||||
Kohana מאפשרת לנו טיפול נוח בשגיאות וחריגים על ידי הפיכת השגיאות לחריגים בעזרת ה
|
||||
[ErrorException](http://php.net/errorexception) של PHP.
|
||||
Kohana יודעת להציג נתונים רבים אודות השגיאות והחריגים שזיהתה:
|
||||
|
||||
1. Exception class -
|
||||
2. Error level - רמת השגיאה
|
||||
3. Error message - הודעת שגיאה
|
||||
4. Source of the error, with the error line highlighted - מקור השגיאה עם סימון השורה הבעייתית
|
||||
5. A [debug backtrace](http://php.net/debug_backtrace) of the execution flow - אפשרות מעקב אחורנית אודות הקריאות השונות שבוצעו עד לקבלת השגיאה על מנת לעקוב לאחור אחר מקור השגיאה
|
||||
6. Included files, loaded extensions, and global variables - קבצים שנכללו, סיומות שנטענו ומשתנים גלובאלים
|
||||
|
||||
## דוגמא להודעת שגיאה
|
||||
|
||||
לחץ על אחד הקישורים הממוספרים על מנת להציג או להסתיר את המידע הנוסף
|
||||
|
||||
<div>{{userguide/examples/error}}</div>
|
||||
|
||||
## Disabling Error/Exception Handling - ביטול הטיפול בשגיאות וחריגים
|
||||
|
||||
במידה וברצונך לבטל את הטיפול בשגיאות, ניתן לעשות זאת בעת הקריאה
|
||||
[Kohana::init] בצורה הבאה:
|
||||
|
||||
~~~
|
||||
Kohana::init(array('errors' => FALSE));
|
||||
~~~
|
||||
|
||||
חשוב לזכור שבדרך כלל נרצה שהשגיאות המפורטות יופיעו רק בעבודה לוקאלית ולא באתר אונליין
|
@@ -1,21 +0,0 @@
|
||||
# Profiling - פרופיל סטטיסטי לכל דף
|
||||
|
||||
קוהנה מאפשרת בקלות לצפות בסטטיסטיקה אודות האפליקציה:
|
||||
|
||||
1. קריאות למטודות קוהנה
|
||||
2. בקשות
|
||||
3. שאילתות שבוצעו על מסד הנתונים
|
||||
4. ממוצע זמני פעולה של האפליקציה
|
||||
|
||||
## דוגמא
|
||||
|
||||
ניתן לאסוף ולהציג את הסטטיסטיקות בכל רגע נתון:
|
||||
~~~
|
||||
<div id="kohana-profiler">
|
||||
<?php echo View::factory('profiler/stats') ?>
|
||||
</div>
|
||||
~~~
|
||||
|
||||
## התוצאה:
|
||||
|
||||
{{profiler/stats}}
|
@@ -1,26 +0,0 @@
|
||||
1. **מתחילים**
|
||||
- [ מה זה Kohana?](about.kohana)
|
||||
- [מוסכמות וסיגנון](about.conventions)
|
||||
- [התקנה](about.install)
|
||||
- [שידרוג](about.upgrading)
|
||||
- [הגדרות](about.configuration)
|
||||
- [Model View Controller הסבר על](about.mvc)
|
||||
- [מערכת קבצים](about.filesystem)
|
||||
- [Autoloading - טעינה אוטומטית](about.autoloading)
|
||||
- [Request זרימת](about.flow)
|
||||
- [API דפדפן](api)
|
||||
2. **ערכות לימוד**
|
||||
- [Hello, World](tutorials.helloworld)
|
||||
- [Routes, URLs, and Links](tutorials.urls)
|
||||
- [Databases](tutorials.databases)
|
||||
- [ORM](tutorials.orm)
|
||||
- [עבודה עם Git](tutorials.git)
|
||||
3. **אבטחה**
|
||||
- [XSS](security.xss)
|
||||
- [Validation - ואלידציה](security.validation)
|
||||
- [Cookies - עוגיות](security.cookies)
|
||||
- [Database - מסד נתונים](security.database)
|
||||
4. **ניפוי באגים**
|
||||
- [קוד](debugging.code)
|
||||
- [טיפול בשגיאות](debugging.errors)
|
||||
- [פרופיל](debugging.profiling)
|
@@ -1,31 +0,0 @@
|
||||
1. **Getting Started**
|
||||
- [What is Kohana?](about.kohana)
|
||||
- [Conventions and Style](about.conventions)
|
||||
- [Model View Controller](about.mvc)
|
||||
- [Cascading Filesystem](about.filesystem)
|
||||
- [Request Flow](about.flow)
|
||||
- [Installation](about.install)
|
||||
- [Upgrading](about.upgrading)
|
||||
- [API Browser](api)
|
||||
3. **Basic Usage**
|
||||
- [Configuration](using.configuration)
|
||||
- [Loading Classes](using.autoloading)
|
||||
- [Views and HTML](using.views)
|
||||
- [Sessions and Cookies](using.sessions)
|
||||
- [Messages](using.messages)
|
||||
4. **Debugging**
|
||||
- [Code](debugging.code)
|
||||
- [Error Handling](debugging.errors)
|
||||
- [Profiling](debugging.profiling)
|
||||
5. **Security**
|
||||
- [XSS](security.xss)
|
||||
- [Validation](security.validation)
|
||||
- [Cookies](security.cookies)
|
||||
- [Database](security.database)
|
||||
6. **Tutorials**
|
||||
- [Hello, World](tutorials.helloworld)
|
||||
- [Routes, URLs, and Links](tutorials.urls)
|
||||
- [Clean URLs](tutorials.removeindex)
|
||||
- [Databases](tutorials.databases)
|
||||
- [ORM](tutorials.orm)
|
||||
- [Working with Git](tutorials.git)
|
@@ -1,316 +0,0 @@
|
||||
# Conventies
|
||||
|
||||
Het is aanbevolen om Kohana's [manier van coderen](http://dev.kohanaframework.org/wiki/kohana2/CodingStyle) te gebruiken. Dit gebruikt de [BSD/Allman stijl](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) van haakjes, en nog andere dingen.
|
||||
|
||||
## Class namen en locaties van bestanden {#classes}
|
||||
|
||||
Class namen in Kohana volgen een strikte conventie om [autoloading](using.autoloading) gemakkelijker te maken. Class namen zouden met een hoofdletter moeten beginnen en een underscore gebruiken om woorden af te scheiden van elkaar. Underscores zijn belangrijk omdat ze de locatie van het bestand weerspiegelen in de folderstructuur.
|
||||
|
||||
De volgende conventies worden gebruikt:
|
||||
|
||||
1. CamelCased class namen worden niet gebruikt, alleen maar als het onnodig is om een nieuw folderniveau aan te maken.
|
||||
2. Alle class bestandsnamen en foldernamen zijn met kleine letters geschreven.
|
||||
3. Alle classes zitten in de `classes` folder. Dit kan op ieder niveau in het [cascading filesystem](about.filesystem).
|
||||
|
||||
[!!] In tegenstelling tot Kohana v2.x, is er geen afscheiding tussen "controllers", "models", "libraries" en "helpers". Alle classes worden in de folder "classes/" geplaatst, of het nu static "helpers" of object "libraries" zijn. Ieder design pattern is mogelijk voor het maken van classes: static, singleton, adapter, etc.
|
||||
|
||||
## Voorbeelden
|
||||
|
||||
Onthoud dat in een class, een underscore een folder betekent. Bekijk de volgende voorbeelden:
|
||||
|
||||
Class Naam | Locatie File
|
||||
----------------------|-------------------------------
|
||||
Controller_Template | classes/controller/template.php
|
||||
Model_User | classes/model/user.php
|
||||
Database | classes/database.php
|
||||
Database_Query | classes/database/query.php
|
||||
Form | classes/form.php
|
||||
|
||||
## Coding Standaarden {#coding_standards}
|
||||
|
||||
Om zeer consistente broncode te schrijven, vragen we dat iedereen de coding standaarden zo nauw mogelijk probeert na te volgen.
|
||||
|
||||
### Gekrulde Haakjes (Brackets)
|
||||
|
||||
Gebruik aub [BSD/Allman Stijl](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) van bracketing.
|
||||
|
||||
### Naam conventies
|
||||
|
||||
Kohana gebruikt underscore namen, geen camelCase.
|
||||
|
||||
#### Classes
|
||||
|
||||
<?php
|
||||
|
||||
// Controller class, gebruikt Controller_ voorvoegsel
|
||||
class Controller_Apple extends Controller {
|
||||
|
||||
// Model class, gebruikt Model_ voorvoegsel
|
||||
class Model_Cheese extends Model {
|
||||
|
||||
// Regular class
|
||||
class peanut {
|
||||
|
||||
Wanneer je een instantie aanmaakt van een class, gebruik dan haakjes als je niets meegeeft aan de constructor:
|
||||
|
||||
<?php
|
||||
|
||||
// Correct:
|
||||
$db = new Database;
|
||||
|
||||
// Niet correct:
|
||||
$db = new Database();
|
||||
|
||||
#### Functies en Methoden
|
||||
|
||||
Functies moeten altijd lowercase zijn. Gebruik underscores om woorden van elkaar te scheiden:
|
||||
|
||||
<?php
|
||||
|
||||
function drink_beverage($beverage)
|
||||
{
|
||||
|
||||
#### Variabelen
|
||||
|
||||
Alle variabelen moeten lowercase zijn, gebruik underscores, geen cameCase:
|
||||
|
||||
<?php
|
||||
|
||||
// Correct:
|
||||
$foo = 'bar';
|
||||
$long_example = 'Gebruik underscores';
|
||||
|
||||
// Niet correct:
|
||||
$weWillenDitDusNiet = 'verstaan?';
|
||||
|
||||
### Inspringen
|
||||
|
||||
Je moet tabs gebruiken om je code te laten inspringen. In geen enkel geval gebruik je spaties als tabs.
|
||||
|
||||
Verticale afstanden (voor multi-line) wordt gedaan met spaties. Tabs zijn niet goed voor verticale uitlijning omdat verschillende mensen andere tabbreedtes hebben.
|
||||
|
||||
<?php
|
||||
|
||||
$text = 'this is a long text block that is wrapped. Normally, we aim for '
|
||||
. 'wrapping at 80 chars. Vertical alignment is very important for '
|
||||
. 'code readability. Remember that all indentation is done with tabs,'
|
||||
. 'but vertical alignment should be completed with spaces, after '
|
||||
. 'indenting with tabs.';
|
||||
|
||||
### String concatenatie
|
||||
|
||||
Plaats geen spaties rond de concatenatie operator:
|
||||
|
||||
<?php
|
||||
|
||||
// Correct:
|
||||
$str = 'one'.$var.'two';
|
||||
|
||||
// Niet correct:
|
||||
$str = 'one'. $var .'two';
|
||||
$str = 'one' . $var . 'two';
|
||||
|
||||
### Enkelvoudige lijn Statements
|
||||
|
||||
Enkelvoudige lijn IF statements mogen enkel maar gebruikt worden wanneer het de normale executie stop zoals `return` of `continue`:
|
||||
|
||||
<?php
|
||||
|
||||
// Aanvaardbaar:
|
||||
if ($foo == $bar)
|
||||
return $foo;
|
||||
|
||||
if ($foo == $bar)
|
||||
continue;
|
||||
|
||||
if ($foo == $bar)
|
||||
break;
|
||||
|
||||
if ($foo == $bar)
|
||||
throw new Exception('You screwed up!');
|
||||
|
||||
// Niet aanvaardbaar:
|
||||
if ($baz == $bun)
|
||||
$baz = $bar + 2;
|
||||
|
||||
### Vergelijkingsoperatoren
|
||||
|
||||
Gebruik OR en AND in je statements:
|
||||
|
||||
<?php
|
||||
|
||||
// Correct:
|
||||
if (($foo AND $bar) OR ($b AND $c))
|
||||
|
||||
// Niet correct:
|
||||
if (($foo && $bar) || ($b && $c))
|
||||
|
||||
Bij if/else blokken, gebruik `elseif`, niet `else if`:
|
||||
|
||||
<?php
|
||||
|
||||
// Correct:
|
||||
elseif ($bar)
|
||||
|
||||
// Niet correct:
|
||||
else if($bar)
|
||||
|
||||
### Switch structuren
|
||||
|
||||
Iedere case, break en default moeten op een aparte lijn staan. Het blok binnenin een case of default moet met één tab ingesprongen worden.
|
||||
|
||||
<?php
|
||||
|
||||
switch ($var)
|
||||
{
|
||||
case 'bar':
|
||||
case 'foo':
|
||||
echo 'hello';
|
||||
break;
|
||||
case 1:
|
||||
echo 'one';
|
||||
break;
|
||||
default:
|
||||
echo 'bye';
|
||||
break;
|
||||
}
|
||||
|
||||
### Haakjes (Parentheses)
|
||||
|
||||
Er moet een spatie achter het statements naam staan, gevolgd door een haakje. Het ! (bang) karakter moet een spatie langs beide kanten hebben om de zichtbaarheid te maximaliseren. Je mag geen spatie hebben na het eerste haakje of voor de laatste haakje, enkel in het geval van een bang of type casting.
|
||||
|
||||
<?php
|
||||
|
||||
// Correct:
|
||||
if ($foo == $bar)
|
||||
if ( ! $foo)
|
||||
|
||||
// Niet correct:
|
||||
if($foo == $bar)
|
||||
if(!$foo)
|
||||
if ((int) $foo)
|
||||
if ( $foo == $bar )
|
||||
if (! $foo)
|
||||
|
||||
### Ternaries
|
||||
|
||||
Alle ternaire operaties moeten volgens het standaard formaat. Gebruik enkel haakjes rond uitdrukkingen, niet rond enkel maar variabelen.
|
||||
|
||||
$foo = ($bar == $foo) ? $foo : $bar;
|
||||
$foo = $bar ? $foo : $bar;
|
||||
|
||||
Alle vergelijkingen en bewerkingen moeten binnenin de haakjes gebeuren:
|
||||
|
||||
$foo = ($bar > 5) ? ($bar + $foo) : strlen($bar);
|
||||
|
||||
Bij het scheiden van complexe ternaries (ternaries waarbij het eerste deel meer dan ~80 karakters bevat) in meerdere regels, moet je spaties gebruiken om operators op te lijnen, deze plaats je in het begin van de opeenvolgende lijnen:
|
||||
|
||||
$foo = ($bar == $foo)
|
||||
? $foo
|
||||
: $bar;
|
||||
|
||||
### Type Casting
|
||||
|
||||
Type casting wordt gedaan met spatie langs elke kant van de cast:
|
||||
|
||||
// Correct:
|
||||
$foo = (string) $bar;
|
||||
if ( (string) $bar)
|
||||
|
||||
// Niet correct:
|
||||
$foo = (string)$bar;
|
||||
|
||||
Indien mogelijk, gebruik dan in plaats van type casting ternaire operators:
|
||||
|
||||
// Correct:
|
||||
$foo = (bool) $bar;
|
||||
|
||||
// Niet correct:
|
||||
$foo = ($bar == TRUE) ? TRUE : FALSE;
|
||||
|
||||
Bij het casten van een integer of een boolean gebruik je het korte formaat:
|
||||
|
||||
// Correct:
|
||||
$foo = (int) $bar;
|
||||
$foo = (bool) $bar;
|
||||
|
||||
// Incorrect:
|
||||
$foo = (integer) $bar;
|
||||
$foo = (boolean) $bar;
|
||||
|
||||
### Constanten
|
||||
|
||||
Gebruik altijd hoofdletters voor constanten:
|
||||
|
||||
// Correct:
|
||||
define('MY_CONSTANT', 'my_value');
|
||||
$a = TRUE;
|
||||
$b = NULL;
|
||||
|
||||
// Niet correct:
|
||||
define('MyConstant', 'my_value');
|
||||
$a = True;
|
||||
$b = null;
|
||||
|
||||
Plaats constant vergelijkingen aan het einde van de tests:
|
||||
|
||||
// Correct:
|
||||
if ($foo !== FALSE)
|
||||
|
||||
// Niet correct:
|
||||
if (FALSE !== $foo)
|
||||
|
||||
Dit is een enigszins een controversiële keuze, dus is een uitleg op zijn plaats. Als we het vorige voorbeeld in gewoon taal schrijven, zou het goede voorbeeld als volgt te lezen zijn:
|
||||
|
||||
if variable $foo is not exactly FALSE
|
||||
|
||||
En het foute voorbeeld zou als volgt te lezen zijn:
|
||||
|
||||
if FALSE is not exactly variable $foo
|
||||
|
||||
En aangezien we van links naar rechts lezen, is het logischer om de constante als laatste te plaatsen.
|
||||
|
||||
### Commentaren
|
||||
|
||||
#### Commentaren op één lijn
|
||||
|
||||
Gebruik //, best boven de lijn met je code waar je de commentaar voor wilt schrijven. Laat een spatie tussen en start met een hoofdletter. Gebruik nooit #
|
||||
|
||||
// Correct
|
||||
|
||||
//Niet correct
|
||||
// niet correct
|
||||
# Niet correct
|
||||
|
||||
### Reguliere expressies
|
||||
|
||||
Bij het coderen van reguliere expressies gebruik je beter PCRE in plaats van POSIX. PCRE zou krachtiger en sneller zijn.
|
||||
|
||||
// Correct:
|
||||
if (preg_match('/abc/i'), $str)
|
||||
|
||||
// Incorrect:
|
||||
if (eregi('abc', $str))
|
||||
|
||||
Gebruik enkele aanhalingstekens rond uw reguliere expressies in plaats van dubbele aanhalingstekens. Enkele aanhalingstekens worden gemakkelijker door hun eenvoud in gebruik. In tegenstelling tot de dubbele aanhalingstekens ondersteunen ze niet variabele interpolatie, noch geïntegreerde backslash sequenties zoals \n of \t, enz.
|
||||
|
||||
// Correct:
|
||||
preg_match('/abc/', $str);
|
||||
|
||||
// Incorrect:
|
||||
preg_match("/abc/", $str);
|
||||
|
||||
Bij het uitvoeren van een reguliere expressie zoeken en vervangen, gebruik dan de $n notatie voor terugverwijzingen. Dit verdient de voorkeur boven \\n.
|
||||
|
||||
// Correct:
|
||||
preg_replace('/(\d+) dollar/', '$1 euro', $str);
|
||||
|
||||
// Incorrect:
|
||||
preg_replace('/(\d+) dollar/', '\\1 euro', $str);
|
||||
|
||||
Tot slot, let wel dat het $-teken voor de eindpositie van de lijn aan te geven toelaat om een newline-karakter als volgend karakter te gebruiken. Gebruik de D modifier om dit te verhelpen indien nodig. [Meer informatie](http://blog.php-security.org/archives/76-Holes-in-most-preg_match-filters.html).
|
||||
|
||||
$str = "email@example.com\n";
|
||||
|
||||
preg_match('/^.+@.+$/', $str); // TRUE
|
||||
preg_match('/^.+@.+$/D', $str); // FALSE
|
@@ -1,76 +0,0 @@
|
||||
# Cascading Filesystem
|
||||
|
||||
Het Kohana filesysteem heeft hiërarchie van folder-structuur. Wanneer een bestand wordt ingeladen door [Kohana::find_file], dan wordt het gezocht in de volgend volgorde:
|
||||
|
||||
Application pad
|
||||
: Gedefineerd als `APPPATH` in `index.php`. De standaard value hiervan is `application`.
|
||||
|
||||
Module paden
|
||||
: Dit is ingesteld als een associatieve array met behulp van [Kohana::modules] in `APPPATH/bootstrap.php`. Elk van de waarden van de array zal worden gezocht in de volgorde waarin de modules worden toegevoegd.
|
||||
|
||||
System pad
|
||||
: Gedefineerd als `SYSPATH` in `index.php`. De standaard value hiervan is `system`. Alle belangrijkste of "core"-bestanden en classes zijn hier gedefinieerd.
|
||||
|
||||
Bestanden die zich hoger bevinden in de volgorde van het inladen van bestanden hebben voorrang op bestanden met dezelfde naam die zich lager bevinden in de volgorde van inladen, dit maakt het mogelijk om ieder bestand te overloaden door een bestand met dezelfde naam in een "hogere" folder te plaatsen:
|
||||
|
||||

|
||||
|
||||
Als je een view bestand hebt met de naam `welcome.php` in de `APPPATH/views` en `SYSPATH/views` folders, dan zal hetgeen uit application worden gereturned als `welcome.php` wordt ingeladen omdat het "hoger" staat in de folderstructuur.
|
||||
|
||||
## Types bestanden
|
||||
|
||||
De top level folders van de application, module en systeem paden hebben volgende standaard folders:
|
||||
|
||||
classes/
|
||||
: Alle classes dat je wilt [automatisch inladen](using.autoloading) moeten zich hier
|
||||
bevinden. Dit houdt in controllers, models, en alle andere classes. Alle classes moeten
|
||||
de [class naam conventies](about.conventions#classes) volgen.
|
||||
|
||||
config/
|
||||
: Configuratie bestanden geven een associatieve array van opties terug die je kunt
|
||||
inladen via [Kohana::config]. Zie [gebruik van configuratie](using.configuration) voor
|
||||
meer informatie.
|
||||
|
||||
i18n/
|
||||
: Vertalingsbestanden geven een associatieve array van strings terug. Vertalen wordt
|
||||
gedaan door de `__()` methode te gebruiken. Om "Hello, world!" te vertalen in het
|
||||
Spaans zou je de methode `__('Hello, world!')` oproepen met [I18n::$lang] ingesteld op "es-es".
|
||||
Zie [gebruik van vertaling](using.translation) voor meer informatie.
|
||||
|
||||
messages/
|
||||
: Berichtenbestanden geven een associatieve array van strings terug die ingeladen kunnen
|
||||
worden via [Kohana::message]. Messages en i18n bestanden verschillen erin dat messages
|
||||
niet worden vertaald, maar altijd geschreven worden in de standaard taal en verwezen worden
|
||||
via een enkelvoudige key. Zie [gebruik van messages](using.messages) voor meer informatie.
|
||||
|
||||
views/
|
||||
: Views zijn plain PHP files die worden gebruikt om HTML of een ander formaat te genereren. Het view bestand wordt
|
||||
ingeladen in in een [View] object en toegewezen variabelen, die het dan zal omzetten naar een HTML fractie. Het is mogelijk om meerder views in elkaar te gebruiken.
|
||||
Zie [gebruik van views](usings.views) voor meer informatie.
|
||||
|
||||
## Vinden van betanden
|
||||
|
||||
Het pad naar eender welk bestand in de folderstructuur kan worden gevonden door het gebruik van [Kohana::find_file]:
|
||||
|
||||
// Vind het volledige pad naar "classes/cookie.php"
|
||||
$path = Kohana::find_file('classes', 'cookie');
|
||||
|
||||
// Vind het volledige pad naar "views/user/login.php"
|
||||
$path = Kohana::find_file('views', 'user/login');
|
||||
|
||||
|
||||
# Vendor Extensions
|
||||
|
||||
Extensies die niet specifiek zijn aan Kohana noemen we "vendor" extensions.
|
||||
Bijvoorbeeld, als je [DOMPDF](http://code.google.com/p/dompdf) wilt gebruiken,
|
||||
dan moet je het kopiëren naar `application/vendor/dompdf` en de DOMPDF
|
||||
autoloading class inladen:
|
||||
|
||||
require Kohana::find_file('vendor', 'dompdf/dompdf/dompdf_config.inc');
|
||||
|
||||
Nu kan je DOMPDF gebruiken zonder inladen van andere bestanden:
|
||||
|
||||
$pdf = new DOMPDF;
|
||||
|
||||
[!!] Indien je views wilt omzetten in PDFs via DOMPDF, probeer dan de
|
||||
[PDFView](http://github.com/shadowhand/pdfview) module.
|
@@ -1,73 +0,0 @@
|
||||
# Request Flow
|
||||
|
||||
Iedere applicatie volgt de zelfde flow:
|
||||
|
||||
1. Applicatie start vanaf `index.php`.
|
||||
2. De application, module, en system paden worden ingesteld.
|
||||
3. Error reporting niveaus worden ingesteld.
|
||||
4. Install file wordt geladen, als het bestaat.
|
||||
5. De [Kohana] class wordt ingeladen.
|
||||
6. Het bootstrap bestand, `APPPATH/bootstrap.php`, wordt geinclude.
|
||||
7. [Kohana::init] wordt aangeroepen, deze stelt error handling, caching, en logging in.
|
||||
8. [Kohana_Config] lezers en [Kohana_Log] schrijvers worden toegevoegd.
|
||||
9. [Kohana::modules] wordt aangeroepen om additionele modules te activeren.
|
||||
* Module paden worden toegevoegd aan het [cascading filesystem](about.filesystem).
|
||||
* Includen van `init.php` bestand, als het bestaat.
|
||||
* Het `init.php` bestand kan een extra omgevingsinstellingen instellen, waaronder het toevoegen van routes.
|
||||
10. [Route::set] wordt verschillende keren opgeroepen om de [applicaties routes](using.routing) te definiëren.
|
||||
11. [Request::instance] wordt opgeroepen om het request-proces te starten.
|
||||
1. Iedere route controleren dat is ingesteld tot er een overeenkomst is gevonden.
|
||||
2. Conroller instantie wordt gecreeërd en het request wordt doorgeven eraan.
|
||||
3. De [Controller::before] methode wordt aangeroepen.
|
||||
4. De controller action wordt aangeroepen, deze genereerd de request response.
|
||||
5. De [Controller::after] methode wordt aangeroepen.
|
||||
* De 5 bovenstaande stappen kunnen verschillende keren worden herhaald wanneer je [HMVC sub-requests](about.mvc) gebruikt.
|
||||
12. De basis [Request] response wordt getoond
|
||||
|
||||
## index.php
|
||||
|
||||
Kohana volgt een [front controller] pattern, dit betekent dat alle requests worden gezonden naar `index.php`. Dit laat een zeer eenvoudig [bestandsstructuur](about.filesystem) design toe. In `index.php` zijn er enkele zeer basis configuratie opties mogelijk. je kan de `$application`, `$modules`, en `$system` paden veranderen en het error reporting level instellen.
|
||||
|
||||
De `$application` variabele laat je toe om de folder in te stellen die al je application bestanden bevat. Standaard is dit `application`. De `$modules` variabele laat je toe om de folder in te stellen die alle module bestanden bevat. De `$system` variabele laat je toe om de folder in te stellen die alle Kohana bestanden bevat.
|
||||
|
||||
Je kan deze drie folders overal naartoe verplaatsen. Bijvoorbeeld, als je folderstructuur zo is ingesteld:
|
||||
|
||||
www/
|
||||
index.php
|
||||
application/
|
||||
modules/
|
||||
system/
|
||||
|
||||
Dan kan je de folders uit de webroot verplaatsen:
|
||||
|
||||
application/
|
||||
modules/
|
||||
system/
|
||||
www/
|
||||
index.php
|
||||
|
||||
Dan moet je de instellingen in `index.php` veranderen naar:
|
||||
|
||||
$application = '../application';
|
||||
$modules = '../modules';
|
||||
$system = '../system';
|
||||
|
||||
Nu kan geen enkele van deze folders worden bereikt via de webserver. Het is niet noodzakelijk om deze verandering te maken, maar het maakt het wel mogelijk om de folders te delen met meerdere applicaties, de mogelijkheden zijn enorm.
|
||||
|
||||
[!!] Er is een veiligheidscontrole bovenaan elke Kohana file om te voorkomen dat het wordt uitgevoerd zonder het gebruik van de front controller. Maar natuurlijk is het veiliger om de application, modules, en system folders te verplaatsen naar een locatie dat niet kan worden bereikt via het web.
|
||||
|
||||
### Error Reporting
|
||||
|
||||
Standaard toont Kohana alle errors, zo ook strikte warnings. Dit wordt ingesteld door [error_reporting](http://php.net/error_reporting):
|
||||
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
Als je applicatie live staat en in productie is, een meer conversatieve instelling is aangeraden, zoals het negeren van notices:
|
||||
|
||||
error_reporting(E_ALL & ~E_NOTICE);
|
||||
|
||||
Als je een wit scherm krijgt wanneer een error is opgetreden, dan zal uw host waarschijnlijk het tonen van errors hebben uitgeschakeld. Je kan dit terug aanzetten door deze lijn toe te voegen juist achter je `error_reporting` call:
|
||||
|
||||
ini_set('display_errors', TRUE);
|
||||
|
||||
Errors zouden **altijd** moeten worden getoond, zelf in productie, omdat het je toelaat om [exception en error handling](debugging.errors) te gebruiken om een mooie error pagina te tonen in plaats van een wit scherm als een error voorkomt.
|
@@ -1,94 +0,0 @@
|
||||
# Installatie
|
||||
|
||||
1. Download de laatste **stabiele** release van de [Kohana website](http://kohanaframework.org/).
|
||||
2. Unzip het gedownloade pakket om de `kohana` folder aan te maken.
|
||||
3. Upload de inhoud van deze folder naar je webserver.
|
||||
4. Open `application/bootstrap.php` en maak de volgende aanpassingen:
|
||||
- Stel de standaard [timezone](http://php.net/timezones) in voor je applicatie
|
||||
- Stel de `base_url` in de [Kohana::init] methode in om te verwijzen naar de locatie van de kohana folder op je server
|
||||
6. Zorg ervoor dat de `application/cache` en `application/logs` folders schrijfrechten hebben voor de web server
|
||||
7. Test je installatie door de URL te openen in je favoriete browser dat je hebt ingesteld als `base_url`
|
||||
|
||||
[!!] Afhankelijk van je platform is het mogelijk dat de installatie subfolders hun rechten verloren hebben tijdens de zip extractie. Chmod ze allemaal met 755 door het commando `find . -type d -exec chmod 0755 {} \;` uit te voeren in de root van je Kohana installatie.
|
||||
|
||||
Je zou de installatie pagina moeten zien. Als het errors toont, zal je ze moeten aanpassen vooraleer je verder kunt gaan.
|
||||
|
||||

|
||||
|
||||
Eens je installatie pagina zegt dat je omgeving goed is ingesteld dan moet je de `install.php` pagina hernoemen of verwijderen in de root folder. Je zou nu de de Kohana welcome pagina moeten zien:
|
||||
|
||||

|
||||
|
||||
## Een productie-omgeving opzetten
|
||||
|
||||
Er zijn enkele dingen dat je best doet met je applicatie vooraleer je deze in productie plaatst:
|
||||
|
||||
1. Bekijk de [configuratie pagina](about.configuration) in de documentatie.
|
||||
Dit omvat het grootste gedeelte van de globale instellingen dat zouden moeten veranderen bij andere omgevingen.
|
||||
Als algemene regel, zet je best caching aan en zet je profiling uit ([Kohana::init] settings) voor sites in productie.
|
||||
[Route caching](api/Route#cache) kan ook helpen als je heel wat routes hebt.
|
||||
2. Catch alle exceptions in `application/bootstrap.php`, zodat gevoelige gegevens niet kan worden gelekt door stack traces.
|
||||
Zie onderstaand voorbeeld van Shadowhand's [wingsc.com broncode](http://github.com/shadowhand/wingsc).
|
||||
3. Zet APC of een andere soort opcode caching aan. Dit is het enige en eenvoudigste manier om de performantie te verbeteren dat je kunt doen in PHP zelf. Hoe complexer je applicatie, hoe groter het voordeel van opcode caching.
|
||||
|
||||
[!!] Opmerking: De standaard bootstrap zal Kohana::$environment = $_ENV['KOHANA_ENV'] instellen indien ingesteld. Documentatie hoe je deze variable moet invullen kan je vinden in je webservers documentatie (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), [Nginx](http://wiki.nginx.org/NginxHttpFcgiModule#fastcgi_param))). Deze manier wordt als beste beschouwd in vergelijking met de alternatieve manieren om Kohana::$environment in te stellen.
|
||||
|
||||
/**
|
||||
* Stel de omgeving in aan de hand van het domein (standaard Kohana::DEVELOPMENT).
|
||||
*/
|
||||
Kohana::$environment = ($_SERVER['SERVER_NAME'] !== 'localhost') ? Kohana::PRODUCTION : Kohana::DEVELOPMENT;
|
||||
/**
|
||||
* Initialiseer Kohana op basis van de omgeving
|
||||
*/
|
||||
Kohana::init(array(
|
||||
'base_url' => '/',
|
||||
'index_file' => FALSE,
|
||||
'profile' => Kohana::$environment !== Kohana::PRODUCTION,
|
||||
'caching' => Kohana::$environment === Kohana::PRODUCTION,
|
||||
));
|
||||
|
||||
/**
|
||||
* Voer de algemene request uit met PATH_INFO. Als er geen URI is gespecifeerd,
|
||||
* dan zal de URI automatisch worden gedetecteerd.
|
||||
*/
|
||||
$request = Request::instance($_SERVER['PATH_INFO']);
|
||||
|
||||
try
|
||||
{
|
||||
// Propeer het request uit te voeren
|
||||
$request->execute();
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
if (Kohana::$environment == Kohana::DEVELOPMENT)
|
||||
{
|
||||
// Just re-throw the exception
|
||||
throw $e;
|
||||
}
|
||||
|
||||
// De error loggen
|
||||
Kohana::$log->add(Kohana::ERROR, Kohana::exception_text($e));
|
||||
|
||||
// Maak een 404 uitvoer
|
||||
$request->status = 404;
|
||||
$request->response = View::factory('template')
|
||||
->set('title', '404')
|
||||
->set('content', View::factory('errors/404'));
|
||||
}
|
||||
|
||||
if ($request->send_headers()->response)
|
||||
{
|
||||
// Verkrijg totaal aantal geheugen en snelheids tijd
|
||||
$total = array(
|
||||
'{memory_usage}' => number_format((memory_get_peak_usage() - KOHANA_START_MEMORY) / 1024, 2).'KB',
|
||||
'{execution_time}' => number_format(microtime(TRUE) - KOHANA_START_TIME, 5).' seconds');
|
||||
|
||||
// Stel de totalen in, in de uitvoer
|
||||
$request->response = str_replace(array_keys($total), $total, $request->response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Toon de uitvoer dan het request.
|
||||
*/
|
||||
echo $request->response;
|
@@ -1,15 +0,0 @@
|
||||
# Wat is Kohana?
|
||||
|
||||
Kohana is een open source, [objectgeoriënteerd](http://nl.wikipedia.org/wiki/Objectgeori%C3%ABnteerd) [MVC](http://wikipedia.org/wiki/Model–View–Controller "Model View Controller") [web framework](http://wikipedia.org/wiki/Web_Framework) gebouwd met [PHP5](http://php.net/manual/intro-whatis "PHP Hypertext Preprocessor") door een aantal vrijwilligers die veiligheid, snelheid en een kleine voetafdruk nastreven.
|
||||
|
||||
[!!] Kohana is gelicentieerd onder een [BSD license](http://kohanaframework.org/license), zodat je het framework legaal kunt gebruiken voor allerlei projecten: open source, commercieel of persoonlijk.
|
||||
|
||||
## Waarom is Kohana zo goed?
|
||||
|
||||
Alles kan worden uitgebreid door het unieke design van het [filesystem](about.filesystem), er is geen of weinig [configuratie](about.configuration) voor nodig, [error handling](debugging.errors) helpt je vlug de oorzaak te vinden van je fouten en [debuggen](debugging) en [profiling](debugging.profiling) zorgen voor een beter inzicht in je applicatie.
|
||||
|
||||
Om je te helpen je applicatie te beveiligen zijn er tools voor [XSS te verwijderen](security.xss), [input validatie](security.validation), [gesigneerde cookies](security.cookies), [formulieren](security.forms) en [HTML](security.html) generators toegevoegd aan het systeem. De [database](security.database) layer voorkomt [SQL injectie](http://wikipedia.org/wiki/SQL_Injection). En natuurlijk, alle officiële code is met zorg geschreven en herbekeken inzake veiligheid.
|
||||
|
||||
## Vul mee deze documentatie aan
|
||||
|
||||
We zijn keihard en volop bezig om je van een complete documentatie te voorzien. Om deze documentatie te helpen verbeteren, gelieve dan de userguide te [forken](http://github.com/kohana/userguide), uw aanpassingen te doen en een pull request te sturen. Als je nog geen ervaring hebt met git kan je altijd een [feature request](http://dev.kohanaframework.org/projects/kohana3/issues) aanmaken (vereist registratie).
|
@@ -1,7 +0,0 @@
|
||||
# (Hiërarchische) Model View Controller
|
||||
|
||||
Model View Controller (of MVC afgekort) is een populair design pattern dat de data (Model) afscheid van de presentatie/templates (View) en de request-logica (Controller).
|
||||
|
||||
Het maakt ontwikkelen van applicaties een stuk gemakkelijker omdat het systeem zo gedesignd is om code meermaals te hergebruiken, wat wil zeggen dat je er minder moet schrijven!
|
||||
|
||||
[!!] Stub
|
@@ -1,4 +0,0 @@
|
||||
# Translation
|
||||
|
||||
[!!] This article is a stub!
|
||||
|
@@ -1,288 +0,0 @@
|
||||
# Upgraden vanaf 2.3.x
|
||||
|
||||
De code van Kohana v3 werkt grotendeels anders dan Kohana 2.3, hier is een lijst van de meeste valkuilen en tips om succesvol te upgraden.
|
||||
|
||||
## Naming conventies
|
||||
|
||||
In 2.x versies onderscheiden de verschillende soorten van classes (zoals controller, model, ...) zich met elkaar met behulp van achtervoegsels. Mappen in de model / controller mappen hadden geen invloed op de naam van de class.
|
||||
|
||||
In 3.0 werd aanpak geschrapt ten gunste van de Zend framework bestandssysteem conventies, waar de naam van de class het pad is naar de class zelf, gescheiden door een underscore in plaats van slashes (dus `/some/class/file.php` bekomt `Some_Class_File`).
|
||||
Zie de [conventies documentatie](start.conventions) voor meer informatie.
|
||||
|
||||
## Input Library
|
||||
|
||||
De Input Library is verwijderd in 3.0, er wordt nu aanbevolen om gewoon `$_GET` en `$_POST` te gebruiken.
|
||||
|
||||
### XSS Protectie
|
||||
|
||||
Als je invoer van gebruikers wilt filteren op XSS kan je [Security::xss_clean] gebruiken om:
|
||||
|
||||
$_POST['description'] = security::xss_clean($_POST['description']);
|
||||
|
||||
Je kan ook altijd [Security::xss_clean] gebruiken als filter met de [Validate] library:
|
||||
|
||||
$validation = new Validate($_POST);
|
||||
|
||||
$validate->filter('description', 'Security::xss_clean');
|
||||
|
||||
### POST & GET
|
||||
|
||||
Eén van de grootste functies van de Input Library was als je probeerde een waarde uit een superglobale array te halen en deze bestond bestond niet, dan zou de Input Library een standaard waarde teruggeven dat je kon instellen:
|
||||
|
||||
$_GET = array();
|
||||
|
||||
// $id heeft de waarde 1 gekregen
|
||||
$id = Input::instance()->get('id', 1);
|
||||
|
||||
$_GET['id'] = 25;
|
||||
|
||||
// $id heeft de waarde 25 gekregen
|
||||
$id = Input::instance()->get('id', 1);
|
||||
|
||||
In 3.0 kan je deze functionaliteit nabootsen door [Arr::get] te gebruiken:
|
||||
|
||||
$_GET = array();
|
||||
|
||||
// $id heeft de waarde 1 gekregen
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
|
||||
$_GET['id'] = 42;
|
||||
|
||||
// $id heeft de waarde 42 gekregen
|
||||
$id = Arr::get($_GET, 'id', 1);
|
||||
|
||||
## ORM Library
|
||||
|
||||
Er zijn redelijk veel grote wijzingingen aangebracht in ORM sedert 2.3. Hier is een lijst met de meest voorkomende upgrade problemen.
|
||||
|
||||
### Member variablen
|
||||
|
||||
Alle member variablen hebben nu een voorvoegsel gekregen met een underscore (_) en zijn niet langer bereikbaar via `__get()`. Nu moet je een functie aanroepen met de naam van de property zonder de underscore.
|
||||
|
||||
Bijvoorbeeld, in 2.3 had je `loaded` en in 3.x is dat nu `_loaded` en heb je nu toegang van buiten de class via `$model->loaded()`.
|
||||
|
||||
### Relaties
|
||||
|
||||
Als je in 2.3 de gerelateerde objecten van een model wilde herhalen, kon je dat zo doen:
|
||||
|
||||
foreach($model->{relation_name} as $relation)
|
||||
|
||||
Maar in 3.0 zal dit niet werken. In de 2.3 serie werden alle queries die gegenereerd werden met behulp van de Database Library gegeneeerd in een globale omgeving, wat betekent dat je niet kon proberen en maken van twee queries. Bijvoorbeeld:
|
||||
|
||||
# TODO: GOED VOORBEELD!!!!
|
||||
|
||||
Deze query zou mislukken doordat de tweede, inner query alle voorwaarden zou overerven van de eerste, wat zou leiden tot het mislukken.
|
||||
In 3.0 is dit aangepast door iedere query te laten genereren in zijn eigen omgeving. Let wel dat sommige dingen hierdoor niet gaan werken zoals je verwacht. Bijvoorbeeld:
|
||||
|
||||
foreach(ORM::factory('user', 3)->where('post_date', '>', time() - (3600 * 24))->posts as $post)
|
||||
{
|
||||
echo $post->title;
|
||||
}
|
||||
|
||||
[!!] (Zie [de Database tutorial](tutorials.databases) voor de nieuwe query syntax)
|
||||
|
||||
In 2.3 zou je verwachten dat dit iterator teruggeeft van alle berichten van een gebruiker met `id` 3 met een `post_date` binnenin de 24 uren, maar in de plaats daarvan zal de WHERE conditie toegepast worden op het user-model en een `Model_Post` worden teruggevens met de joining conditities gespecifieerd.
|
||||
|
||||
Om hetzelfde effect te verkrijgen zoals in 2.3, moet je de structuur iets aanpassen:
|
||||
|
||||
foreach(ORM::factory('user', 3)->posts->where('post_date', '>', time() - (36000 * 24))->find_all() as $post)
|
||||
{
|
||||
echo $post->title;
|
||||
}
|
||||
|
||||
Dit is ook van toepassing op de `has_one` relaties:
|
||||
|
||||
// Niet correct
|
||||
$user = ORM::factory('post', 42)->author;
|
||||
// Correct
|
||||
$user = ORM::factory('post', 42)->author->find();
|
||||
|
||||
### Has and belongs to many relaties
|
||||
|
||||
In 2.3 kon je `has_and_belongs_to_many` relaties specifieren. In 3.0 is deze functionaliteit herschreven naar `has_many` *through*.
|
||||
|
||||
In het model definieer je een `has_many` relatie met een ander model maar dan voeg je nog een `'through' => 'table'` attribuut aan toe, waar `'table'` de naam is van de trough tabel. Bijvoorbeeld (in de context van posts<>categories):
|
||||
|
||||
$_has_many = array
|
||||
(
|
||||
'categories' => array
|
||||
(
|
||||
'model' => 'category', // The foreign model
|
||||
'through' => 'post_categories' // The joining table
|
||||
),
|
||||
);
|
||||
|
||||
Als je Kohana hebt opgezet om een tabel voorvoegsel te gebruiken, dan hoef je geen zorgen te maken om dit voorvoegsel hier te gebruiken bij de tabelnaam.
|
||||
|
||||
### Foreign keys
|
||||
|
||||
Als je in Kohana 2.x's ORM een foreign key wilde overschrijven moest je de relatie specificeren waaraan het toebehoorde, en de nieuwe foreign key instellen in de member variabele `$foreign_keys`.
|
||||
|
||||
In 3.0 moet je nu een `foreign_key` definiëren in de relatie-definitie, zoals hier:
|
||||
|
||||
Class Model_Post extends ORM
|
||||
{
|
||||
$_belongs_to = array
|
||||
(
|
||||
'author' => array
|
||||
(
|
||||
'model' => 'user',
|
||||
'foreign_key' => 'user_id',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
In dit voorbeeld zouden we een `user_id` veld moeten hebben in de tabel posts.
|
||||
|
||||
|
||||
|
||||
In has_many relaties is de `far_key` het veld in de trough tabel die linkt naar de foreign tabel en is de `foreign key` het veld in de trough tabel die "this" model's tabel linkt naar de trough table.
|
||||
|
||||
Stel je de volgende opstelleing voor: "Posts" hebben en behoren tot vele "Categories" via `posts_sections` ("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',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Uiteraard is de aliasing setup hier een beetje gek, onnodig, maar het is een goed voorbeeld om te tonen hoe het foreign/far key systeem werkt.
|
||||
|
||||
### ORM Iterator
|
||||
|
||||
Het is ook best te melden dat `ORM_Iterator` nu herschreven is naar `Database_Result`.
|
||||
|
||||
Als je een array van ORM objecten met hun keys als index van de array wilt verkrijgen, moet je [Database_Result::as_array] gebruiken, bijvoorbeeld:
|
||||
|
||||
|
||||
$objects = ORM::factory('user')->find_all()->as_array('id');
|
||||
|
||||
Waar `id` de primary key is in de user tabel.
|
||||
|
||||
## Router Library
|
||||
|
||||
In versie 2 was er een Router library die de main request afhandelde. Het liet je de basisroutes instellen in het `config/routes.php` bestand en het liet je toe om zelfgeschreven regex te gebruiken voor routes, maar het was niet echt flexibel als je iets radicaal wou veranderen.
|
||||
|
||||
## Routes
|
||||
|
||||
Het routing systeem (nu wordt verwezen naar het request systeem) is een stuk flexibeler in 3.0. Routes zijn nu gedefinieerd in het boostrap bestand (`application/bootstrap.php`) en de de module's init.php (`modules/module_name/init.php`). Het is ook interessant te weten dat routes worden geëvalueerd in de volgorde dat ze worden gedefinieerd. In plaats daarvan specifieer je een patroon voor elke uri, je kan variabelen gebruiken om segmenten aan te duiden (zoals een controller, methode, id).
|
||||
|
||||
Bijvoorbeeld, in 2.x zouden deze regexes:
|
||||
|
||||
$config['([a-z]+)/?(\d+)/?([a-z]*)'] = '$1/$3/$1';
|
||||
|
||||
de uri `controller/id/method` linken aan `controller/method/id`. In 3.0 gebruik je dit:
|
||||
|
||||
Route::set('reversed','(<controller>(/<id>(/<action>)))')
|
||||
->defaults(array('controller' => 'posts', 'action' => 'index'));
|
||||
|
||||
[!!] Iedere uri moet een unieke naam hebben (in dit geval `reversed`), de reden hiervoor wordt nader uitgelegd in de [url tutorial](tutorials.urls).
|
||||
|
||||
Slashes geven dynamische secties weer die zouden moeten worden ontleed in variabelen. Haakjes geven optionele secties aan die niet vereist zijn. Als je met een route enkel uris die beginnen met admin wilt aanspreken kan je dit gebruiken:
|
||||
|
||||
Rouse::set('admin', 'admin(/<controller>(/<id>(/<action>)))');
|
||||
|
||||
En als je wilt een dat een gebruiker een controller specificeert:
|
||||
|
||||
Route::set('admin', 'admin/<controller>(/<id>(/<action>))');
|
||||
|
||||
Kohana maakt geen gebruik van `default defaults`. Als je wilt dat Kohana ervan uit gaat dat de standaard actie 'index' is, dan moet je dat ook zo instellen! Dit kan je doen via [Route::defaults]. Als je zelfgeschreven regex wilt gebruiken voor uri segmenten dan moet je ene array met `segment => regex` meegeven, bijvoorbeeld:
|
||||
|
||||
Route::set('reversed', '(<controller>(/<id>(/<action>)))', array('id' => '[a-z_]+'))
|
||||
->defaults(array('controller' => 'posts', 'action' => 'index'))
|
||||
|
||||
Dit zou de `id` waarde forceren om te bestaan uit kleine letters van a tot z en underscores.
|
||||
|
||||
### Actions
|
||||
|
||||
Nog één ding dat belangrijk is om te melden, is dat methoden in een controller die toegankelijk moeten zijn via een url nu "actions" worden genoemd. Ze krijgen een voorvoegsel 'action_'. Bijvoorbeeld in het bovenstaande voorbeeld, als de user de url `admin/posts/1/edit` aanroept dan is de actie `edit` maar is de methode die wordt aangeroepen in de controller `action_edit`. Zie de [url tutorial](tutorials.urls) voor meer informatie.
|
||||
|
||||
## Sessies
|
||||
|
||||
De volgende methoden worden niet meer ondersteund: Session::set_flash(), Session::keep_flash() or Session::expire_flash(), inde plaats daarvan gebruik je nu [Session::get_once].
|
||||
|
||||
## URL Helper
|
||||
|
||||
Er zijn maar een aantal kleinere dingen veranderd in de url helper. `url::redirect()` werd vervangen door `$this->request->redirect()` (binnenin controllers) en `Request::instance()->redirect()`.
|
||||
|
||||
`url::current` werd nu vervangen door `$this->request->uri()`
|
||||
|
||||
## Valid / Validation
|
||||
|
||||
Deze twee classes zijn nu samengevoegd in één enkele class met de naam `Validate`.
|
||||
|
||||
De syntax om arrays te valideren is een klein beetje gewijzigd:
|
||||
|
||||
$validate = new Validate($_POST);
|
||||
|
||||
// Pas een filter toe op alle waarden in de array
|
||||
$validate->filter(TRUE, 'trim');
|
||||
|
||||
// Om enkel rules te definiëren gebruik je rule()
|
||||
$validate
|
||||
->rule('field', 'not_empty')
|
||||
->rule('field', 'matches', array('another_field'));
|
||||
|
||||
// Om meerdere rules te definiëren voor een veld gebruik je rules(), je geeft een array mee met `passing an array of rules => params als tweede argument
|
||||
$validate->rules('field', array(
|
||||
'not_empty' => NULL,
|
||||
'matches' => array('another_field')
|
||||
));
|
||||
|
||||
De 'required' rule is ook verandert van naam. Nu wordt voor de duidelijkheid 'not_empty' gebruikt.
|
||||
|
||||
## View Library
|
||||
|
||||
Er zijn enkele kleine wijzigingen aangebracht aan de View library die de moeite zijn om even te melden.
|
||||
|
||||
In 2.3 werden views gegenereerd binnenin de scope van de controller, dit liet je toe om `$this` te gebruiken als referentie naar de controller vanuit je view, dit is verandert in 3.0. Views worden nu gegenereerd in een lege scope. Als je nog `$this` wilt gebruiken in je view, moet je een referentie leggen via [View::bind]: `$view->bind('this', $this)`.
|
||||
|
||||
Het moet wel gezegd worden dat dit een *erg* slechte manier van werken is omdat het je view koppelt aan de controller wat tegenhoud om deze view opnieuw te gebruiken. Het is aan te raden om de noodzakelijke variabelen voor je view als volgt door te sturen:
|
||||
|
||||
$view = View::factory('my/view');
|
||||
|
||||
$view->variable = $this->property;
|
||||
|
||||
// OF als je dit wilt "chainen"
|
||||
|
||||
$view
|
||||
->set('variable', $this->property)
|
||||
->set('another_variable', 42);
|
||||
|
||||
// NIET aangeraden
|
||||
$view->bind('this', $this);
|
||||
|
||||
Omdat de view gegenereerd wordt in een lege scope, is `Controller::_kohana_load_view` nu overtollig. Als je de view moet aanpassen vooraleer het word gegenereerd (bijvoorbeeld om een menu te gereneren over de gehele site) kan je [Controller::after] gebruiken.
|
||||
|
||||
Class Controller_Hello extends Controller_Template
|
||||
{
|
||||
function after()
|
||||
{
|
||||
$this->template->menu = '...';
|
||||
|
||||
return parent::after();
|
||||
}
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
# Debuggen
|
||||
|
||||
Kohana heeft verschillende goede tools om je te helpen met het debuggen van je applicatie.
|
||||
|
||||
De meest gebruikte is [Kohana::debug]. Deze eenvoudige methode geef alle variablen terug, vergelijkbaar met [var_export](http://php.net/var_export) of [print_r](http://php.net/print_r), maar het gebruikt HTML voor extra opmaak.
|
||||
|
||||
// Toon een dump van de variabelen $foo en $bar
|
||||
echo Kohana::debug($foo, $bar);
|
||||
|
||||
Kohana biedt ook een methode aan om de broncode van een bepaald bestand te tonen via [Kohana::debug_source].
|
||||
|
||||
// Toon deze lijn van de broncode
|
||||
echo Kohana::debug_source(__FILE__, __LINE__);
|
||||
|
||||
Als je informatie wilt tonen over uw applicatie bestanden zonder te vertellen wat de installatie folder is, kan je [Kohana::debug_path] gebruiken:
|
||||
|
||||
// Toont "APPPATH/cache" in plaats van het echte path
|
||||
echo Kohana::debug_path(APPPATH.'cache');
|
@@ -1,22 +0,0 @@
|
||||
# Error/Exception Handling
|
||||
|
||||
Kohana biedt zowel een exception handler als een error handler aan die errors transformeert in exceptions met behulp van PHP's [ErrorException](http://php.net/errorexception) class. Veel details over de error en de interne toestand van de applicatie wordt weergegeven door de handler:
|
||||
|
||||
1. Exception class
|
||||
2. Error niveau
|
||||
3. Error bericht
|
||||
4. Bron van de error, met de errorlijn gehighlight
|
||||
5. Een [debug backtrace](http://php.net/debug_backtrace) van de uitvoerings flow
|
||||
6. Ingeladen bestanden, extensies en globale variablen
|
||||
|
||||
## Voorbeeld
|
||||
|
||||
Klik op een van de links om extra informatie te tonen:
|
||||
|
||||
<div>{{userguide/examples/error}}</div>
|
||||
|
||||
## Error/Exception Handling uitzetten
|
||||
|
||||
Als je niet de interne error handling wilt gebruiken, kan je deze uitschakelen wanneer je [Kohana::init] aanroept:
|
||||
|
||||
Kohana::init(array('errors' => FALSE));
|
@@ -1,20 +0,0 @@
|
||||
# Profiling
|
||||
|
||||
Kohana biedt een zeer eenvoudige manier aan om statistieken over uw aanvraag te tonen:
|
||||
|
||||
1. Gewone [Kohana] methodes dat aangeroepen worden
|
||||
2. Requests
|
||||
3. [Database] queries
|
||||
4. Gemiddelde uitvoeringstijden voor uw applicatie
|
||||
|
||||
## Voorbeeld
|
||||
|
||||
Je kan op elk tijdstip de huidige [profiler] statistieken tonen of opvragen:
|
||||
|
||||
<div id="kohana-profiler">
|
||||
<?php echo View::factory('profiler/stats') ?>
|
||||
</div>
|
||||
|
||||
## Voorbeeld
|
||||
|
||||
{{profiler/stats}}
|
@@ -1 +0,0 @@
|
||||
This page lists the features of Kohana v3
|
@@ -1,31 +0,0 @@
|
||||
1. **Ga aan de slag**
|
||||
- [Wat is Kohana?](about.kohana)
|
||||
- [Conventies and Codeerstijl](about.conventions)
|
||||
- [Model View Controller](about.mvc)
|
||||
- [Cascading Filesystem](about.filesystem)
|
||||
- [Request Flow](about.flow)
|
||||
- [Installatie](about.install)
|
||||
- [Upgraden](about.upgrading)
|
||||
- [API Browser](api)
|
||||
3. **Basis gebruik**
|
||||
- [Configuratie](using.configuration)
|
||||
- [Laden van classes](using.autoloading)
|
||||
- [Views en HTML](using.views)
|
||||
- [Sessies en Cookies](using.sessions)
|
||||
- [Berichten (Messages)](using.messages)
|
||||
4. **Debuggen**
|
||||
- [Code](debugging.code)
|
||||
- [Error Handling](debugging.errors)
|
||||
- [Profiling](debugging.profiling)
|
||||
5. **Beveiliging**
|
||||
- [XSS](security.xss)
|
||||
- [Validatie](security.validation)
|
||||
- [Cookies](security.cookies)
|
||||
- [Database](security.database)
|
||||
6. **Tutorials**
|
||||
- [Hello, World](tutorials.helloworld)
|
||||
- [Routes, URLs en Links](tutorials.urls)
|
||||
- [URLs opschonen](tutorials.removeindex)
|
||||
- [Databases](tutorials.databases)
|
||||
- [ORM](tutorials.orm)
|
||||
- [Werken met Git](tutorials.git)
|
@@ -1,3 +0,0 @@
|
||||
# Cookie Veiligheid
|
||||
|
||||
[!!] Nog niet beschikbaar
|
@@ -1,3 +0,0 @@
|
||||
# Database Veiligheid
|
||||
|
||||
[!!] Nog niet beschikbaar
|
@@ -1,244 +0,0 @@
|
||||
# Validatie
|
||||
|
||||
Validatie kan uitgevoerd worden op elke array met behulp van de [Validate] class. Labels, filters, regels en callbacks kunnen aan het Validate object worden toegevoegd via een array key, zogenaamd een "veldnaam".
|
||||
|
||||
labels
|
||||
: Een label is een gebruiksvriendelijke leesbare versie van de veldnaam.
|
||||
|
||||
filters
|
||||
: Een filter wijzigt de waarde van een veld voordat de regels en callbacks worden uitgevoerd.
|
||||
|
||||
rules
|
||||
: Een regel is een controle op een veld dat "TRUE" of "FALSE" teruggeeft. A rule is a check on a field that returns `TRUE` or `FALSE`. Als een regel `FALSE` teruggeeft, wordt er een error toegevoegd aan het veld.
|
||||
|
||||
callbacks
|
||||
: Een callback is een zelfgeschreven methode die het gehele Validate object tot zijn beschikking heeft. De return value van een callback wordt genegeerd. In plaats daarvan moet de callback handmatig een error toevoegen aan het object met behulp van [Validate::error] wanneer een fout optreedt.
|
||||
|
||||
[!!] Merk op dat de [Validate] callbacks en de [PHP callbacks](http://php.net/manual/language.pseudo-types.php#language.types.callback) niet hetzelfde zijn.
|
||||
|
||||
Waneer je `TRUE` als veldnaam gebruikt bij het toevoegen van een filter, regel of callback, dan zal deze worden toegepast op alle velden met een naam.
|
||||
|
||||
**Het [Validate] object zal alle velden verwijderen van de array wanneer deze niet specifiek een naam hebben gekregen via een label, filter, regel of callback. Dit voorkomt toegang tot velden die niet gevalideerd zijn als een veiligheidsmaatregel.**
|
||||
|
||||
Een validatie object maken wordt gedaan door de [Validate::factory] methode:
|
||||
|
||||
$post = Validate::factory($_POST);
|
||||
|
||||
[!!] Het `$post` object zal worden gebruikt voor de rest van deze tutorial. Deze tutorial zal je tonen hoe je een registratie van een nieuwe gebruiker valideert.
|
||||
|
||||
### Standaard regels
|
||||
|
||||
Validatie heeft standaard altijd enkele regels:
|
||||
|
||||
Naam van de regel | Functie
|
||||
------------------------- |---------------------------------------------------
|
||||
[Validate::not_empty] | Waarde moet een niet-lege waarde zijn
|
||||
[Validate::regex] | Waarde moet voldoen aan de reguliere expressie
|
||||
[Validate::min_length] | Minimum aantal karakters voor een waarde
|
||||
[Validate::max_length] | Maximum aantal karakters voor een waarde
|
||||
[Validate::exact_length] | Waarde moet een exact aantal karakters bevatten
|
||||
[Validate::email] | Een emailadres is vereist
|
||||
[Validate::email_domain] | Controleer of het domein van het email bestaat
|
||||
[Validate::url] | Waarde moet een URL zijn
|
||||
[Validate::ip] | Waarde moet een IP address zijn
|
||||
[Validate::phone] | Waarde moet een telefoonnummer zijn
|
||||
[Validate::credit_card] | Waarde moet een credit card zijn
|
||||
[Validate::date] | Waarde moet een datum (en tijd) zijn
|
||||
[Validate::alpha] | Alleen alpha karakters toegelaten
|
||||
[Validate::alpha_dash] | Alleen alpha karakters en koppeltekens toegelaten
|
||||
[Validate::alpha_numeric] | Alleen alpha karakters en nummers toegelaten
|
||||
[Validate::digit] | Waarde moet een geheel getal zijn
|
||||
[Validate::decimal] | Waarde moet een decimaal of float getal zijn
|
||||
[Validate::numeric] | Alleen nummers toegelaten
|
||||
[Validate::range] | Waarde moet zich bevinden binnenin een range
|
||||
[Validate::color] | Waarde moet een geldige HEX kleurencode zijn
|
||||
[Validate::matches] | Waarde moet gelijk zijn aan een ander veld
|
||||
|
||||
[!!] Iedere methode dat bestaat binnenin de [Validate] class kan gebruikt worden als validatie-regel zonder een volledige callback te definiëren. Bijvoorbeeld, `'not_empty'` toevoegen is hetzelfde als `array('Validate', 'not_empty')`.
|
||||
|
||||
## Toevoegen van filters
|
||||
|
||||
Alle validatie-filters worden gedefineerd als een veldnaam, een methode of een functie (gebruik makend van [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback) syntax) en een array van parameters:
|
||||
|
||||
$object->filter($field, $callback, $parameter);
|
||||
|
||||
Filters veranderen de waarde van een veld vooraleer deze gecontoleerd zijn via regels of callbacks.
|
||||
|
||||
Indien we het veld "username" willen omvormen naar kleine letters:
|
||||
|
||||
$post->filter('username', 'strtolower');
|
||||
|
||||
Als we alle witruimtes voor en na de waarde willen verwijderen voor *alle* velden:
|
||||
|
||||
$post->filter(TRUE, 'trim');
|
||||
|
||||
## Toevoegen van regels
|
||||
|
||||
Alle validatieregels worden gedefineerd als een veldnaam, een methode of een functie (gebruik makend van [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback) syntax) en een array van parameters:
|
||||
|
||||
$object->rule($field, $callback, $parameter);
|
||||
|
||||
Om ons voorbeeld te starten, zullen we validatie uitvoeren op een `$_POST` array die gebruikers registratie gegevens bevat:
|
||||
|
||||
$post = Validate::factory($_POST);
|
||||
|
||||
Vervolgens moeten we de POST-informatie met behulp van [Validate] doorlopen. Om te beginnen moeten we een aantal regels toevoegen:
|
||||
|
||||
$post
|
||||
->rule('username', 'not_empty')
|
||||
->rule('username', 'regex', array('/^[a-z_.]++$/iD'))
|
||||
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array('6'))
|
||||
->rule('confirm', 'matches', array('password'))
|
||||
|
||||
->rule('use_ssl', 'not_empty');
|
||||
|
||||
Iedere bestaande PHP functie kan worden gebruikt als regel. Bijvoorbeeld, als we willen controleren of een gebruiker een correcte waarde heeft ingevuld als antwoord op de SSL question:
|
||||
|
||||
$post->rule('use_ssl', 'in_array', array(array('yes', 'no')));
|
||||
|
||||
Merk op dat alle array parameters steeds moeten "verpakt" worden door een array! Zonder die array, `in_array` zou worden aangeroepen als `in_array($value, 'yes', 'no')`, wat een PHP error zou teruggeven.
|
||||
|
||||
Je kan eigen regels toevoegen met behulp van een [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback]:
|
||||
|
||||
$post->rule('username', 'User_Model::unique_username');
|
||||
|
||||
[!!] Momenteel (v3.0.7) is het niet mogelijk om een object te gebruiken als rule, enkel statische methodes en functies.
|
||||
|
||||
De methode `User_Model::unique_username()` zal ongeveer gedefinieerd worden als:
|
||||
|
||||
public static function unique_username($username)
|
||||
{
|
||||
// Controleer of de username al bestaat in de database
|
||||
return ! DB::select(array(DB::expr('COUNT(username)'), 'total'))
|
||||
->from('users')
|
||||
->where('username', '=', $username)
|
||||
->execute()
|
||||
->get('total');
|
||||
}
|
||||
|
||||
[!!] Zelfgeschreven regels laten toe om de vele extra controles te hergebruiken voor verschillende doeleinden. Deze functies zullen meestal bestaan in een model, maar kunnen gedefinieerd worden in elke class.
|
||||
|
||||
## Toevoegen van callbacks
|
||||
|
||||
Alle validatie-callbacks worden gedefineerd als een veldnaam en een methode of een functie (gebruik makend van [PHP callback](http://php.net/manual/language.pseudo-types.php#language.types.callback) syntax):
|
||||
|
||||
$object->callback($field, $callback);
|
||||
|
||||
[!!] In tegenstelling tot filters en regels, kunnen geen parameters worden meegestuurd naar een callback.
|
||||
|
||||
Het gebruikers wachtwoord moet gehashed worden indien het gevalideerd is, dus zulen we dit doen met een callback:
|
||||
|
||||
$post->callback('password', array($model, 'hash_password'));
|
||||
|
||||
Dit in de veronderstelling dat de `$model->hash_password()` methode er gelijkaardig uitzien als:
|
||||
|
||||
public function hash_password(Validate $array, $field)
|
||||
{
|
||||
if ($array[$field])
|
||||
{
|
||||
// Hash het wachtwoord als het bestaat
|
||||
$array[$field] = sha1($array[$field]);
|
||||
}
|
||||
}
|
||||
|
||||
# Een volledig voorbeeld
|
||||
|
||||
Eerst hewwen we een [View] nodig met daarin een HTML formulier, die we plaatsen in `application/views/user/register.php`:
|
||||
|
||||
<?php echo Form::open() ?>
|
||||
<?php if ($errors): ?>
|
||||
<p class="message">Er zijn enkele fouten opgelopen, gelieve je ingevoerde gegevens opnieuw te bekijken.</p>
|
||||
<ul class="errors">
|
||||
<?php foreach ($errors as $message): ?>
|
||||
<li><?php echo $message ?></li>
|
||||
<?php endforeach ?>
|
||||
<?php endif ?>
|
||||
|
||||
<dl>
|
||||
<dt><?php echo Form::label('username', 'Gebruikersnaam') ?></dt>
|
||||
<dd><?php echo Form::input('username', $post['username']) ?></dd>
|
||||
|
||||
<dt><?php echo Form::label('password', 'Wachtwoord') ?></dt>
|
||||
<dd><?php echo Form::password('password') ?></dd>
|
||||
<dd class="help">Wachtwoord moet minstens 6 karakters lang zijn.</dd>
|
||||
<dt><?php echo Form::label('confirm', 'Bevestig wachtwoord') ?></dt>
|
||||
<dd><?php echo Form::password('confirm') ?></dd>
|
||||
|
||||
<dt><?php echo Form::label('use_ssl', 'Gebruik extra veiligheid?') ?></dt>
|
||||
<dd><?php echo Form::select('use_ssl', array('yes' => 'Altijd', 'no' => 'Enkel indien nodig'), $post['use_ssl']) ?></dd>
|
||||
<dd class="help">Voor uw veiligheid wordt SSL altijd gebruik bij betalingen.</dd>
|
||||
</dl>
|
||||
|
||||
<?php echo Form::submit(NULL, 'Registreer') ?>
|
||||
<?php echo Form::close() ?>
|
||||
|
||||
[!!] Dit voorbeeld maakt veel gebruik van de [Form] helper. Het gebruik van [Form] in plaats van HTML schrijven zorgt ervoor dat alle formuliervelden overweg kunnen met ingevoerde waardes die HTML karakters bevatten. Indien je liever zelf HTML schrijft, gebruik dan zeker [HTML::chars] om gebruikersgegevens te "escapen".
|
||||
|
||||
Vervolgens hebben we een controller nodig en een actie om de registratie uit te voeren, we plaatsen dit in `application/classes/controller/user.php`:
|
||||
|
||||
class Controller_User extends Controller {
|
||||
|
||||
public function action_register()
|
||||
{
|
||||
$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', array($user, 'unique_username'))
|
||||
|
||||
->rule('password', 'not_empty')
|
||||
->rule('password', 'min_length', array('6'))
|
||||
->rule('confirm', 'matches', array('password'))
|
||||
|
||||
->rule('use_ssl', 'not_empty')
|
||||
->rule('use_ssl', 'in_array', array(array('yes', 'no')))
|
||||
|
||||
->callback('password', array($user, 'hash_password'));
|
||||
|
||||
if ($post->check())
|
||||
{
|
||||
// Data is gevalideerd, registreer de gebruiker
|
||||
$user->register($post);
|
||||
|
||||
// Altijd een redirect uitvoeren na een succesvolle POST om herladingsberichten te voorkomen.
|
||||
$this->request->redirect('user/profile');
|
||||
}
|
||||
|
||||
// Validatie is fout gelopen, verzamel alle errors
|
||||
$errors = $post->errors('user');
|
||||
|
||||
// Toon het registratieformulier
|
||||
$this->request->response = View::factory('user/register')
|
||||
->bind('post', $post)
|
||||
->bind('errors', $errors);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
We hebben ook een user-model nodig, we plaatsen dit in `application/classes/model/user.php`:
|
||||
|
||||
class Model_User extends Model {
|
||||
|
||||
public function register($array)
|
||||
{
|
||||
// Maak een nieuw gebruikerslijn aan in de database
|
||||
$id = DB::insert(array_keys($array))
|
||||
->values($array)
|
||||
->execute();
|
||||
|
||||
// Bewaar het nieuwe gebruikers id in een cookie
|
||||
cookie::set('user', $id);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Dat is het, we hebben een volledig gebruikersregistratie voorbeeld afgewerkt dat zorgvuldig ingevoerde gegevens controleert.
|
@@ -1,15 +0,0 @@
|
||||
# Cross-Site Scripting (XSS) Veiligheid
|
||||
|
||||
De eerste stap om [XSS](http://wikipedia.org/wiki/Cross-Site_Scripting)-aanvallen te voorkomen is weten wanneer je jezelf moet beschermen. XSS kan enkel worden geactiveerd wanneer het wordt weergegeven in de HTML-inhoud, dit kan soms via een formulier-veld of worden getoond van database resultaten. Elke globale variabele dat gebruikersgegevens bevat kan worden aangetast. Dit omvat `$ _GET`, `$ _POST` en `$ _COOKIE` gegevens.
|
||||
|
||||
## Het voorkomen
|
||||
|
||||
Er zijn maar een paar eenvoudige regels te volgen om uw applicatie HTML te beschermen tegen XSS. De eerste stap is om de [Security::xss] methode te gebruiken om alle ingevoerde gegevens op te kuisen die afkomstig zijn van een globale variabele. Als je geen HTML wilt in een variable, gebruik dan [strip_tags](http://php.net/strip_tags) om alle ongewenste HTML tags te verwijderen van de ingevoerde waarde.
|
||||
|
||||
[!!] Als je gebruikers toelaat om HTML in te voeren in je applicatie, dan is het streng aanbevolen om een HTML "opkuis-tool" te gebruiken zoals [HTML Purifier](http://htmlpurifier.org/) of [HTML Tidy](http://php.net/tidy).
|
||||
|
||||
De tweede stap is om altijd de ingevoerde HTML te escapen. De [HTML] class voorziet generatoren voor veelvoorkomende tags, zo ook script en stylesheet links, ankers, afbeeldingen en e-mail (mailto) links. Elke niet-vertrouwde inhoud moet worden ge-escaped met [HTML::chars].
|
||||
|
||||
## Referenties
|
||||
|
||||
* [OWASP XSS Cheat Sheet](http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet)
|
@@ -1,248 +0,0 @@
|
||||
# Databases {#top}
|
||||
|
||||
Kohana 3.0 heeft een goede module ingebouwd om te kunnen werken met databases. Standaard ondersteund de database module drivers voor [MySQL](http://php.net/mysql) en [PDO](http://php.net/pdo).
|
||||
|
||||
De database module zit bij de Kohana 3.0 installatie maar het moet nog worden ingesteld vooraleer je het kan gebruiken. In je `application/bootstrap.php` bestand moet je de aanroep naar [Kohana::modules] aanpassen en de database module eraan toevoegen:
|
||||
|
||||
Kohana::modules(array(
|
||||
...
|
||||
'database' => MODPATH.'database',
|
||||
...
|
||||
));
|
||||
|
||||
## Configuratie {#configuration}
|
||||
|
||||
Nadat de module is ingesteld moet je een configuratie bestand aanmaken zodat de module weet hoe het moet connecteren met je database. Een voorbeeld configuratie bestand kan je vinden in `modules/database/config/database.php`.
|
||||
|
||||
De structuur van een database configuratie groep, genoemd "instantie", ziet er als volgt uit:
|
||||
|
||||
string INSTANCE_NAME => array(
|
||||
'type' => string DATABASE_TYPE,
|
||||
'connection' => array CONNECTION_ARRAY,
|
||||
'table_prefix' => string TABLE_PREFIX,
|
||||
'charset' => string CHARACTER_SET,
|
||||
'profiling' => boolean QUERY_PROFILING,
|
||||
),
|
||||
|
||||
[!!] Meerdere instanties van deze instellingen kunnen worden gedefinieerd binnen het configuratie bestand.
|
||||
|
||||
Het verstaan van elk van deze instellingen is belangrijk.
|
||||
|
||||
INSTANCE_NAME
|
||||
: Connecties kunnen elke naam hebben, maar je moet minstens één connectie hebben met de naam "default".
|
||||
|
||||
DATABASE_TYPE
|
||||
: Eén van de geïnstalleerde database drivers. Kohana heeft standaard de "mysql" en "pdo" drivers.
|
||||
|
||||
CONNECTION_ARRAY
|
||||
: Specifieke driver opties om te connecteren naar je database. (Driver opties worden uitgelegd [beneden](#connection_settings).)
|
||||
|
||||
TABLE_PREFIX
|
||||
: Voorvoegsel dat wordt toegevoegd aan al je tabelnamen door de [query builder](#query_building).
|
||||
|
||||
QUERY_PROFILING
|
||||
: Zet [profiling](debugging.profiling) aan van database queries.
|
||||
|
||||
### Voorbeeld
|
||||
|
||||
Het voorbeeld bestand hieronder toont 2 MySQL connecties, een lokale en één op afstand (=remote).
|
||||
|
||||
return array
|
||||
(
|
||||
'default' => array
|
||||
(
|
||||
'type' => 'mysql',
|
||||
'connection' => array(
|
||||
'hostname' => 'localhost',
|
||||
'username' => 'dbuser',
|
||||
'password' => 'mijnwachtwoord',
|
||||
'persistent' => FALSE,
|
||||
'database' => 'mijn_db_naam',
|
||||
),
|
||||
'table_prefix' => '',
|
||||
'charset' => 'utf8',
|
||||
'profiling' => TRUE,
|
||||
),
|
||||
'remote' => array(
|
||||
'type' => 'mysql',
|
||||
'connection' => array(
|
||||
'hostname' => '55.55.55.55',
|
||||
'username' => 'remote_user',
|
||||
'password' => 'mijnwachtwoord',
|
||||
'persistent' => FALSE,
|
||||
'database' => 'mijn_remote_db_naam',
|
||||
),
|
||||
'table_prefix' => '',
|
||||
'charset' => 'utf8',
|
||||
'profiling' => TRUE,
|
||||
),
|
||||
);
|
||||
|
||||
### Connectie instellingen {#connection_settings}
|
||||
|
||||
Iedere database driver heeft verschillende connectie instellingen.
|
||||
|
||||
#### MySQL
|
||||
|
||||
Een MySQL database accepteert de volgende opties in de `connection` array:
|
||||
|
||||
Type | Optie | Omschrijving | Standaard Waarde
|
||||
----------|------------|----------------------------| -------------------------
|
||||
`string` | hostname | Hostname van de database | `localhost`
|
||||
`integer` | port | Poort nummer | `NULL`
|
||||
`string` | socket | UNIX socket | `NULL`
|
||||
`string` | username | Database gebruikersnaam | `NULL`
|
||||
`string` | password | Database wachtwoord | `NULL`
|
||||
`boolean` | persistent | Persistente connecties | `FALSE`
|
||||
`string` | database | Database naam | `kohana`
|
||||
|
||||
#### PDO
|
||||
|
||||
Een PDO database accepteert de volgende opties in de `connection` array:
|
||||
|
||||
Type | Optie | Omschrijving | Standaard Waarde
|
||||
----------|------------|----------------------------| -------------------------
|
||||
`string` | dsn | PDO data source identifier | `localhost`
|
||||
`string` | username | Database gebruikersnaam | `NULL`
|
||||
`string` | password | Database wachtwoord | `NULL`
|
||||
`boolean` | persistent | Persistente connecties | `FALSE`
|
||||
|
||||
[!!] Als je PDO gebruikt en je bent niet zeker wat je moet gebruiken voor de `dsn` optie, bekijk dan [PDO::__construct](http://php.net/pdo.construct).
|
||||
|
||||
## Connecties en Instanties {#connections}
|
||||
|
||||
Iedere configuratie groep verwijst naar een database instantie. Iedere instantie kan worden aangesproken via [Database::instance]:
|
||||
|
||||
$default = Database::instance();
|
||||
$remote = Database::instance('remote');
|
||||
|
||||
Om de database los te koppelen, moet je gewoonweg het object vernietigen:
|
||||
|
||||
unset($default, Database::$instances['default']);
|
||||
|
||||
Om all database instanties in één keer los te koppelen, gebruik je:
|
||||
|
||||
Database::$instances = array();
|
||||
|
||||
## Het maken van Queries {#making_queries}
|
||||
|
||||
Er zijn twee verschillende manieren om queries te maken. De eenvoudigste manier om een query te maken is het gebruik van [Database_Query], via [DB::query]. Deze queries worden "prepared statements" genoemd en laat je toe om query parameters instellen die automatisch worden "geescaped". De tweede manier om een query te maken is door deze op te bouwen met behulp van methode-aanroepen. Dit wordt gedaan met behulp van de [query builder](#query_building).
|
||||
|
||||
[!!] Alle queries worden uitgevoerd via de `execute` methode, deze verwacht een [Database] object of een instantienaam. Zie [Database_Query::execute] voor meer informatie.
|
||||
|
||||
### Prepared Statements
|
||||
|
||||
Het gebruik van prepared statements laat je toe om SQL queries manueel te schrijven terwijl de query waarden nog steeds automatisch worden "geescaped" om [SQL injectie](http://wikipedia.org/wiki/SQL_Injection) te voorkomen. Een query aanmaken is relatief gemakkelijk:
|
||||
|
||||
$query = DB::query(Database::SELECT, 'SELECT * FROM users WHERE username = :user');
|
||||
|
||||
De [DB::query] factory methode creëert een nieuwe [Database_Query] class voor ons, zodat "methode-chaining" mogelijk is. De query bevat een `:user` parameter, die we kunnen toewijzen aan een waarde:
|
||||
|
||||
$query->param(':user', 'john');
|
||||
|
||||
[!!] Parameter namen kunnen elke string zijn aangezien worden vervangen via het gebruik van [strtr](http://php.net/strtr). Het wordt ten zeerste aanbevolen om **geen** dollar tekens te gebruiken als parameter namen om verwarring te voorkomen.
|
||||
|
||||
Als je de SQL wilt tonen dat zal worden uitgevoerd, moet je het object gewoonweg casten naar een string:
|
||||
|
||||
echo Kohana::debug((string) $query);
|
||||
// Zou moeten tonen:
|
||||
// SELECT * FROM users WHERE username = 'john'
|
||||
|
||||
Je kan ook altijd de `:user` parameter aanpassen door de [Database_Query::param] opnieuw aan te roepen:
|
||||
|
||||
$query->param(':user', $_GET['search']);
|
||||
|
||||
[!!] Indien je meerdere paramters in één keer wilt instellen kan je dat doen met [Database_Query::parameters].
|
||||
|
||||
Eénmaal je iets hebt toegewezen aan elke parameter, kan je de query uitvoeren:
|
||||
|
||||
$query->execute();
|
||||
|
||||
Het is ook mogelijk om een parameter te "verbinden" met een variabele, door het gebruik van een [variabele referentie]((http://php.net/language.references.whatdo)). Dit kan extreem gebruikvol zijn wanneer je dezelfde query meerdere keren moet uitvoeren:
|
||||
|
||||
$query = DB::query(Database::INSERT, 'INSERT INTO users (username, password) VALUES (:user, :pass)')
|
||||
->bind(':user', $username)
|
||||
->bind(':pass', $password);
|
||||
|
||||
foreach ($new_users as $username => $password)
|
||||
{
|
||||
$query->execute();
|
||||
}
|
||||
|
||||
In het bovenstaand voorbeeld worden de variabelen `$username` en `$password` gewijzigd in iedere loop van het `foreach` statement. Wanneer de parameter verandert, veranderen infeite de `:user` en `:pass` query parameters. Het zorgvuldig gebruik van parameter binding kan een pak code besparen.
|
||||
|
||||
### Query Building {#query_building}
|
||||
|
||||
Het maken van dynamische queries via objecten en methodes zorgt ervoor dat queries zeer snel kunnen worden geschreven op een agnostische manier. Query building voegt ook identifier (tabel en kolom naam) en value quoting toe.
|
||||
|
||||
[!!] Op dit moment, is het niet mogelijk om query building te combineren met prepared statements.
|
||||
|
||||
#### SELECT
|
||||
|
||||
Elk type database query wordt vertegenwoordigd door een andere class, elk met hun eigen methoden. Bijvoorbeeld, om een SELECT-query te maken, gebruiken we [DB::select]:
|
||||
|
||||
$query = DB::select()->from('users')->where('username', '=', 'john');
|
||||
|
||||
Standaard zal [DB::select] alle kolommen selecteren (`SELECT * ...`), maar je kan ook specificeren welke kolommen je wilt teruggeven:
|
||||
|
||||
$query = DB::select('username', 'password')->from('users')->where('username', '=', 'john');
|
||||
|
||||
Neem nu een minuut de tijd om te kijken wat deze methode-keten doet. Eerst maken we een selectie object met behulp van [DB::select]. Vervolgens stellen we tabel(len) in door de `from` methode te gebruiken. Als laatste stap zoeken we voor specifieke records door gebruik te maken van de `where` methode. We kunnen de SQL tonen dat zal worden uitgevoerd door deze te casten naar een string:
|
||||
|
||||
echo Kohana::debug((string) $query);
|
||||
// Zou moeten tonen:
|
||||
// SELECT `username`, `password` FROM `users` WHERE `username` = 'john'
|
||||
|
||||
Merk op hoe de kolom en tabel namen automatisch worden "geescaped", eveneens de waarden? Dit is een van de belangrijkste voordelen van het gebruik van de query builder.
|
||||
|
||||
Het is mogelijk om `AS` aliassen te maken wanneer je iets selecteert:
|
||||
|
||||
$query = DB::select(array('username', 'u'), array('password', 'p'))->from('users');
|
||||
|
||||
Deze query zal de volgende SQL genereren:
|
||||
|
||||
SELECT `username` AS `u`, `password` AS `p` FROM `users`
|
||||
|
||||
#### INSERT
|
||||
|
||||
Om records aan te maken in de database gebruik je [DB::insert] om een INSERT query aan te maken:
|
||||
|
||||
$query = DB::insert('users', array('username', 'password'))->values(array('fred', 'p@5sW0Rd'));
|
||||
|
||||
Deze query zal de volgende SQL genereren:
|
||||
|
||||
INSERT INTO `users` (`username`, `password`) VALUES ('fred', 'p@5sW0Rd')
|
||||
|
||||
#### UPDATE
|
||||
|
||||
Om een bestaande record aan te passen gebruik je [DB::update] om een UPDATE query aan te maken:
|
||||
|
||||
$query = DB::update('users')->set(array('username' => 'jane'))->where('username', '=', 'john');
|
||||
|
||||
Deze query zal de volgende SQL genereren:
|
||||
|
||||
UPDATE `users` SET `username` = 'jane' WHERE `username` = 'john'
|
||||
|
||||
#### DELETE
|
||||
|
||||
Om een bestaande record te verwijderen gebruik je [DB::delete] om een DELETE query aan te maken:
|
||||
|
||||
$query = DB::delete('users')->where('username', 'IN', array('john', 'jane'));
|
||||
|
||||
Deze query zal de volgende SQL genereren:
|
||||
|
||||
DELETE FROM `users` WHERE `username` IN ('john', 'jane')
|
||||
|
||||
#### Database Functies {#database_functions}
|
||||
|
||||
Uiteindelijk zal je waarschijnlijk uitdraaien in een situatie waar je beroep moet doen op `COUNT` of een andere database functie binnenin je query. De query builder ondersteunt deze functies op twee manieren. De eerste mogelijkheid is met behulp van aanhalingstekens binnenin de aliassen:
|
||||
|
||||
$query = DB::select(array('COUNT("username")', 'total_users'))->from('users');
|
||||
|
||||
Dit ziet er bijna precies hetzelfde uit als een standaard "AS" alias, maar let op hoe de kolom naam is verpakt in dubbele aanhalingstekens. Iedere keer als er een waarde met dubbele aanhalingstekens verschijnt binnenin een kolom naam, wordt **alleen** het gedeelte binnen de dubbele aanhalingstekens "geescaped". Deze query zal de volgende SQL genereren:
|
||||
|
||||
SELECT COUNT(`username`) AS `total_users` FROM `users`
|
||||
|
||||
#### Complexe Expressies
|
||||
|
||||
Aliassen met aanhalingstekens zullen de meeste problemen oplossen, maar van tijd tot tijd kan je in een situatie komen waar je een complexe expressie kunt gebruiken. In deze gevallen moet je een database expressie gebruiken die je kan creëren met [DB::expr]. Een database expressie wordt als directe input genomen en er wordt geen "escaping" uitgevoerd.
|
@@ -1,149 +0,0 @@
|
||||
# Werken met Git
|
||||
|
||||
Kohana gebruikt [git](http://git-scm.com/) als versie controle systeem en [github](http://github.com/kohana) voor community-bijdragen. Deze tutorial zal je tonen hoe je beide platformen kunt gebruiken om een applicatie op te zetten.
|
||||
|
||||
## Het installeren en instellen van Git op uw computer
|
||||
|
||||
### Installeren van Git
|
||||
|
||||
- OSX: [Git-OSX](http://code.google.com/p/git-osx-installer/)
|
||||
- Windows: [Msygit](http://code.google.com/p/msysgit/)
|
||||
- Of download het van de [git-site](http://git-scm.com/) en installeer het manueel (zie de git website)
|
||||
|
||||
### Basis globale instellingen
|
||||
|
||||
git config --global user.name "Uw Naam"
|
||||
git config --global user.email "uwemail@website.com"
|
||||
|
||||
### Extra, maar aan te raden instellingen
|
||||
|
||||
Om een beter visueel overzicht te hebben van de git commando's en repositories in je console stel je best volgende in:
|
||||
|
||||
git config --global color.diff auto
|
||||
git config --global color.status auto
|
||||
git config --global color.branch auto
|
||||
|
||||
### Automatische aanvulling installeren
|
||||
|
||||
[!!] Deze lijnen code zijn enkel van toepassing voor OSX
|
||||
|
||||
Deze lijnen code doen al het vuile werk voor je zodat automatische aanvulling kan werken voor uw git-omgeving
|
||||
|
||||
cd /tmp
|
||||
git clone git://git.kernel.org/pub/scm/git/git.git
|
||||
cd git
|
||||
git checkout v`git --version | awk '{print $3}'`
|
||||
cp contrib/completion/git-completion.bash ~/.git-completion.bash
|
||||
cd ~
|
||||
rm -rf /tmp/git
|
||||
echo -e "source ~/.git-completion.bash" >> .profile
|
||||
|
||||
### Gebruik altijd LF als regeleinden
|
||||
|
||||
Dit is de conventie die we maken met Kohana. Stel deze instellingen voor uw eigen goed en vooral als je wilt bijdragen aan de Kohana community.
|
||||
|
||||
git config --global core.autocrlf input
|
||||
git config --global core.savecrlf true
|
||||
|
||||
[!!] Meer informatie over regeleinden kan je vinden op [github](http://help.github.com/dealing-with-lineendings/)
|
||||
|
||||
### Meer informatie op je op weg te zetten
|
||||
|
||||
- [Git Screencasts](http://www.gitcasts.com/)
|
||||
- [Git Reference](http://gitref.org/)
|
||||
- [Pro Git book](http://progit.org/book/)
|
||||
|
||||
## Initi<74>le structuur
|
||||
|
||||
[!!] Deze tutorial zal ervan uitgaan dat uw webserver al is ingesteld, en dat je een nieuwe applicatie zal maken op <http://localhost/gitorial/>.
|
||||
|
||||
Met behulp van je console, ga naar de lege map `gitorial` en voer `git init` uit. Dit zal een ruwe structuur voor een nieuwe git repository aanmaken.
|
||||
|
||||
Vervolgend zullen we een [submodule](http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html) maken voor de `system` folder. Ga naar <http://github.com/kohana/core> en kopieer de "Clone URL":
|
||||
|
||||

|
||||
|
||||
Gebruik nu de URL om de submodule aan te maken voor `system`:
|
||||
|
||||
git submodule add git://github.com/kohana/core.git system
|
||||
|
||||
[!!] Dit cre<72>ert een link naar de huidige ontwikkelingsversie voor de volgende stabiele uitgave. De ontwikkelingsversie is meestal veilig om te gebruiken, het heeft dezelfde API als de huidige stabiele download maar met bugfixes al toegepast.
|
||||
|
||||
Voeg nu elke submodule toe dat je wil. Bijvoorbeeld als je de [Database] module nodig hebt:
|
||||
|
||||
git submodule add git://github.com/kohana/database.git modules/database
|
||||
|
||||
Nadat de submodules zijn toegevoegd, moet je ze nog initialiseren:
|
||||
|
||||
git submodule init
|
||||
|
||||
Nu dat de submodules zijn toegevoegd en geinitialiseerd, kan je ze commit'en:
|
||||
|
||||
git commit -m 'Added initial submodules'
|
||||
|
||||
Vervolgens cre<72>ren we de applicatie folder structuur. Hier is een absoluut minimum vereist:
|
||||
|
||||
mkdir -p application/classes/{controller,model}
|
||||
mkdir -p application/{config,views}
|
||||
mkdir -m 0777 -p application/{cache,logs}
|
||||
|
||||
Als je nu `find application` uitvoert, moet je dit zien:
|
||||
|
||||
application
|
||||
application/cache
|
||||
application/config
|
||||
application/classes
|
||||
application/classes/controller
|
||||
application/classes/model
|
||||
application/logs
|
||||
application/views
|
||||
|
||||
We willen niet dat git de log of cache bestanden volgt dus voegen we een `.gitignore` bestand toe aan deze folders. Dit zal alle niet-verborgen bestanden negeren:
|
||||
|
||||
echo '[^.]*' > application/{logs,cache}/.gitignore
|
||||
|
||||
[!!] Git negeert lege folders, dus het toevoegen van een `.gitignore` bestand zorgt er voor dat git de folder volgt maar niet de bestanden er in.
|
||||
|
||||
Nu hebben we nog de `index.php` en `bootstrap.php` bestanden nodig:
|
||||
|
||||
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
|
||||
|
||||
Commit deze veranderingen ook:
|
||||
|
||||
git add application
|
||||
git commit -m 'Added initial directory structure'
|
||||
|
||||
Dit is alles wat je nodig hebt. Je hebt nu een applicatie dat Git gebruikt als versiesysteem.
|
||||
|
||||
## Updaten van Submodules
|
||||
|
||||
Op een gegeven moment zal je waarschijnlijk ook je submodules willen upgraden. Om al je submodules te updaten naar de laatste "HEAD" versie:
|
||||
|
||||
git submodule foreach 'git checkout master && git pull origin master'
|
||||
|
||||
Om een enkele submodule te update, bijvoorbeel `system`:
|
||||
|
||||
cd system
|
||||
git checkout master
|
||||
git pull origin master
|
||||
cd ..
|
||||
git add system
|
||||
git commit -m 'Updated system to latest version'
|
||||
|
||||
Als je een enkele submodule wilt updaten naar een specifieke commit:
|
||||
|
||||
cd modules/database
|
||||
git pull origin master
|
||||
git checkout fbfdea919028b951c23c3d99d2bc1f5bbeda0c0b
|
||||
cd ../..
|
||||
git add database
|
||||
git commit -m 'Updated database module'
|
||||
|
||||
Merk op dat je ook een commit kunt uitchecken via een tag, zoals een officieel versie, bijvoorbeeld:
|
||||
|
||||
git checkout 3.0.6
|
||||
|
||||
Voer gewoon `git tag` uit zonder parameters om een lijst van alle tags te krijgen.
|
||||
|
||||
U weet nu "alles" over git!
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user