Added Kohana v3.0.8

This commit is contained in:
Deon George
2010-08-21 14:43:03 +10:00
parent 27aee719b0
commit 64bdbdc981
558 changed files with 58712 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
# 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).

View File

@@ -0,0 +1,95 @@
# 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;
~~~

View File

@@ -0,0 +1,26 @@
# 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.

View File

@@ -0,0 +1,13 @@
# 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:
![Cascading Filesystem Infographic](img/cascading_filesystem.png)
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é.

View File

@@ -0,0 +1,21 @@
# 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

View File

@@ -0,0 +1,20 @@
# 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.
![Install Page](img/install.png "Example of install page")
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:
![Welcome Page](img/welcome.png "Example of welcome page")

View File

@@ -0,0 +1,11 @@
# 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/ModelViewController "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.

View File

@@ -0,0 +1,5 @@
# 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.

View File

@@ -0,0 +1,290 @@
# 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');
`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();
}
}

View File

@@ -0,0 +1,24 @@
# 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');
~~~

View File

@@ -0,0 +1,24 @@
# 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));
~~~

View File

@@ -0,0 +1,22 @@
# 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}}

View File

@@ -0,0 +1 @@
Cette page liste les fonctionnalités clés de Kohana v3.

View File

@@ -0,0 +1,26 @@
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)

View File

@@ -0,0 +1,3 @@
# Sécurité des Cookies
[!!] stub

View File

@@ -0,0 +1,3 @@
# Sécurité de la Base de données
[!!] stub

View File

@@ -0,0 +1,241 @@
# 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.

View File

@@ -0,0 +1,17 @@
# 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)

View File

@@ -0,0 +1,242 @@
# 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.

View File

@@ -0,0 +1,117 @@
# 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:
![Github Clone URL](http://img.skitch.com/20091019-rud5mmqbf776jwua6hx9nm1n.png)
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'
~~~

View File

@@ -0,0 +1,103 @@
# 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:
![Hello, World!](img/hello_world_1.png "Hello, World!")
## 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:
![hello, world! We just wanted to say it!](img/hello_world_2.png "hello, world! We just wanted to say it!")
## 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 ;).

View File

@@ -0,0 +1,121 @@
# 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.

View File

@@ -0,0 +1,163 @@
# 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