diff --git a/application/bootstrap.php b/application/bootstrap.php index d12c416c..e49c28d1 100644 --- a/application/bootstrap.php +++ b/application/bootstrap.php @@ -1,6 +1,20 @@ " + */ +if (isset($_SERVER['KOHANA_ENV'])) +{ + Kohana::$environment = constant('Kohana::'.strtoupper($_SERVER['KOHANA_ENV'])); +} /** * Initialize Kohana, setting the default options. @@ -57,12 +87,12 @@ Kohana::init(array( /** * Attach the file write to logging. Multiple writers are supported. */ -Kohana::$log->attach(new Kohana_Log_File(APPPATH.'logs')); +Kohana::$log->attach(new Log_File(APPPATH.'logs')); /** * Attach a file reader to config. Multiple readers are supported. */ -Kohana::$config->attach(new Kohana_Config_File); +Kohana::$config->attach(new Config_File); /** * Enable modules. Modules are referenced by a relative or absolute path. @@ -74,13 +104,11 @@ Kohana::modules(array( 'database' => SMDPATH.'database', // Database access // 'image' => SMDPATH.'image', // Image manipulation 'orm' => SMDPATH.'orm', // Object Relationship Mapping - // 'oauth' => SMDPATH.'oauth', // OAuth authentication - // 'pagination' => SMDPATH.'pagination', // Paging of results // 'unittest' => SMDPATH.'unittest', // Unit testing - // 'userguide' => SMDPATH.'userguide', // User guide and API documentation - 'xml' => SMDPATH.'xml', // XML module for Kohana 3 PHP Framework - 'email' => SMDPATH.'email', // Email module for Kohana 3 PHP Framework - 'gchart' => MODPATH.'gchart', // Google Chart Module + 'userguide' => SMDPATH.'userguide', // User guide and API documentation + 'email' => SMDPATH.'email', // Email module for Kohana 3 PHP Framework + 'gchart' => MODPATH.'gchart', // Google Chart Module + 'xml' => SMDPATH.'xml', // XML module for Kohana 3 PHP Framework )); /** @@ -113,21 +141,3 @@ Route::set('default/media', 'media(/)', array('file' => '.+')) 'action' => 'media', 'file' => NULL, )); - -// Make sure their PHP version is current enough -if (strcmp(phpversion(),'5.3') < 0) { - echo 'This application requires PHP 5.3 or newer to run'; - die(); -} - -if ( ! defined('SUPPRESS_REQUEST')) -{ - /** - * Execute the main request. A source of the URI can be passed, eg: $_SERVER['PATH_INFO']. - * If no source is specified, the URI will be automatically detected. - */ - echo Request::instance() - ->execute() - ->send_headers() - ->response; -} diff --git a/includes/kohana/README.md b/includes/kohana/README.md index 97e31dc3..e19aba89 100644 --- a/includes/kohana/README.md +++ b/includes/kohana/README.md @@ -1,3 +1,3 @@ -# Kohana PHP Framework, version 3.0 (dev) +# Kohana PHP Framework, version 3.1 (release) -This is the current development version of [Kohana](http://kohanaframework.org/). +This is the current release version of [Kohana](http://kohanaframework.org/). diff --git a/includes/kohana/install.php b/includes/kohana/install.php index 37d15300..cbb0a4c5 100644 --- a/includes/kohana/install.php +++ b/includes/kohana/install.php @@ -1,12 +1,4 @@ - + @@ -171,12 +163,20 @@ clearstatcache(TRUE);

+ + + + + + + + - + @@ -195,6 +195,14 @@ clearstatcache(TRUE); + + + + + + + + diff --git a/includes/kohana/modules/auth/README.md b/includes/kohana/modules/auth/README.md new file mode 100644 index 00000000..27ac9cd7 --- /dev/null +++ b/includes/kohana/modules/auth/README.md @@ -0,0 +1,13 @@ +New Age Auth +--- + +I've forked the main Auth module because there were some fundamental flaws with it: + + 1. It's trivial to [bruteforce](http://dev.kohanaframework.org/issues/3163) publicly hidden salt hashes. + - I've fixed this by switching the password hashing algorithm to the more secure secret-key based hash_hmac method. + 2. ORM drivers were included. + - I've fixed this by simply removing them. They cause confusion with new users because they think that Auth requires ORM. The only driver currently provided by default is the file driver. + 3. Auth::get_user()'s api is inconsistent because it returns different data types. + - I've fixed this by returning an empty user model by default. You can override what gets returned (if you've changed your user model class name for instance) by overloading the get_user() method in your application. + +These changes should be merged into the mainline branch eventually, but they completely break the API, so likely won't be done until 3.1. \ No newline at end of file diff --git a/includes/kohana/modules/auth/classes/kohana/auth.php b/includes/kohana/modules/auth/classes/kohana/auth.php index f9989c7d..c5030e8a 100644 --- a/includes/kohana/modules/auth/classes/kohana/auth.php +++ b/includes/kohana/modules/auth/classes/kohana/auth.php @@ -5,8 +5,8 @@ * * @package Kohana/Auth * @author Kohana Team - * @copyright (c) 2007-2009 Kohana Team - * @license http://kohanaphp.com/license.html + * @copyright (c) 2007-2010 Kohana Team + * @license http://kohanaframework.org/license */ abstract class Kohana_Auth { @@ -27,7 +27,7 @@ abstract class Kohana_Auth { if ( ! $type = $config->get('driver')) { - $type = 'ORM'; + $type = 'file'; } // Set the session class name @@ -40,16 +40,6 @@ abstract class Kohana_Auth { return Auth::$_instance; } - /** - * Create an instance of Auth. - * - * @return Auth - */ - public static function factory($config = array()) - { - return new Auth($config); - } - protected $_session; protected $_config; @@ -61,9 +51,6 @@ abstract class Kohana_Auth { */ public function __construct($config = array()) { - // Clean up the salt pattern and split it into an array - $config['salt_pattern'] = preg_split('/,\s*/', Kohana::config('auth')->get('salt_pattern')); - // Save the config in the object $this->_config = $config; @@ -78,13 +65,13 @@ abstract class Kohana_Auth { /** * Gets the currently logged in user from the session. - * Returns FALSE if no user is currently logged in. + * Returns NULL if no user is currently logged in. * * @return mixed */ - public function get_user() + public function get_user($default = NULL) { - return $this->_session->get($this->_config['session_key'], FALSE); + return $this->_session->get($this->_config['session_key'], $default); } /** @@ -102,11 +89,8 @@ abstract class Kohana_Auth { if (is_string($password)) { - // Get the salt from the stored password - $salt = $this->find_salt($this->password($username)); - - // Create a hashed password using the salt from the stored password - $password = $this->hash_password($password, $salt); + // Create a hashed password + $password = $this->hash($password); } return $this->_login($username, $password, $remember); @@ -141,90 +125,40 @@ abstract class Kohana_Auth { /** * Check if there is an active session. Optionally allows checking for a - * specific role. + * specific role. * * @param string role name * @return mixed */ public function logged_in($role = NULL) { - return FALSE !== $this->get_user(); + return ($this->get_user() !== NULL); } /** - * Creates a hashed password from a plaintext password, inserting salt - * based on the configured salt pattern. + * Creates a hashed hmac password from a plaintext password. This + * method is deprecated, [Auth::hash] should be used instead. * + * @deprecated * @param string plaintext password - * @return string hashed password string */ - public function hash_password($password, $salt = FALSE) + public function hash_password($password) { - if ($salt === FALSE) - { - // Create a salt seed, same length as the number of offsets in the pattern - $salt = substr($this->hash(uniqid(NULL, TRUE)), 0, count($this->_config['salt_pattern'])); - } - - // Password hash that the salt will be inserted into - $hash = $this->hash($salt.$password); - - // Change salt to an array - $salt = str_split($salt, 1); - - // Returned password - $password = ''; - - // Used to calculate the length of splits - $last_offset = 0; - - foreach ($this->_config['salt_pattern'] as $offset) - { - // Split a new part of the hash off - $part = substr($hash, 0, $offset - $last_offset); - - // Cut the current part out of the hash - $hash = substr($hash, $offset - $last_offset); - - // Add the part to the password, appending the salt character - $password .= $part.array_shift($salt); - - // Set the last offset to the current offset - $last_offset = $offset; - } - - // Return the password, with the remaining hash appended - return $password.$hash; + return $this->hash($password); } /** - * Perform a hash, using the configured method. + * Perform a hmac hash, using the configured method. * * @param string string to hash * @return string */ public function hash($str) { - return hash($this->_config['hash_method'], $str); - } + if ( ! $this->_config['hash_key']) + throw new Kohana_Exception('A valid hash key must be set in your auth config.'); - /** - * Finds the salt from a password, based on the configured salt pattern. - * - * @param string hashed password - * @return string - */ - public function find_salt($password) - { - $salt = ''; - - foreach ($this->_config['salt_pattern'] as $i => $offset) - { - // Find salt characters, take a good long look... - $salt .= substr($password, $offset + $i, 1); - } - - return $salt; + return hash_hmac($this->_config['hash_method'], $str, $this->_config['hash_key']); } protected function complete_login($user) @@ -238,4 +172,4 @@ abstract class Kohana_Auth { return TRUE; } -} // End Auth \ No newline at end of file +} // End Auth diff --git a/includes/kohana/modules/auth/classes/kohana/auth/file.php b/includes/kohana/modules/auth/classes/kohana/auth/file.php index 439f17fa..31ca0c3b 100644 --- a/includes/kohana/modules/auth/classes/kohana/auth/file.php +++ b/includes/kohana/modules/auth/classes/kohana/auth/file.php @@ -5,8 +5,8 @@ * * @package Kohana/Auth * @author Kohana Team - * @copyright (c) 2007-2008 Kohana Team - * @license http://kohanaphp.com/license.html + * @copyright (c) 2007-2010 Kohana Team + * @license http://kohanaframework.org/license */ class Kohana_Auth_File extends Auth { diff --git a/includes/kohana/modules/auth/classes/model/auth/user.php b/includes/kohana/modules/auth/classes/model/auth/user.php deleted file mode 100644 index 179391ba..00000000 --- a/includes/kohana/modules/auth/classes/model/auth/user.php +++ /dev/null @@ -1,244 +0,0 @@ - array('model' => 'user_token'), - 'roles' => array('model' => 'role', 'through' => 'roles_users'), - ); - - // Validation rules - protected $_rules = array( - 'username' => array( - 'not_empty' => NULL, - 'min_length' => array(4), - 'max_length' => array(32), - 'regex' => array('/^[-\pL\pN_.]++$/uD'), - ), - 'password' => array( - 'not_empty' => NULL, - 'min_length' => array(5), - 'max_length' => array(42), - ), - 'password_confirm' => array( - 'matches' => array('password'), - ), - 'email' => array( - 'not_empty' => NULL, - 'min_length' => array(4), - 'max_length' => array(127), - 'email' => NULL, - ), - ); - - // Validation callbacks - protected $_callbacks = array( - 'username' => array('username_available'), - 'email' => array('email_available'), - ); - - // Field labels - protected $_labels = array( - 'username' => 'username', - 'email' => 'email address', - 'password' => 'password', - 'password_confirm' => 'password confirmation', - ); - - // Columns to ignore - protected $_ignored_columns = array('password_confirm'); - - /** - * Validates login information from an array, and optionally redirects - * after a successful login. - * - * @param array values to check - * @param string URI or URL to redirect to - * @return boolean - */ - public function login(array & $array, $redirect = FALSE) - { - $fieldname = $this->unique_key($array['username']); - $array = Validate::factory($array) - ->label('username', $this->_labels[$fieldname]) - ->label('password', $this->_labels['password']) - ->filter(TRUE, 'trim') - ->rules('username', $this->_rules[$fieldname]) - ->rules('password', $this->_rules['password']); - - // Get the remember login option - $remember = isset($array['remember']); - - // Login starts out invalid - $status = FALSE; - - if ($array->check()) - { - // Attempt to load the user - $this->where($fieldname, '=', $array['username'])->find(); - - if ($this->loaded() AND Auth::instance()->login($this, $array['password'], $remember)) - { - if (is_string($redirect)) - { - // Redirect after a successful login - Request::instance()->redirect($redirect); - } - - // Login is successful - $status = TRUE; - } - else - { - $array->error('username', 'invalid'); - } - } - - return $status; - } - - /** - * Validates an array for a matching password and password_confirm field, - * and optionally redirects after a successful save. - * - * @param array values to check - * @param string URI or URL to redirect to - * @return boolean - */ - public function change_password(array & $array, $redirect = FALSE) - { - $array = Validate::factory($array) - ->label('password', $this->_labels['password']) - ->label('password_confirm', $this->_labels['password_confirm']) - ->filter(TRUE, 'trim') - ->rules('password', $this->_rules['password']) - ->rules('password_confirm', $this->_rules['password_confirm']); - - if ($status = $array->check()) - { - // Change the password - $this->password = $array['password']; - - if ($status = $this->save() AND is_string($redirect)) - { - // Redirect to the success page - Request::instance()->redirect($redirect); - } - } - - return $status; - } - - /** - * Complete the login for a user by incrementing the logins and saving login timestamp - * - * @return void - */ - public function complete_login() - { - if ( ! $this->_loaded) - { - // nothing to do - return; - } - - // Update the number of logins - $this->logins = new Database_Expression('logins + 1'); - - // Set the last login date - $this->last_login = time(); - - // Save the user - $this->save(); - } - - /** - * Does the reverse of unique_key_exists() by triggering error if username exists. - * Validation callback. - * - * @param Validate Validate object - * @param string field name - * @return void - */ - public function username_available(Validate $array, $field) - { - if ($this->unique_key_exists($array[$field], 'username')) - { - $array->error($field, 'username_available', array($array[$field])); - } - } - - /** - * Does the reverse of unique_key_exists() by triggering error if email exists. - * Validation callback. - * - * @param Validate Validate object - * @param string field name - * @return void - */ - public function email_available(Validate $array, $field) - { - if ($this->unique_key_exists($array[$field], 'email')) - { - $array->error($field, 'email_available', array($array[$field])); - } - } - - /** - * Tests if a unique key value exists in the database. - * - * @param mixed the value to test - * @param string field name - * @return boolean - */ - public function unique_key_exists($value, $field = NULL) - { - if ($field === NULL) - { - // Automatically determine field by looking at the value - $field = $this->unique_key($value); - } - - return (bool) DB::select(array('COUNT("*")', 'total_count')) - ->from($this->_table_name) - ->where($field, '=', $value) - ->where($this->_primary_key, '!=', $this->pk()) - ->execute($this->_db) - ->get('total_count'); - } - - /** - * Allows a model use both email and username as unique identifiers for login - * - * @param string unique value - * @return string field name - */ - public function unique_key($value) - { - return Validate::email($value) ? 'email' : 'username'; - } - - /** - * Saves the current object. Will hash password if it was changed. - * - * @return ORM - */ - public function save() - { - if (array_key_exists('password', $this->_changed)) - { - $this->_object['password'] = Auth::instance()->hash_password($this->_object['password']); - } - - return parent::save(); - } - -} // End Auth User Model \ No newline at end of file diff --git a/includes/kohana/modules/auth/classes/model/auth/user/token.php b/includes/kohana/modules/auth/classes/model/auth/user/token.php deleted file mode 100644 index e7d820c0..00000000 --- a/includes/kohana/modules/auth/classes/model/auth/user/token.php +++ /dev/null @@ -1,101 +0,0 @@ - array()); - - // Current timestamp - protected $_now; - - /** - * Handles garbage collection and deleting of expired objects. - * - * @return void - */ - public function __construct($id = NULL) - { - parent::__construct($id); - - // Set the now, we use this a lot - $this->_now = time(); - - if (mt_rand(1, 100) === 1) - { - // Do garbage collection - $this->delete_expired(); - } - - if ($this->expires < $this->_now) - { - // This object has expired - $this->delete(); - } - } - - /** - * Overload saving to set the created time and to create a new token - * when the object is saved. - * - * @return ORM - */ - public function save() - { - if ($this->loaded() === FALSE) - { - // Set the created time, token, and hash of the user agent - $this->created = $this->_now; - $this->user_agent = sha1(Request::$user_agent); - } - - while (TRUE) - { - // Generate a new token - $this->token = $this->create_token(); - - try - { - return parent::save(); - } - catch (Kohana_Database_Exception $e) - { - // Collision occurred, token is not unique - } - } - } - - /** - * Deletes all expired tokens. - * - * @return ORM - */ - public function delete_expired() - { - // Delete all expired tokens - DB::delete($this->_table_name) - ->where('expires', '<', $this->_now) - ->execute($this->_db); - - return $this; - } - - /** - * Generate a new unique token. - * - * @return string - * @uses Text::random - */ - protected function create_token() - { - // Create a random token - return Text::random('alnum', 32); - } - -} // End Auth User Token Model \ No newline at end of file diff --git a/includes/kohana/modules/auth/config/auth.php b/includes/kohana/modules/auth/config/auth.php index 3d18e7b7..0d802087 100644 --- a/includes/kohana/modules/auth/config/auth.php +++ b/includes/kohana/modules/auth/config/auth.php @@ -2,9 +2,9 @@ return array( - 'driver' => 'ORM', - 'hash_method' => 'sha1', - 'salt_pattern' => '1, 3, 5, 9, 14, 15, 20, 21, 28, 30', + 'driver' => 'file', + 'hash_method' => 'sha256', + 'hash_key' => NULL, 'lifetime' => 1209600, 'session_key' => 'auth_user', @@ -13,4 +13,4 @@ return array( // 'admin' => 'b3154acf3a344170077d11bdb5fff31532f679a1919e716a02', ), -); \ No newline at end of file +); diff --git a/includes/kohana/modules/auth/guide/auth/config.md b/includes/kohana/modules/auth/guide/auth/config.md new file mode 100644 index 00000000..e69de29b diff --git a/includes/kohana/modules/auth/guide/auth/edit.md b/includes/kohana/modules/auth/guide/auth/edit.md new file mode 100644 index 00000000..e69de29b diff --git a/includes/kohana/modules/auth/guide/auth/index.md b/includes/kohana/modules/auth/guide/auth/index.md new file mode 100644 index 00000000..e69de29b diff --git a/includes/kohana/modules/auth/guide/auth/login.md b/includes/kohana/modules/auth/guide/auth/login.md new file mode 100644 index 00000000..e69de29b diff --git a/includes/kohana/modules/auth/guide/auth/menu.md b/includes/kohana/modules/auth/guide/auth/menu.md new file mode 100644 index 00000000..1708caa9 --- /dev/null +++ b/includes/kohana/modules/auth/guide/auth/menu.md @@ -0,0 +1,7 @@ +## [Auth]() +- [Config](config) +- [User Model](user) +- [Register Users](register) +- [Log in and out](login) +- [Edit User](edit) +- [Using Roles](roles) diff --git a/includes/kohana/modules/auth/guide/auth/register.md b/includes/kohana/modules/auth/guide/auth/register.md new file mode 100644 index 00000000..e69de29b diff --git a/includes/kohana/modules/auth/guide/auth/roles.md b/includes/kohana/modules/auth/guide/auth/roles.md new file mode 100644 index 00000000..e69de29b diff --git a/includes/kohana/modules/auth/guide/auth/user.md b/includes/kohana/modules/auth/guide/auth/user.md new file mode 100644 index 00000000..e69de29b diff --git a/includes/kohana/modules/cache/README.md b/includes/kohana/modules/cache/README.md index 8c486cb7..cd04fbde 100644 --- a/includes/kohana/modules/cache/README.md +++ b/includes/kohana/modules/cache/README.md @@ -15,6 +15,7 @@ Currently this module supports the following cache methods. 5. SQLite (Supports tags) 6. File 7. Xcache +8. Wincache Planned support --------------- diff --git a/includes/kohana/modules/cache/classes/cache/wincache.php b/includes/kohana/modules/cache/classes/cache/wincache.php new file mode 100644 index 00000000..603e446a --- /dev/null +++ b/includes/kohana/modules/cache/classes/cache/wincache.php @@ -0,0 +1,3 @@ +_sanitize_id($id))) === FALSE) ? $default : $data; + $data = apc_fetch($this->_sanitize_id($id), $success); + + return $success ? $data : $default; } /** @@ -130,4 +132,4 @@ class Kohana_Cache_Apc extends Cache { { return apc_clear_cache('user'); } -} \ No newline at end of file +} diff --git a/includes/kohana/modules/cache/classes/kohana/cache/eaccelerator.php b/includes/kohana/modules/cache/classes/kohana/cache/eaccelerator.php index 7abcd775..96c97f50 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache/eaccelerator.php +++ b/includes/kohana/modules/cache/classes/kohana/cache/eaccelerator.php @@ -30,8 +30,8 @@ * * PHP 5.2.4 or greater * * Eaccelerator PHP extension * - * @package Kohana - * @category Cache + * @package Kohana/Cache + * @category Base * @author Kohana Team * @copyright (c) 2009-2010 Kohana Team * @license http://kohanaphp.com/license @@ -130,4 +130,4 @@ class Kohana_Cache_Eaccelerator extends Cache { { return eaccelerator_clean(); } -} \ No newline at end of file +} diff --git a/includes/kohana/modules/cache/classes/kohana/cache/exception.php b/includes/kohana/modules/cache/classes/kohana/cache/exception.php index f8677e78..d89d25eb 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache/exception.php +++ b/includes/kohana/modules/cache/classes/kohana/cache/exception.php @@ -1,3 +1,11 @@ _config, 'cache_dir', APPPATH.Cache_File::CACHE_DIR); - $this->_cache_dir = new RecursiveDirectoryIterator($directory); + $directory = Arr::get($this->_config, 'cache_dir', Kohana::$cache_dir); + $this->_cache_dir = new SplFileInfo($directory); } + // PHP < 5.3 exception handle + catch (ErrorException $e) + { + $this->_cache_dir = $this->_make_directory($directory, 0777, TRUE); + } + // PHP >= 5.3 exception handle catch (UnexpectedValueException $e) { - if ( ! mkdir($directory, 0777, TRUE)) - { - throw new Kohana_Cache_Exception('Failed to create the defined cache directory : :directory', array(':directory' => $directory)); - } - chmod($directory, 0777); - $this->_cache_dir = new RecursiveDirectoryIterator($directory); + $this->_cache_dir = $this->_make_directory($directory, 0777, TRUE); } // If the defined directory is a file, get outta here @@ -138,7 +133,7 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect { $file = new SplFileInfo($directory.$filename); // If file does not exist - if ( ! $file->getRealPath()) + if ( ! $file->isFile()) { // Return default value return $default; @@ -233,7 +228,7 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect { $type = gettype($data); // Serialize the data - $data = json_encode((object) array( + $data = json_encode( (object) array( 'payload' => ($type === 'string') ? $data : serialize($data), 'expiry' => time() + $lifetime, 'type' => $type @@ -366,7 +361,7 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect { } } // Else, is directory - else if ($file->isDir()) + elseif ($file->isDir()) { // Create new DirectoryIterator $files = new DirectoryIterator($file->getPathname()); @@ -378,7 +373,7 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect { $name = $files->getFilename(); // If the name is not a dot - if ($name != '.' and $name != '..') + if ($name != '.' AND $name != '..' AND substr($file->getFilename(), 0, 1) == '.') { // Create new file resource $fp = new SplFileInfo($files->getRealPath()); @@ -442,4 +437,27 @@ class Kohana_Cache_File extends Cache implements Kohana_Cache_GarbageCollect { { return $this->_cache_dir->getRealPath().DIRECTORY_SEPARATOR.$filename[0].$filename[1].DIRECTORY_SEPARATOR; } + + /** + * Makes the cache directory if it doesn't exist. Simply a wrapper for + * `mkdir` to ensure DRY principles + * + * @see http://php.net/manual/en/function.mkdir.php + * @param string directory + * @param string mode + * @param string recursive + * @param string context + * @return SplFileInfo + * @throws Kohana_Cache_Exception + */ + protected function _make_directory($directory, $mode = 0777, $recursive = FALSE, $context = NULL) + { + if ( ! mkdir($directory, $mode, $recursive, $context)) + { + throw new Kohana_Cache_Exception('Failed to create the defined cache directory : :directory', array(':directory' => $directory)); + } + chmod($directory, $mode); + + return new SplFileInfo($directory);; + } } diff --git a/includes/kohana/modules/cache/classes/kohana/cache/garbagecollect.php b/includes/kohana/modules/cache/classes/kohana/cache/garbagecollect.php index 228dd610..62c3148e 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache/garbagecollect.php +++ b/includes/kohana/modules/cache/classes/kohana/cache/garbagecollect.php @@ -4,8 +4,8 @@ * of their own, such as [Cache_File] and [Cache_Sqlite]. Memory based * cache systems clean their own caches periodically. * - * @package Kohana - * @category Cache + * @package Kohana/Cache + * @category Base * @version 2.0 * @author Kohana Team * @copyright (c) 2009-2010 Kohana Team @@ -20,4 +20,4 @@ interface Kohana_Cache_GarbageCollect { * @return void */ public function garbage_collect(); -} \ No newline at end of file +} diff --git a/includes/kohana/modules/cache/classes/kohana/cache/memcache.php b/includes/kohana/modules/cache/classes/kohana/cache/memcache.php index e67c2496..c377dc46 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache/memcache.php +++ b/includes/kohana/modules/cache/classes/kohana/cache/memcache.php @@ -24,6 +24,7 @@ * 'timeout' => 1, * 'retry_interval' => 15, * 'status' => TRUE, + * 'instant_death' => TRUE, * 'failure_callback' => array('className', 'classMethod') * ), * // Second memcache server @@ -72,8 +73,8 @@ * * Memcache (plus Memcached-tags for native tagging support) * * Zlib * - * @package Kohana - * @category Cache + * @package Kohana/Cache + * @category Base * @version 2.0 * @author Kohana Team * @copyright (c) 2009-2010 Kohana Team @@ -98,6 +99,13 @@ class Kohana_Cache_Memcache extends Cache { */ protected $_flags; + /** + * The default configuration for the memcached server + * + * @var array + */ + protected $_default_config = array(); + /** * Constructs the memcache Kohana_Cache object * @@ -127,22 +135,23 @@ class Kohana_Cache_Memcache extends Cache { } // Setup default server configuration - $config = array( - 'host' => 'localhost', - 'port' => 11211, - 'persistent' => FALSE, - 'weight' => 1, - 'timeout' => 1, - 'retry_interval' => 15, - 'status' => TRUE, - 'failure_callback' => array($this, '_failed_request'), + $this->_default_config = array( + 'host' => 'localhost', + 'port' => 11211, + 'persistent' => FALSE, + 'weight' => 1, + 'timeout' => 1, + 'retry_interval' => 15, + 'status' => TRUE, + 'instant_death' => TRUE, + 'failure_callback' => array($this, '_failed_request'), ); // Add the memcache servers to the pool foreach ($servers as $server) { // Merge the defined config with defaults - $server += $config; + $server += $this->_default_config; if ( ! $this->_memcache->addServer($server['host'], $server['port'], $server['persistent'], $server['weight'], $server['timeout'], $server['retry_interval'], $server['status'], $server['failure_callback'])) { @@ -276,7 +285,7 @@ class Kohana_Cache_Memcache extends Cache { * @return void|boolean * @since 3.0.8 */ - protected function _failed_request($hostname, $port) + public function _failed_request($hostname, $port) { if ( ! $this->_config['instant_death']) return; @@ -287,8 +296,12 @@ class Kohana_Cache_Memcache extends Cache { // Get host settings from configuration foreach ($this->_config['servers'] as $server) { + // Merge the defaults, since they won't always be set + $server += $this->_default_config; + // We're looking at the failed server if ($hostname == $server['host'] and $port == $server['port']) { + // Server to disable, since it failed $host = $server; continue; } @@ -303,7 +316,7 @@ class Kohana_Cache_Memcache extends Cache { $host['port'], $host['timeout'], $host['retry_interval'], - FALSE, + FALSE, // Server is offline array($this, '_failed_request' )); } diff --git a/includes/kohana/modules/cache/classes/kohana/cache/memcachetag.php b/includes/kohana/modules/cache/classes/kohana/cache/memcachetag.php index cdb0db73..866ab9bf 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache/memcachetag.php +++ b/includes/kohana/modules/cache/classes/kohana/cache/memcachetag.php @@ -2,8 +2,8 @@ /** * See [Kohana_Cache_Memcache] * -* @package Kohana -* @category Cache +* @package Kohana/Cache +* @category Base * @version 2.0 * @author Kohana Team * @copyright (c) 2009-2010 Kohana Team @@ -11,7 +11,7 @@ */ class Kohana_Cache_MemcacheTag extends Cache_Memcache implements Kohana_Cache_Tagging { - /** + /** * Constructs the memcache object * * @param array configuration @@ -19,12 +19,12 @@ class Kohana_Cache_MemcacheTag extends Cache_Memcache implements Kohana_Cache_Ta */ protected function __construct(array $config) { + parent::__construct($config); + if ( ! method_exists($this->_memcache, 'tag_add')) { throw new Kohana_Cache_Exception('Memcached-tags PHP plugin not present. Please see http://code.google.com/p/memcached-tags/ for more information'); } - - parent::__construct($config); } /** @@ -73,4 +73,4 @@ class Kohana_Cache_MemcacheTag extends Cache_Memcache implements Kohana_Cache_Ta { throw new Kohana_Cache_Exception('Memcached-tags does not support finding by tag'); } -} \ No newline at end of file +} diff --git a/includes/kohana/modules/cache/classes/kohana/cache/sqlite.php b/includes/kohana/modules/cache/classes/kohana/cache/sqlite.php index 32619771..70045e53 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache/sqlite.php +++ b/includes/kohana/modules/cache/classes/kohana/cache/sqlite.php @@ -4,8 +4,8 @@ * * Requires SQLite3 and PDO * - * @package Kohana - * @category Cache + * @package Kohana/Cache + * @category Base * @author Kohana Team * @copyright (c) 2009-2010 Kohana Team * @license http://kohanaphp.com/license @@ -195,16 +195,16 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_ $data = serialize($data); // Normalise tags - $tags = (NULL === $tags) ? NULL : '<'.implode('>,<', $tags).'>'; + $tags = (NULL === $tags) ? NULL : ('<'.implode('>,<', $tags).'>'); // Setup lifetime if ($lifetime === NULL) { - $lifetime = (0 === Arr::get('default_expire', NULL)) ? 0 : Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE) + time(); + $lifetime = (0 === Arr::get('default_expire', NULL)) ? 0 : (Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE) + time()); } else { - $lifetime = (0 === $lifetime) ? 0 : $lifetime + time(); + $lifetime = (0 === $lifetime) ? 0 : ($lifetime + time()); } // Prepare statement @@ -333,4 +333,4 @@ class Kohana_Cache_Sqlite extends Cache implements Kohana_Cache_Tagging, Kohana_ return (bool) $statement->fetchAll(); } -} \ No newline at end of file +} diff --git a/includes/kohana/modules/cache/classes/kohana/cache/tagging.php b/includes/kohana/modules/cache/classes/kohana/cache/tagging.php index b7fe1ab7..001a2246 100644 --- a/includes/kohana/modules/cache/classes/kohana/cache/tagging.php +++ b/includes/kohana/modules/cache/classes/kohana/cache/tagging.php @@ -2,8 +2,8 @@ /** * Kohana Cache Tagging Interface * - * @package Kohana - * @category Cache + * @package Kohana/Cache + * @category Base * @author Kohana Team * @copyright (c) 2009-2010 Kohana Team * @license http://kohanaphp.com/license @@ -39,4 +39,4 @@ interface Kohana_Cache_Tagging { * @return array */ public function find($tag); -} \ No newline at end of file +} diff --git a/includes/kohana/modules/cache/classes/kohana/cache/wincache.php b/includes/kohana/modules/cache/classes/kohana/cache/wincache.php new file mode 100644 index 00000000..51484f44 --- /dev/null +++ b/includes/kohana/modules/cache/classes/kohana/cache/wincache.php @@ -0,0 +1,140 @@ + array( // Driver group + * 'driver' => 'wincache', // using wincache driver + * ), + * ) + * + * In cases where only one cache group is required, if the group is named `default` there is + * no need to pass the group name when instantiating a cache instance. + * + * #### General cache group configuration settings + * + * Below are the settings available to all types of cache driver. + * + * Name | Required | Description + * -------------- | -------- | --------------------------------------------------------------- + * driver | __YES__ | (_string_) The driver type to use + * + * ### System requirements + * + * * Windows XP SP3 with IIS 5.1 and » FastCGI Extension + * * Windows Server 2003 with IIS 6.0 and » FastCGI Extension + * * Windows Vista SP1 with IIS 7.0 and FastCGI Module + * * Windows Server 2008 with IIS 7.0 and FastCGI Module + * * Windows 7 with IIS 7.5 and FastCGI Module + * * Windows Server 2008 R2 with IIS 7.5 and FastCGI Module + * * PHP 5.2.X, Non-thread-safe build + * * PHP 5.3 X86, Non-thread-safe VC9 build + * + * @package Kohana/Cache + * @category Base + * @author Kohana Team + * @copyright (c) 2009-2010 Kohana Team + * @license http://kohanaphp.com/license + */ +class Kohana_Cache_Wincache extends Cache { + + /** + * Check for existence of the wincache extension This method cannot be invoked externally. The driver must + * be instantiated using the `Cache::instance()` method. + * + * @param array configuration + * @throws Kohana_Cache_Exception + */ + protected function __construct(array $config) + { + if ( ! extension_loaded('wincache')) + { + throw new Kohana_Cache_Exception('PHP wincache extension is not available.'); + } + + parent::__construct($config); + } + + /** + * Retrieve a cached value entry by id. + * + * // Retrieve cache entry from wincache group + * $data = Cache::instance('wincache')->get('foo'); + * + * // Retrieve cache entry from wincache group and return 'bar' if miss + * $data = Cache::instance('wincache')->get('foo', 'bar'); + * + * @param string id of cache to entry + * @param string default value to return if cache miss + * @return mixed + * @throws Kohana_Cache_Exception + */ + public function get($id, $default = NULL) + { + $data = wincache_ucache_get($this->_sanitize_id($id), $success); + + return $success ? $data : $default; + } + + /** + * Set a value to cache with id and lifetime + * + * $data = 'bar'; + * + * // Set 'bar' to 'foo' in wincache group, using default expiry + * Cache::instance('wincache')->set('foo', $data); + * + * // Set 'bar' to 'foo' in wincache group for 30 seconds + * Cache::instance('wincache')->set('foo', $data, 30); + * + * @param string id of cache entry + * @param string data to set to cache + * @param integer lifetime in seconds + * @return boolean + */ + public function set($id, $data, $lifetime = NULL) + { + if ($lifetime === NULL) + { + $lifetime = Arr::get($this->_config, 'default_expire', Cache::DEFAULT_EXPIRE); + } + + return wincache_ucache_set($this->_sanitize_id($id), $data, $lifetime); + } + + /** + * Delete a cache entry based on id + * + * // Delete 'foo' entry from the wincache group + * Cache::instance('wincache')->delete('foo'); + * + * @param string id to remove from cache + * @return boolean + */ + public function delete($id) + { + return wincache_ucache_delete($this->_sanitize_id($id)); + } + + /** + * Delete all cache entries. + * + * Beware of using this method when + * using shared memory cache systems, as it will wipe every + * entry within the system for all clients. + * + * // Delete all cache entries in the wincache group + * Cache::instance('wincache')->delete_all(); + * + * @return boolean + */ + public function delete_all() + { + return wincache_ucache_clear(); + } +} diff --git a/includes/kohana/modules/cache/config/cache.php b/includes/kohana/modules/cache/config/cache.php index c509c704..9ec311c0 100644 --- a/includes/kohana/modules/cache/config/cache.php +++ b/includes/kohana/modules/cache/config/cache.php @@ -46,6 +46,11 @@ return array 'driver' => 'apc', 'default_expire' => 3600, ), + 'wincache' => array + ( + 'driver' => 'wincache', + 'default_expire' => 3600, + ), 'sqlite' => array ( 'driver' => 'sqlite', diff --git a/includes/kohana/modules/oauth/config/userguide.php b/includes/kohana/modules/cache/config/userguide.php similarity index 82% rename from includes/kohana/modules/oauth/config/userguide.php rename to includes/kohana/modules/cache/config/userguide.php index 828837ff..524afc41 100644 --- a/includes/kohana/modules/oauth/config/userguide.php +++ b/includes/kohana/modules/cache/config/userguide.php @@ -5,16 +5,16 @@ return array( 'modules' => array( // This should be the path to this modules userguide pages, without the 'guide/'. Ex: '/guide/modulename/' would be 'modulename' - 'oauth' => array( + 'cache' => array( // Whether this modules userguide pages should be shown 'enabled' => TRUE, // The name that should show up on the userguide index page - 'name' => 'OAuth', + 'name' => 'Cache', // A short description of this module, shown on the index page - 'description' => 'Official OAuth module, used for open protocol authorization.', + 'description' => 'Common interface for caching engines.', // Copyright message, shown in the footer for this module 'copyright' => '© 2008–2010 Kohana Team', diff --git a/includes/kohana/modules/cache/guide/cache.config.md b/includes/kohana/modules/cache/guide/cache/config.md similarity index 100% rename from includes/kohana/modules/cache/guide/cache.config.md rename to includes/kohana/modules/cache/guide/cache/config.md diff --git a/includes/kohana/modules/cache/guide/cache/examples.md b/includes/kohana/modules/cache/guide/cache/examples.md new file mode 100644 index 00000000..e69de29b diff --git a/includes/kohana/modules/cache/guide/cache.about.md b/includes/kohana/modules/cache/guide/cache/index.md similarity index 100% rename from includes/kohana/modules/cache/guide/cache.about.md rename to includes/kohana/modules/cache/guide/cache/index.md diff --git a/includes/kohana/modules/cache/guide/cache/menu.md b/includes/kohana/modules/cache/guide/cache/menu.md new file mode 100644 index 00000000..5218558f --- /dev/null +++ b/includes/kohana/modules/cache/guide/cache/menu.md @@ -0,0 +1,3 @@ +## [Cache]() +- [Configuration](config) +- [Usage](usage) \ No newline at end of file diff --git a/includes/kohana/modules/cache/guide/cache/usage.md b/includes/kohana/modules/cache/guide/cache/usage.md new file mode 100644 index 00000000..8a8239bc --- /dev/null +++ b/includes/kohana/modules/cache/guide/cache/usage.md @@ -0,0 +1,219 @@ +# Kohana Cache usage + +[Kohana_Cache] provides a simple interface allowing getting, setting and deleting of cached values. Two interfaces included in _Kohana Cache_ additionally provide _tagging_ and _garbage collection_ where they are supported by the respective drivers. + +## Getting a new cache instance + +Creating a new _Kohana Cache_ instance is simple, however it must be done using the [Cache::instance] method, rather than the traditional `new` constructor. + + // Create a new instance of cache using the default group + $cache = Cache::instance(); + +The default group will use whatever is set to [Cache::$default] and must have a corresponding [configuration](cache.config) definition for that group. + +To create a cache instance using a group other than the _default_, simply provide the group name as an argument. + + // Create a new instance of the memcache group + $memcache = Cache::instance('memcache'); + +If there is a cache instance already instantiated then you can get it directly from the class member. + + [!!] Beware that this can cause issues if you do not test for the instance before trying to access it. + + // Check for the existance of the cache driver + if (isset(Cache::$instances['memcache'])) + { + // Get the existing cache instance directly (faster) + $memcache = Cache::$instances['memcache']; + } + else + { + // Get the cache driver instance (slower) + $memcache = Cache::instance('memcache'); + } + +## Setting and getting variables to and from cache + +The cache library supports scalar and object values, utilising object serialization where required (or not supported by the caching engine). This means that the majority or objects can be cached without any modification. + + [!!] Serialisation does not work with resource handles, such as filesystem, curl or socket resources. + +### Setting a value to cache + +Setting a value to cache using the [Cache::set] method can be done in one of two ways; either using the Cache instance interface, which is good for atomic operations; or getting an instance and using that for multiple operations. + +The first example demonstrates how to quickly load and set a value to the default cache instance. + + // Create a cachable object + $object = new stdClass; + + // Set a property + $object->foo = 'bar'; + + // Cache the object using default group (quick interface) with default time (3600 seconds) + Cache::instance()->set('foo', $object); + +If multiple cache operations are required, it is best to assign an instance of Cache to a variable and use that as below. + + // Set the object using a defined group for a defined time period (30 seconds) + $memcache = Cache::instance('memcache'); + $memcache->set('foo', $object, 30); + +#### Setting a value with tags + +Certain cache drivers support setting values with tags. To set a value to cache with tags using the following interface. + + // Get a cache instance that supports tags + $memcache = Cache::instance('memcachetag'); + + // Test for tagging interface + if ($memcache instanceof Kohana_Cache_Tagging) + { + // Set a value with some tags for 30 seconds + $memcache->set('foo', $object, 30, array('snafu', 'stfu', 'fubar')); + } + // Otherwise set without tags + else + { + // Set a value for 30 seconds + $memcache->set('foo', $object, 30); + } + +It is possible to implement custom tagging solutions onto existing or new cache drivers by implementing the [Kohana_Cache_Tagging] interface. Kohana_Cache only applies the interface to drivers that support tagging natively as standard. + +### Getting a value from cache + +Getting variables back from cache is achieved using the [Cache::get] method using a single key to identify the cache entry. + + // Retrieve a value from cache (quickly) + $object = Cache::instance()->get('foo'); + +In cases where the requested key is not available or the entry has expired, a default value will be returned (__NULL__ by default). It is possible to define the default value as the key is requested. + + // If the cache key is available (with default value set to FALSE) + if ($object = Cache::instance()->get('foo', FALSE)) + { + // Do something + } + else + { + // Do something else + } + +#### Getting values from cache using tags + +It is possible to retrieve values from cache grouped by tag, using the [Cache::find] method with drivers that support tagging. + + [!!] The __Memcachetag__ driver does not support the `Cache::find($tag)` interface and will throw an exception. + + // Get an instance of cache + $cache = Cache::instance('memcachetag'); + + // Wrap in a try/catch statement to gracefully handle memcachetag + try + { + // Find values based on tag + return $cache->find('snafu'); + } + catch (Kohana_Cache_Exception $e) + { + // Handle gracefully + return FALSE; + } + +### Deleting values from cache + +Deleting variables is very similar to the getting and setting methods already described. Deleting operations are split into three categories: + + - __Delete value by key__. Deletes a cached value by the associated key. + - __Delete all values__. Deletes all caches values stored in the cache instance. + - __Delete values by tag__. Deletes all values that have the supplied tag. This is only supported by Memcached-Tag and Sqlite. + +#### Delete value by key + +To delete a specific value by its associated key: + + // If the cache entry for 'foo' is deleted + if (Cache::instance()->delete('foo')) + { + // Cache entry successfully deleted, do something + } + +By default a `TRUE` value will be returned. However a `FALSE` value will be returned in instances where the key did not exist in the cache. + +#### Delete all values + +To delete all values in a specific instance: + + // If all cache items where deleted successfully + if (Cache::instance()->delete_all()) + { + // Do something + } + +It is also possible to delete all cache items in every instance: + + // For each cache instance + foreach (Cache::$instances as $group => $instance) + { + if ($instance->delete_all()) + { + var_dump('instance : '.$group.' has been flushed!'); + } + } + +#### Delete values by tag + +Some of the caching drivers support deleting by tag. This will remove all the cached values that are associated with a specific tag. Below is an example of how to robustly handle deletion by tag. + + // Get cache instance + $cache = Cache::instance(); + + // Check for tagging interface + if ($cache instanceof Kohana_Cache_Tagging) + { + // Delete all entries by the tag 'snafu' + $cache->delete_tag('snafu'); + } + +#### Garbage Collection + +Garbage Collection (GC) is the cleaning of expired cache entries. For the most part, caching engines will take care of garbage collection internally. However a few of the file based systems do not handle this task and in these circumstances it would be prudent to garbage collect at a predetermined frequency. If no garbage collection is executed, the resource storing the cache entries will eventually fill and become unusable. + +When not automated, garbage collection is the responsibility of the developer. It is prudent to have a GC probability value that dictates how likely the garbage collection routing will be run. An example of such a system is demonstrated below. + + // Get a cache instance + $cache_file = Cache::instance('file'); + + // Set a GC probability of 10% + $gc = 10; + + // If the GC probability is a hit + if (rand(0,99) <= $gc and $cache_file instanceof Kohana_Cache_GarbageCollect) + { + // Garbage Collect + $cache_file->garbage_collect(); + } + +# Interfaces + +Kohana Cache comes with two interfaces that are implemented where the drivers support them: + + - __[Kohana_Cache_Tagging] for tagging support on cache entries__ + - [Cache_MemcacheTag] + - [Cache_Sqlite] + - __[Kohana_Cache_GarbageCollect] for garbage collection with drivers without native support__ + - [Cache_File] + - [Cache_Sqlite] + +When using interface specific caching features, ensure that code checks for the required interface before using the methods supplied. The following example checks whether the garbage collection interface is available before calling the `garbage_collect` method. + + // Create a cache instance + $cache = Cache::instance(); + + // Test for Garbage Collection + if ($cache instanceof Kohana_Cache_GarbageCollect) + { + // Collect garbage + $cache->garbage_collect(); + } \ No newline at end of file diff --git a/includes/kohana/modules/cache/guide/menu.cache.md b/includes/kohana/modules/cache/guide/menu.cache.md deleted file mode 100644 index 3f516e5c..00000000 --- a/includes/kohana/modules/cache/guide/menu.cache.md +++ /dev/null @@ -1,4 +0,0 @@ -1. **Cache** - - [About](cache.about) - - [Configuration](cache.config) - - [Usage](cache.usage) \ No newline at end of file diff --git a/includes/kohana/modules/codebench/classes/bench/datespan.php b/includes/kohana/modules/codebench/classes/bench/datespan.php index 6ea1f508..ff35479e 100644 --- a/includes/kohana/modules/codebench/classes/bench/datespan.php +++ b/includes/kohana/modules/codebench/classes/bench/datespan.php @@ -29,7 +29,7 @@ class Bench_DateSpan extends Codebench { public static function bench_span_original($remote, $local = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds') { // Array with the output formats - $output = preg_split('/[^a-z]+/', strtolower((string) $output)); + $output = preg_split('/[^a-z]+/', strtolower( (string) $output)); // Invalid output if (empty($output)) @@ -116,7 +116,7 @@ class Bench_DateSpan extends Codebench { public static function bench_span_use_array($remote, $local = NULL, $output = 'years,months,weeks,days,hours,minutes,seconds') { // Array with the output formats - $output = preg_split('/[^a-z]+/', strtolower((string) $output)); + $output = preg_split('/[^a-z]+/', strtolower( (string) $output)); // Invalid output if (empty($output)) diff --git a/includes/kohana/modules/codebench/classes/controller/codebench.php b/includes/kohana/modules/codebench/classes/controller/codebench.php index 52e84045..cdd9a705 100644 --- a/includes/kohana/modules/codebench/classes/controller/codebench.php +++ b/includes/kohana/modules/codebench/classes/controller/codebench.php @@ -17,7 +17,9 @@ class Controller_Codebench extends Kohana_Controller_Template { { // Convert submitted class name to URI segment if (isset($_POST['class'])) + { $this->request->redirect('codebench/'.trim($_POST['class'])); + } // Pass the class name on to the view $this->template->class = (string) $class; diff --git a/includes/kohana/modules/codebench/classes/kohana/codebench.php b/includes/kohana/modules/codebench/classes/kohana/codebench.php index d8a71c17..68601bd1 100644 --- a/includes/kohana/modules/codebench/classes/kohana/codebench.php +++ b/includes/kohana/modules/codebench/classes/kohana/codebench.php @@ -155,10 +155,10 @@ abstract class Kohana_Codebench { foreach ($codebench['benchmarks'] as & $method) { // Calculate percentage difference relative to fastest and slowest methods - $method['percent']['fastest']['time'] = (empty($fastest_method['time'])) ? 0 : $method['time'] / $fastest_method['time'] * 100; - $method['percent']['fastest']['memory'] = (empty($fastest_method['memory'])) ? 0 : $method['memory'] / $fastest_method['memory'] * 100; - $method['percent']['slowest']['time'] = (empty($slowest_method['time'])) ? 0 : $method['time'] / $slowest_method['time'] * 100; - $method['percent']['slowest']['memory'] = (empty($slowest_method['memory'])) ? 0 : $method['memory'] / $slowest_method['memory'] * 100; + $method['percent']['fastest']['time'] = (empty($fastest_method['time'])) ? 0 : ($method['time'] / $fastest_method['time'] * 100); + $method['percent']['fastest']['memory'] = (empty($fastest_method['memory'])) ? 0 : ($method['memory'] / $fastest_method['memory'] * 100); + $method['percent']['slowest']['time'] = (empty($slowest_method['time'])) ? 0 : ($method['time'] / $slowest_method['time'] * 100); + $method['percent']['slowest']['memory'] = (empty($slowest_method['memory'])) ? 0 : ($method['memory'] / $slowest_method['memory'] * 100); // Assign a grade for time and memory to each method $method['grade']['time'] = $this->_grade($method['percent']['fastest']['time']); @@ -168,10 +168,10 @@ abstract class Kohana_Codebench { foreach ($method['subjects'] as & $subject) { // Calculate percentage difference relative to fastest and slowest subjects for this method - $subject['percent']['fastest']['time'] = (empty($fastest_subject['time'])) ? 0 : $subject['time'] / $fastest_subject['time'] * 100; - $subject['percent']['fastest']['memory'] = (empty($fastest_subject['memory'])) ? 0 : $subject['memory'] / $fastest_subject['memory'] * 100; - $subject['percent']['slowest']['time'] = (empty($slowest_subject['time'])) ? 0 : $subject['time'] / $slowest_subject['time'] * 100; - $subject['percent']['slowest']['memory'] = (empty($slowest_subject['memory'])) ? 0 : $subject['memory'] / $slowest_subject['memory'] * 100; + $subject['percent']['fastest']['time'] = (empty($fastest_subject['time'])) ? 0 : ($subject['time'] / $fastest_subject['time'] * 100); + $subject['percent']['fastest']['memory'] = (empty($fastest_subject['memory'])) ? 0 : ($subject['memory'] / $fastest_subject['memory'] * 100); + $subject['percent']['slowest']['time'] = (empty($slowest_subject['time'])) ? 0 : ($subject['time'] / $slowest_subject['time'] * 100); + $subject['percent']['slowest']['memory'] = (empty($slowest_subject['memory'])) ? 0 : ($subject['memory'] / $slowest_subject['memory'] * 100); // Assign a grade letter for time and memory to each subject $subject['grade']['time'] = $this->_grade($subject['percent']['fastest']['time']); diff --git a/includes/kohana/modules/codebench/config/userguide.php b/includes/kohana/modules/codebench/config/userguide.php new file mode 100644 index 00000000..f9e6a14d --- /dev/null +++ b/includes/kohana/modules/codebench/config/userguide.php @@ -0,0 +1,23 @@ + array( + + // This should be the path to this modules userguide pages, without the 'guide/'. Ex: '/guide/modulename/' would be 'modulename' + 'codebench' => array( + + // Whether this modules userguide pages should be shown + 'enabled' => TRUE, + + // The name that should show up on the userguide index page + 'name' => 'Codebench', + + // A short description of this module, shown on the index page + 'description' => 'Code benchmarking tool.', + + // Copyright message, shown in the footer for this module + 'copyright' => '© 2008–2010 Kohana Team', + ) + ) +); \ No newline at end of file diff --git a/includes/kohana/modules/codebench/guide/codebench/index.md b/includes/kohana/modules/codebench/guide/codebench/index.md new file mode 100644 index 00000000..78b6f217 --- /dev/null +++ b/includes/kohana/modules/codebench/guide/codebench/index.md @@ -0,0 +1,76 @@ +# Using Codebench + +[!!] The contents of this page are taken (with some minor changes) from and are copyright Geert De Deckere. + +For a long time I have been using a quick-and-dirty `benchmark.php` file to optimize bits of PHP code, many times regex-related stuff. The file contained not much more than a [gettimeofday](http://php.net/gettimeofday) function wrapped around a `for` loop. It worked, albeit not very efficiently. Something more solid was needed. I set out to create a far more usable piece of software to aid in the everlasting quest to squeeze every millisecond out of those regular expressions. + +## Codebench Goals + +### Benchmark multiple regular expressions at once + +Being able to compare the speed of an arbitrary amount of regular expressions would be tremendously useful. In case you are wondering—yes, I had been writing down benchmark times for each regex, uncommenting them one by one. You get the idea. Those days should be gone forever now. + +### Benchmark multiple subjects at once + +What gets overlooked too often when testing and optimizing regular expressions is the fact that speed can vastly differ depending on the subjects, also known as input or target strings. Just because your regular expression matches, say, a valid email address quickly, does not necessarily mean it will quickly realize when an invalid email is provided. I plan to write a follow-up article with hands-on regex examples to demonstrate this point. Anyway, Codebench allows you to create an array of subjects which will be passed to each benchmark. + +### Make it flexible enough to work for all PCRE functions + +Initially I named the module “Regexbench”. I quickly realized, though, it would be flexible enough to benchmark all kinds of PHP code, hence the change to “Codebench”. While tools specifically built to help profiling PCRE functions, like [preg_match](http://php.net/preg_match) or [preg_replace](http://php.net/preg_replace), definitely have their use, more flexibility was needed here. You should be able to compare all kinds of constructions like combinations of PCRE functions and native PHP string functions. + +### Create clean and portable benchmark cases + +Throwing valuable benchmark data away every time I needed to optimize another regular expression had to stop. A clean file containing the complete set of all regex variations to compare, together with the set of subjects to test them against, would be more than welcome. Moreover, it would be easy to exchange benchmark cases with others. + +### Visualize the benchmarks + +Obviously providing a visual representation of the benchmark results, via simple graphs, would make interpreting them easier. Having not to think about Internet Explorer for once, made writing CSS a whole lot more easy and fun. It resulted in some fine graphs which are fully resizable. + +Below are two screenshots of Codebench in action. `Valid_Color` is a class made for benchmarking different ways to validate hexadecimal HTML color values, e.g. `#FFF`. If you are interested in the story behind the actual regular expressions, take a look at [this topic in the Kohana forums](http://forum.kohanaphp.com/comments.php?DiscussionID=2192). + +![Benchmarking several ways to validate HTML color values](codebench_screenshot1.png) +**Benchmarking seven ways to validate HTML color values** + +![Collapsable results per subject for each method](codebench_screenshot2.png) +**Collapsable results per subject for each method** + +## Working with Codebench + +Codebench is included in Kohana 3, but if you need you [can download it](http://github.com/kohana/codebench/) from GitHub. Be sure Codebench is activated in your `application/bootstrap.php`. + +Creating your own benchmarks is just a matter of creating a class that extends the Codebench class. The class should go in `classes/bench` and the class name should have the `Bench_` prefix. Put the code parts you want to compare into separate methods. Be sure to prefix those methods with `bench_`, other methods will not be benchmarked. Glance at the files in `modules/codebench/classes/bench/` for more examples. + +Here is another short example with some extra explanations. + + // classes/bench/ltrimdigits.php + class Bench_LtrimDigits extends Codebench { + + // Some optional explanatory comments about the benchmark file. + // HTML allowed. URLs will be converted to links automatically. + public $description = 'Chopping off leading digits: regex vs ltrim.'; + + // How many times to execute each method per subject. + // Total loops = loops * number of methods * number of subjects + public $loops = 100000; + + // The subjects to supply iteratively to your benchmark methods. + public $subjects = array + ( + '123digits', + 'no-digits', + ); + + public function bench_regex($subject) + { + return preg_replace('/^\d+/', '', $subject); + } + + public function bench_ltrim($subject) + { + return ltrim($subject, '0..9'); + } + } + + + +And the winner is… [ltrim](http://php.net/ltrim). Happy benchmarking! \ No newline at end of file diff --git a/includes/kohana/modules/codebench/guide/codebench/menu.md b/includes/kohana/modules/codebench/guide/codebench/menu.md new file mode 100644 index 00000000..c73a19a0 --- /dev/null +++ b/includes/kohana/modules/codebench/guide/codebench/menu.md @@ -0,0 +1 @@ +## [Codebench]() \ No newline at end of file diff --git a/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot1.png b/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot1.png new file mode 100644 index 00000000..d1cfcfb2 Binary files /dev/null and b/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot1.png differ diff --git a/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot2.png b/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot2.png new file mode 100644 index 00000000..85bf560b Binary files /dev/null and b/includes/kohana/modules/codebench/media/guide/codebench/codebench_screenshot2.png differ diff --git a/includes/kohana/modules/codebench/views/codebench.php b/includes/kohana/modules/codebench/views/codebench.php index 19619503..7b6ef2a9 100644 --- a/includes/kohana/modules/codebench/views/codebench.php +++ b/includes/kohana/modules/codebench/views/codebench.php @@ -2,7 +2,7 @@ /** * Codebench — A benchmarking module. * - * @package Kohana + * @package Kohana/Codebench * @author Kohana Team * @copyright (c) 2009 Kohana Team * @license http://kohanaphp.com/license.html @@ -14,7 +14,9 @@ - <?php if ($class !== '') echo $class, ' · ' ?>Codebench + <?php if ($class !== ''): ?> + <?php echo $class, ' · ' ?> + <?php endif; ?>Codebench - - -

-

We just wanted to say it! :)

- - - -Si luego refrescamos la página podremos ver el fruto de nuestra labor - - -![hello, world! We just wanted to say it!](img/hello_world_2.png "hello, world! We just wanted to say it!") - -## 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. diff --git a/includes/kohana/modules/userguide/guide/es-es/tutorials.md b/includes/kohana/modules/userguide/guide/es-es/tutorials.md deleted file mode 100644 index a4363aec..00000000 --- a/includes/kohana/modules/userguide/guide/es-es/tutorials.md +++ /dev/null @@ -1,7 +0,0 @@ -# Tutoriales - -[!!] inacabado - -- [Hola, Mundo](tutorials.helloworld) -- [Rutas, URLs, y Enlaces](tutorials.urls) -- [Bases de Datos](tutorials.databases) diff --git a/includes/kohana/modules/userguide/guide/es-es/tutorials.urls.md b/includes/kohana/modules/userguide/guide/es-es/tutorials.urls.md deleted file mode 100644 index 21c6912a..00000000 --- a/includes/kohana/modules/userguide/guide/es-es/tutorials.urls.md +++ /dev/null @@ -1,3 +0,0 @@ -# Rutas, URLs, y Enlaces - -[!!] inacabado diff --git a/includes/kohana/modules/userguide/guide/es-es/upgrading.md b/includes/kohana/modules/userguide/guide/es-es/upgrading.md deleted file mode 100644 index 07fefeca..00000000 --- a/includes/kohana/modules/userguide/guide/es-es/upgrading.md +++ /dev/null @@ -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) diff --git a/includes/kohana/modules/userguide/guide/features.md b/includes/kohana/modules/userguide/guide/features.md deleted file mode 100644 index 25cbb18e..00000000 --- a/includes/kohana/modules/userguide/guide/features.md +++ /dev/null @@ -1 +0,0 @@ -This page lists the features of Kohana v3 \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/about.autoloading.md b/includes/kohana/modules/userguide/guide/fr-fr/about.autoloading.md deleted file mode 100644 index 753bc9eb..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/about.autoloading.md +++ /dev/null @@ -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). \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/about.configuration.md b/includes/kohana/modules/userguide/guide/fr-fr/about.configuration.md deleted file mode 100644 index 0ac81c6f..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/about.configuration.md +++ /dev/null @@ -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: - -~~~ - '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; -~~~ diff --git a/includes/kohana/modules/userguide/guide/fr-fr/about.conventions.md b/includes/kohana/modules/userguide/guide/fr-fr/about.conventions.md deleted file mode 100644 index 2ac39c69..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/about.conventions.md +++ /dev/null @@ -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. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/about.filesystem.md b/includes/kohana/modules/userguide/guide/fr-fr/about.filesystem.md deleted file mode 100644 index 2a306300..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/about.filesystem.md +++ /dev/null @@ -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: - -![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é. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/about.flow.md b/includes/kohana/modules/userguide/guide/fr-fr/about.flow.md deleted file mode 100644 index 6f13cb7b..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/about.flow.md +++ /dev/null @@ -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 diff --git a/includes/kohana/modules/userguide/guide/fr-fr/about.install.md b/includes/kohana/modules/userguide/guide/fr-fr/about.install.md deleted file mode 100644 index 86e533c1..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/about.install.md +++ /dev/null @@ -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. - -![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") diff --git a/includes/kohana/modules/userguide/guide/fr-fr/about.kohana.md b/includes/kohana/modules/userguide/guide/fr-fr/about.kohana.md deleted file mode 100644 index 2897852b..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/about.kohana.md +++ /dev/null @@ -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. diff --git a/includes/kohana/modules/userguide/guide/fr-fr/about.mvc.md b/includes/kohana/modules/userguide/guide/fr-fr/about.mvc.md deleted file mode 100644 index 16df839f..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/about.mvc.md +++ /dev/null @@ -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. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/about.upgrading.md b/includes/kohana/modules/userguide/guide/fr-fr/about.upgrading.md deleted file mode 100644 index 4f0ec30b..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/about.upgrading.md +++ /dev/null @@ -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','((/(/)))') - ->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(/(/(/)))'); - -Et si vous voulez forcer l'utilisateur à spécifier un controleur: - - Route::set('admin', 'admin/(/(/))'); - -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', '((/(/)))', 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(); - } - } diff --git a/includes/kohana/modules/userguide/guide/fr-fr/debugging.code.md b/includes/kohana/modules/userguide/guide/fr-fr/debugging.code.md deleted file mode 100644 index 7b7b92cd..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/debugging.code.md +++ /dev/null @@ -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'); -~~~ diff --git a/includes/kohana/modules/userguide/guide/fr-fr/debugging.errors.md b/includes/kohana/modules/userguide/guide/fr-fr/debugging.errors.md deleted file mode 100644 index b4f9b508..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/debugging.errors.md +++ /dev/null @@ -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: - -
{{userguide/examples/error}}
- -## 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)); -~~~ \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/debugging.profiling.md b/includes/kohana/modules/userguide/guide/fr-fr/debugging.profiling.md deleted file mode 100644 index 4dea4b6e..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/debugging.profiling.md +++ /dev/null @@ -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: - -~~~ -
- -
-~~~ - -## Exemple - -{{profiler/stats}} \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/features.md b/includes/kohana/modules/userguide/guide/fr-fr/features.md deleted file mode 100644 index 068341da..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/features.md +++ /dev/null @@ -1 +0,0 @@ -Cette page liste les fonctionnalités clés de Kohana v3. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/menu.md b/includes/kohana/modules/userguide/guide/fr-fr/menu.md deleted file mode 100644 index 2c8bca8a..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/menu.md +++ /dev/null @@ -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) diff --git a/includes/kohana/modules/userguide/guide/fr-fr/security.cookies.md b/includes/kohana/modules/userguide/guide/fr-fr/security.cookies.md deleted file mode 100644 index cd999df1..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/security.cookies.md +++ /dev/null @@ -1,3 +0,0 @@ -# Sécurité des Cookies - -[!!] stub diff --git a/includes/kohana/modules/userguide/guide/fr-fr/security.database.md b/includes/kohana/modules/userguide/guide/fr-fr/security.database.md deleted file mode 100644 index 9046f266..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/security.database.md +++ /dev/null @@ -1,3 +0,0 @@ -# Sécurité de la Base de données - -[!!] stub diff --git a/includes/kohana/modules/userguide/guide/fr-fr/security.validation.md b/includes/kohana/modules/userguide/guide/fr-fr/security.validation.md deleted file mode 100644 index 9a5b3f97..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/security.validation.md +++ /dev/null @@ -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`: - - - -

Des erreurs ont été trouvées, veuillez vérifier les informations entrées.

-
    - -
  • - - - -
    -
    -
    - -
    -
    -
    Le mot de passe doit contenir au moins 6 caractères.
    -
    -
    - -
    -
    'Toujours', 'no' => 'Seulement si nécessaire'), $post['use_ssl']) ?>
    -
    Pour des raisons de sécurité, SSL est toujours utilisé pour les paiements.
    -
    - - - - -[!!] 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. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/security.xss.md b/includes/kohana/modules/userguide/guide/fr-fr/security.xss.md deleted file mode 100644 index 374f8fbe..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/security.xss.md +++ /dev/null @@ -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) diff --git a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.databases.md b/includes/kohana/modules/userguide/guide/fr-fr/tutorials.databases.md deleted file mode 100644 index f21aefe9..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.databases.md +++ /dev/null @@ -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. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.git.md b/includes/kohana/modules/userguide/guide/fr-fr/tutorials.git.md deleted file mode 100644 index e8cac61f..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.git.md +++ /dev/null @@ -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 à . - -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 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' -~~~ - - diff --git a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.helloworld.md b/includes/kohana/modules/userguide/guide/fr-fr/tutorials.helloworld.md deleted file mode 100644 index c4360b39..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.helloworld.md +++ /dev/null @@ -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: - - 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... - -
    {{userguide/examples/hello_world_error}}
    - -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: - - - - We've got a message for you! - - - -

    -

    We just wanted to say it! :)

    - - - -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 ;). \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.orm.md b/includes/kohana/modules/userguide/guide/fr-fr/tutorials.orm.md deleted file mode 100644 index ee7d9bbf..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.orm.md +++ /dev/null @@ -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. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.urls.md b/includes/kohana/modules/userguide/guide/fr-fr/tutorials.urls.md deleted file mode 100644 index 911a21a4..00000000 --- a/includes/kohana/modules/userguide/guide/fr-fr/tutorials.urls.md +++ /dev/null @@ -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', '((/(/)))') - ->defaults(array( - 'controller' => 'welcome', - 'action' => 'index', - )); - -Ce code crée une route appelée `default` dont l'URI doit avoir le format `((/(/)))`. 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(/(/(/)))') - ->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', '(/(/(/)))', - 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', '', - array( - 'action' => '(login|logout)' - )) - ->defaults(array( - 'controller' => 'auth' - )); - - /* - * Feeds multi-formats - * 452346/comments.rss - * 5373.json - */ - Route::set('feeds', '(/).', - array( - 'user_id' => '\d+', - 'format' => '(rss|atom|json)', - )) - ->defaults(array( - 'controller' => 'feeds', - 'action' => 'status', - )); - - /* - * Pages statiques - */ - Route::set('static', '.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', '():', - array( - 'controller' => '[A-Z][a-z]++', - 'action' => '[A-Z][a-z]++', - )) - ->defaults(array( - 'controller' => 'Slideshow', - )); - - /* - * Recherche rapide - */ - Route::set('search', ':', 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//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/(/).`. 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 `(/)` 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 diff --git a/includes/kohana/modules/userguide/guide/he-il/about.autoloading.md b/includes/kohana/modules/userguide/guide/he-il/about.autoloading.md deleted file mode 100644 index 46064bb2..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/about.autoloading.md +++ /dev/null @@ -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). \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/he-il/about.configuration.md b/includes/kohana/modules/userguide/guide/he-il/about.configuration.md deleted file mode 100644 index 6db0d4ae..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/about.configuration.md +++ /dev/null @@ -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: - -~~~ - '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; -~~~ diff --git a/includes/kohana/modules/userguide/guide/he-il/about.filesystem.md b/includes/kohana/modules/userguide/guide/he-il/about.filesystem.md deleted file mode 100644 index 6372ee09..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/about.filesystem.md +++ /dev/null @@ -1,18 +0,0 @@ -# Cascading Filesystem - מערכת קבצים מדורגת - -מערכת הקבצים של Kohana בנוייה ממבנה בסיסי יחיד אשר משוכפל לכל התקיות הנמצאות בנתיב המכונה -include path. להלן צורת המבנה: - -1. application - אפליקציה -2. modules, in order added - מודולים, לפי סדר ההופעה -3. system - מערכת - -קבצים הנמצאים בתקיות שמעל ה include path מקבלים קדימות על קבצים עם שם זהה, עובדה המאפשרת -לטעון ולדרוס פעולות קבצים על ידי טעינה של קבצים זהים לקבצים הקיימים, רק במיקום גבוה יותר יחסית. לדוגמא: - -![Cascading Filesystem Infographic](img/cascading_filesystem.png) - -אם יש מצב בו יש לנו קובץ מבט (view) בשם layout.php הממוקם בתקייה application/views וגם קיים בתקייה system/views -הקובץ הממוקם בתקייה application יהיה זה שיוחזר ברגע שננסה לגשת ל layout.php -בגלל שהוא נמצא גבוה יותר בסדר האינקלוד (include path order). -ואם נמחוק את הקובץ הנמצא בתקייה application/views, אז הקובץ שיוחזר יהיה הקובץ השני שממוקם ב system/views. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/he-il/about.flow.md b/includes/kohana/modules/userguide/guide/he-il/about.flow.md deleted file mode 100644 index a94d08bb..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/about.flow.md +++ /dev/null @@ -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 diff --git a/includes/kohana/modules/userguide/guide/he-il/about.kohana.md b/includes/kohana/modules/userguide/guide/he-il/about.kohana.md deleted file mode 100644 index 7103c9d3..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/about.kohana.md +++ /dev/null @@ -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). diff --git a/includes/kohana/modules/userguide/guide/he-il/about.mvc.md b/includes/kohana/modules/userguide/guide/he-il/about.mvc.md deleted file mode 100644 index 131e43bd..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/about.mvc.md +++ /dev/null @@ -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. -- ממשק המשתמש ממתין לפעולות נוספות של המשתמש, וכשאלה מתרחשות, התהליך חוזר על עצמו. diff --git a/includes/kohana/modules/userguide/guide/he-il/debugging.code.md b/includes/kohana/modules/userguide/guide/he-il/debugging.code.md deleted file mode 100644 index edeb38db..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/debugging.code.md +++ /dev/null @@ -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'); -~~~ diff --git a/includes/kohana/modules/userguide/guide/he-il/debugging.errors.md b/includes/kohana/modules/userguide/guide/he-il/debugging.errors.md deleted file mode 100644 index 2369aea0..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/debugging.errors.md +++ /dev/null @@ -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 - קבצים שנכללו, סיומות שנטענו ומשתנים גלובאלים - -## דוגמא להודעת שגיאה - -לחץ על אחד הקישורים הממוספרים על מנת להציג או להסתיר את המידע הנוסף - -
    {{userguide/examples/error}}
    - -## Disabling Error/Exception Handling - ביטול הטיפול בשגיאות וחריגים - -במידה וברצונך לבטל את הטיפול בשגיאות, ניתן לעשות זאת בעת הקריאה - [Kohana::init] בצורה הבאה: - -~~~ -Kohana::init(array('errors' => FALSE)); -~~~ - -חשוב לזכור שבדרך כלל נרצה שהשגיאות המפורטות יופיעו רק בעבודה לוקאלית ולא באתר אונליין \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/he-il/debugging.profiling.md b/includes/kohana/modules/userguide/guide/he-il/debugging.profiling.md deleted file mode 100644 index bd7663b1..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/debugging.profiling.md +++ /dev/null @@ -1,21 +0,0 @@ -# Profiling - פרופיל סטטיסטי לכל דף - -קוהנה מאפשרת בקלות לצפות בסטטיסטיקה אודות האפליקציה: - -1. קריאות למטודות קוהנה -2. בקשות -3. שאילתות שבוצעו על מסד הנתונים -4. ממוצע זמני פעולה של האפליקציה - -## דוגמא - -ניתן לאסוף ולהציג את הסטטיסטיקות בכל רגע נתון: -~~~ -
    - -
    -~~~ - -## התוצאה: - -{{profiler/stats}} \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/he-il/menu.md b/includes/kohana/modules/userguide/guide/he-il/menu.md deleted file mode 100644 index 5b027976..00000000 --- a/includes/kohana/modules/userguide/guide/he-il/menu.md +++ /dev/null @@ -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) diff --git a/includes/kohana/modules/userguide/guide/menu.md b/includes/kohana/modules/userguide/guide/menu.md deleted file mode 100644 index a5aacb86..00000000 --- a/includes/kohana/modules/userguide/guide/menu.md +++ /dev/null @@ -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) diff --git a/includes/kohana/modules/userguide/guide/nl/about.conventions.md b/includes/kohana/modules/userguide/guide/nl/about.conventions.md deleted file mode 100644 index 65094928..00000000 --- a/includes/kohana/modules/userguide/guide/nl/about.conventions.md +++ /dev/null @@ -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 - - 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 diff --git a/includes/kohana/modules/userguide/guide/nl/about.filesystem.md b/includes/kohana/modules/userguide/guide/nl/about.filesystem.md deleted file mode 100644 index f2a1ddee..00000000 --- a/includes/kohana/modules/userguide/guide/nl/about.filesystem.md +++ /dev/null @@ -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: - -![Cascading Filesystem Infographic](img/cascading_filesystem.png) - -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. diff --git a/includes/kohana/modules/userguide/guide/nl/about.flow.md b/includes/kohana/modules/userguide/guide/nl/about.flow.md deleted file mode 100644 index b9194e0d..00000000 --- a/includes/kohana/modules/userguide/guide/nl/about.flow.md +++ /dev/null @@ -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. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/nl/about.install.md b/includes/kohana/modules/userguide/guide/nl/about.install.md deleted file mode 100644 index 71a566d5..00000000 --- a/includes/kohana/modules/userguide/guide/nl/about.install.md +++ /dev/null @@ -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. - -![Install Page](img/install.png "Voorbeeld van de installatie pagina") - -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: - -![Welcome Page](img/welcome.png "Voorbeeld van welcome pagina") - -## 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; diff --git a/includes/kohana/modules/userguide/guide/nl/about.kohana.md b/includes/kohana/modules/userguide/guide/nl/about.kohana.md deleted file mode 100644 index 1371b381..00000000 --- a/includes/kohana/modules/userguide/guide/nl/about.kohana.md +++ /dev/null @@ -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). \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/nl/about.mvc.md b/includes/kohana/modules/userguide/guide/nl/about.mvc.md deleted file mode 100644 index 2e94ba8f..00000000 --- a/includes/kohana/modules/userguide/guide/nl/about.mvc.md +++ /dev/null @@ -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 diff --git a/includes/kohana/modules/userguide/guide/nl/about.translation.md b/includes/kohana/modules/userguide/guide/nl/about.translation.md deleted file mode 100644 index 00c3f529..00000000 --- a/includes/kohana/modules/userguide/guide/nl/about.translation.md +++ /dev/null @@ -1,4 +0,0 @@ -# Translation - -[!!] This article is a stub! - diff --git a/includes/kohana/modules/userguide/guide/nl/about.upgrading.md b/includes/kohana/modules/userguide/guide/nl/about.upgrading.md deleted file mode 100644 index d843e996..00000000 --- a/includes/kohana/modules/userguide/guide/nl/about.upgrading.md +++ /dev/null @@ -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','((/(/)))') - ->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(/(/(/)))'); - -En als je wilt een dat een gebruiker een controller specificeert: - - Route::set('admin', 'admin/(/(/))'); - -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', '((/(/)))', 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(); - } - } diff --git a/includes/kohana/modules/userguide/guide/nl/debugging.code.md b/includes/kohana/modules/userguide/guide/nl/debugging.code.md deleted file mode 100644 index 6013ec72..00000000 --- a/includes/kohana/modules/userguide/guide/nl/debugging.code.md +++ /dev/null @@ -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'); diff --git a/includes/kohana/modules/userguide/guide/nl/debugging.errors.md b/includes/kohana/modules/userguide/guide/nl/debugging.errors.md deleted file mode 100644 index aba56ac6..00000000 --- a/includes/kohana/modules/userguide/guide/nl/debugging.errors.md +++ /dev/null @@ -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: - -
    {{userguide/examples/error}}
    - -## 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)); diff --git a/includes/kohana/modules/userguide/guide/nl/debugging.profiling.md b/includes/kohana/modules/userguide/guide/nl/debugging.profiling.md deleted file mode 100644 index 9c82f7dc..00000000 --- a/includes/kohana/modules/userguide/guide/nl/debugging.profiling.md +++ /dev/null @@ -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: - -
    - -
    - -## Voorbeeld - -{{profiler/stats}} \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/nl/features.md b/includes/kohana/modules/userguide/guide/nl/features.md deleted file mode 100644 index 25cbb18e..00000000 --- a/includes/kohana/modules/userguide/guide/nl/features.md +++ /dev/null @@ -1 +0,0 @@ -This page lists the features of Kohana v3 \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/nl/menu.md b/includes/kohana/modules/userguide/guide/nl/menu.md deleted file mode 100644 index 3aa787c1..00000000 --- a/includes/kohana/modules/userguide/guide/nl/menu.md +++ /dev/null @@ -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) diff --git a/includes/kohana/modules/userguide/guide/nl/security.cookies.md b/includes/kohana/modules/userguide/guide/nl/security.cookies.md deleted file mode 100644 index 174800f6..00000000 --- a/includes/kohana/modules/userguide/guide/nl/security.cookies.md +++ /dev/null @@ -1,3 +0,0 @@ -# Cookie Veiligheid - -[!!] Nog niet beschikbaar diff --git a/includes/kohana/modules/userguide/guide/nl/security.database.md b/includes/kohana/modules/userguide/guide/nl/security.database.md deleted file mode 100644 index aa5135b3..00000000 --- a/includes/kohana/modules/userguide/guide/nl/security.database.md +++ /dev/null @@ -1,3 +0,0 @@ -# Database Veiligheid - -[!!] Nog niet beschikbaar diff --git a/includes/kohana/modules/userguide/guide/nl/security.validation.md b/includes/kohana/modules/userguide/guide/nl/security.validation.md deleted file mode 100644 index 80947b94..00000000 --- a/includes/kohana/modules/userguide/guide/nl/security.validation.md +++ /dev/null @@ -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`: - - - -

    Er zijn enkele fouten opgelopen, gelieve je ingevoerde gegevens opnieuw te bekijken.

    -
      - -
    • - - - -
      -
      -
      - -
      -
      -
      Wachtwoord moet minstens 6 karakters lang zijn.
      -
      -
      - -
      -
      'Altijd', 'no' => 'Enkel indien nodig'), $post['use_ssl']) ?>
      -
      Voor uw veiligheid wordt SSL altijd gebruik bij betalingen.
      -
      - - - - -[!!] 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. diff --git a/includes/kohana/modules/userguide/guide/nl/security.xss.md b/includes/kohana/modules/userguide/guide/nl/security.xss.md deleted file mode 100644 index 05f5ed00..00000000 --- a/includes/kohana/modules/userguide/guide/nl/security.xss.md +++ /dev/null @@ -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) diff --git a/includes/kohana/modules/userguide/guide/nl/tutorials.databases.md b/includes/kohana/modules/userguide/guide/nl/tutorials.databases.md deleted file mode 100644 index 44f40d8e..00000000 --- a/includes/kohana/modules/userguide/guide/nl/tutorials.databases.md +++ /dev/null @@ -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. diff --git a/includes/kohana/modules/userguide/guide/nl/tutorials.git.md b/includes/kohana/modules/userguide/guide/nl/tutorials.git.md deleted file mode 100644 index 0595654b..00000000 --- a/includes/kohana/modules/userguide/guide/nl/tutorials.git.md +++ /dev/null @@ -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/) - -## Initile structuur - -[!!] Deze tutorial zal ervan uitgaan dat uw webserver al is ingesteld, en dat je een nieuwe applicatie zal maken op . - -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 en kopieer de "Clone URL": - -![Github Clone URL](http://img.skitch.com/20091019-rud5mmqbf776jwua6hx9nm1n.png) - -Gebruik nu de URL om de submodule aan te maken voor `system`: - - git submodule add git://github.com/kohana/core.git system - -[!!] Dit creert 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 creren 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! diff --git a/includes/kohana/modules/userguide/guide/nl/tutorials.helloworld.md b/includes/kohana/modules/userguide/guide/nl/tutorials.helloworld.md deleted file mode 100644 index 7392571b..00000000 --- a/includes/kohana/modules/userguide/guide/nl/tutorials.helloworld.md +++ /dev/null @@ -1,106 +0,0 @@ -# Hello, World - -Aangezien bijna ieder framework een soort van "hello world" voorbeeld heeft, zou het onbeleefd van ons zijn om deze traditie te doorbreken! - -We gaan starten met het maken van een zeer basis hello world, om vervolgens uit te breiden om het MVC principe te volgen. - -## Tot op het bot - -Eerst moeten we een controller maken dat Kohana kan gebruiken om de request af te handelen. - -Maak het bestand `application/classes/controller/hello.php` in uw applicatie folder en zorg voor deze code erin: - - template->message = 'hello, world!'; - } - } - -`extends Controller_Template` -: We breiden nu uit van de template controller, dit maakt het meer logisch om views te gebruiken in onze controller. - -`public $template = 'site';` -: De template controller moet weten welke template we willen gebruiken. Het zal automatisch de view inladen die gedefinieerd is in deze variabele en het view object eraan toewijzen. - -`$this->template->message = 'hello, world!';` -: `$this->template` is een referentie naar het view object voor onze site template. Wat we hier doen is een variabele "message", met waarde "hello, world", toewijzen aan de view. - -Laten we nu proberen onze code uit te voeren... - -
      {{userguide/examples/hello_world_error}}
      - -Voor de één of andere reden geeft Kohana een error en toont het niet ons cool bericht. - -Als we kijken naar het error-bericht kunnen we zien dat de View library onze site template niet kon vinden, waarschijnlijk omdat we er nog geen aangemaakt hebben - *doh*! - -Laten we het view bestand `application/views/site.php` aanmaken voor ons bericht: - - - - We've got a message for you! - - - -

      -

      We just wanted to say it! :)

      - - - -Als we de pagina vernieuwen dan kunnen we de vruchten zien van ons *zwaar" werk: - -![hello, world! We just wanted to say it!](img/hello_world_2.png "hello, world! We just wanted to say it!") - -## Stage 3 – Profit! - -In deze tutorial heb je geleerd hoe je een controller maakt en een view gebruikt om je logica te scheiden van het visuele. - -Dit is natuurlijk een zeer elementaire inleiding over het werken met Kohana en toont zelfs niet de sterkte van het framework voor wanneer je applicaties hiermee ontwikkelt. diff --git a/includes/kohana/modules/userguide/guide/nl/tutorials.orm.md b/includes/kohana/modules/userguide/guide/nl/tutorials.orm.md deleted file mode 100644 index bc5be9f2..00000000 --- a/includes/kohana/modules/userguide/guide/nl/tutorials.orm.md +++ /dev/null @@ -1,298 +0,0 @@ -# ORM {#top} - -Kohana 3.0 bevat een krachtige ORM-module die het "active record"-patroon gebruikt en database introspectie gebruikt om kolominformatie te bepalen van een model. - -De ORM-module is opgenomen in de Kohana 3.0 installatie maar moet worden ingeschakeld vooraleer je het kunt gebruiken. In je `application/bootstrap.php` bestand moet je de oproen naar [Kohana::modules] aanpassen en de ORM-module insluiten: - - Kohana::modules(array( - ... - 'orm' => MODPATH.'orm', - ... - )); - -## Configuratie {#configuration} - -ORM vergt weinig configuratie om aan de slag te kunnen. Breid uw model classes uit met ORM om de module te kunnen gebruiken: - - class Model_User extends ORM - { - ... - } - -In het voorbeeld hierboven zal het model zoeken naar een tabel `users` in de standaard database. - -### Model Configuratie Properties - -De volgende eigenschappen worden gebruikt om ieder model te configureren: - -Type | Eigenschap | Omschrijving | Standaard waarde -----------|---------------------|--------------------------------------| ------------------------- -`string` | _table_name | Tabelnaam om te gebruiken | `singular model name` -`string` | _db | Naam van de database om te gebruiken | `default` -`string` | _primary_key | Kolom die dient als primary key | `id` -`string` | _primary_val | Kolom die dient als primary value | `name` -`bool` | _table_names_plural | Zijn de tabelnamen meervoudig? | `TRUE` -`array` | _sorting | Array met kolom => volgorde | `primary key => ASC` -`string` | _foreign_key_suffix | Achtervoegsel voor foreign keys | `_id` - -## Het gebruik van ORM - -### Een Record inladen - -Om een instantie van een model aan te maken, kan je de [ORM::factory] methode of [ORM::__construct] gebruiken: - - $user = ORM::factory('user'); - // of - $user = new Model_User(); - -De constructor en factory methodes accepteren ook een primary key waarde om het gegeven model's data in te laden: - - // Laad gebruiker met ID 5 - $user = ORM::factory('user', 5); - - // Kijk of de gebruiker succesvol werd ingeladen - if ($user->loaded()) { ... } - -Je kan optioneel een array met keys => value paren meegeven om een data object in te laden die voldoet aan de gegeven criteria: - - // Laad een gebruiker met email joe@example.com - $user = ORM::factory('user', array('email' => 'joe@example.com')); - -### Zoeken naar één of meerdere records - -ORM ondersteunt de meeste krachtige [Database] methoden voor het doorzoeken van gegevens van uw model. Zie de `_db_methods` eigenschap voor een volledige lijst van ondersteunde methode oproepen. Records worden opgehaald met behulp van de [ORM::find] en [ORM::find_all] functies. - - // Dit zal de eerste actieve gebruiker nemen met de naam Bob - $user = ORM::factory('user') - ->where('active', '=', TRUE) - ->where('name', '=', 'Bob') - ->find(); - - // Dit zal alle gebruikers nemen met de naam Bob - $users = ORM::factory('user') - ->where('name', '=', 'Bob') - ->find_all(); - -Wanneer je een lijst van modellen ontvangt met behulp van [ORM::find_all], kan je deze doorlopen zoals je doet met database resultaten: - - foreach ($users as $user) - { - ... - } - -Een zeer handige functie van ORM is de [ORM::as_array] methode die het record zal teruggeven als een array. Indien je dit gebruikt met [ORM::find_all], zal een array van alle records worden teruggegeven. Een goed voorbeeld van wanneer dit nuttig is, is voor select in het HTML formulier: - - // Toon een dropdown/select met daarin alle gebruikersnamen (id als value van de options) - echo Form::select('user', ORM::factory('user')->find_all()->as_array('id', 'username')); - -### Het aantal records tellen - -Gebruik [ORM::count_all] om het aantal records terug te geven voor een bepaalde query. - - // Aantal actieve gebruikers - $count = ORM::factory('user')->where('active', '=', TRUE)->count_all(); - -Als je het totaal aantal gebruikers wilt tellen voor een bepaalde query, terwijl je enkel een bepaalde set van deze gebruikers wilt tonen, gebruik dan de [ORM::reset] methode met `FALSE` vooraleer je `count_all` gebruikt: - - $user = ORM::factory('user'); - - // Totaal aantal gebruikers (reset FALSE zorgt ervoor dat het query object dat het query object niet geleegd wordt) - $count = $user->where('active', '=', TRUE)->reset(FALSE)->count_all(); - - // Geef enkel de eerste 10 resultaten terug van deze resultaten - $users = $user->limit(10)->find_all(); - -### Properties van een model aanspreken - -Alle model properties zijn toegankelijk via de `__get` en `__set` magic methodes. - - $user = ORM::factory('user', 5); - - // Geef de gebruikersnaam terug - echo $user->name; - - // Verander de gebruiker zijn naam - $user->name = 'Bob'; - -Voor het opslaan van gegevens/properties die niet bestaan in de tabel van het model, kan je gebruik maken van het `_ignored_columns` data member. De gegevens zullen worden opgeslagen in het interne `_object` member, maar zal worden genegeerd op database-niveau. - - class Model_User extends ORM - { - ... - protected $_ignored_columns = array('field1', 'field2', …); - ... - } - -Meerdere key => value paren kunnen worden ingesteld door gebruik te maken van de [ORM::values] methode. - - $user->values(array('username' => 'Joe', 'password' => 'bob')); - -### Aanmaken en opslaan van records - -De methode [ORM::save] wordt gebruikt om zowel nieuwe records aan te maken als het upaten van bestaande. - - // Nieuw record aanmaken - $user = ORM::factory('user'); - $user->name = 'Nieuwe gebruiker'; - $user->save(); - - // Aanpassen van een bestaand record - $user = ORM::factory('user', 5); - $user->name = 'Gebruiker 2'; - $user->save(); - - // Controleer of het record opgeslagen is - if ($user->saved()) { ... } - -Je kan meerdere records tegelijk veranderen met de [ORM::save_all] methode: - - $user = ORM::factory('user'); - $user->name = 'Bob'; - - // Verander bij alle actieve gebruikers de naam naar 'Bob' - $user->where('active', '=', TRUE)->save_all(); - -#### Gebruik `Updated` en `Created` kolommen - -De `_updated_column` en `_created_column` members staan ter beschikking om automatisch aangepast te worden wanneer een model wordt gecreëerd of aangepast. Ze worden standaard niet gebruikt. Om ze te gebruiken: - - // date_created is de kolom die wordt gebruikt om de aanmaak datum op te slaan. Gebruik format => TRUE om een timestamp op te slaan - protected $_created_column = array('date_created', 'format' => TRUE); - - // date_modified is de kolom die wordt gebruikt om de datum op te slaan wanneer het item is aangepast. In dit geval wordt een string gebruikt om een date() formaat te specificeren - protected $_updated_column = array('date_modified', 'format' => 'm/d/Y'); - -### Verwijderen van records - -Records worden verwijderd met [ORM::delete] en [ORM::delete_all]. Deze methoden werken op dezelfde manier als het opslaan van records zoals hierboven beschreven, met de uitzondering dat [ORM::delete] nog een optionele parameter heeft, het `id` van het record om te verwijderen. Anders wordt het huidig ingeladen record verwijderd. - -### Relaties - -ORM ondersteunt zeer goed relateies. Ruby heeft een [goede tutorial omtrent relaties](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html). - -#### Belongs-To en Has-Many - -We gaan er van uit dat we werken met een school dat veel (has many) studenten heeft. Iedere student kan enkel maar tot één school behoren (belong to). Dan zullen de relaties als volgt gedefinieerd worden: - - // In het model "school" - protected $_has_many = array('students' => array()); - - // In het model "student" - protected $_belongs_to = array('school' => array()); - -Om een student zijn school te verkrijgen gebruik je: - - $school = $student->school; - -Om een school zijn studenten te verkrijgen gebruik je: - - // Merk op dat find_all is vereist na "students" - $students = $school->students->find_all(); - - // Om resultaten te "filteren": - $students = $school->students->where('active', '=', TRUE)->find_all(); - -Standaard zal ORM willen zoeken naar een `school_id` model in de studenten tabel. Dit kan worden overschreven door gebruik te maken van het `foreign_key` attribuut: - - protected $_belongs_to = array('school' => array('foreign_key' => 'schoolID')); - -De foreign key moet overschreven worden in zowel het student als school model. - -#### Has-One - -Has-One is een speciale versie van Has-Many, het enige verschil is dat er maar één enkel record is. In het bovenstaande voorbeeld zou iedere school maar één student hebben (al is dat wel een slecht voorbeeld). - - // In het model "school" - protected $_has_one = array('student' => array()); - -Je moet niet zoals bij Belongs-To de `find` methode gebruiken wanneer je verwijst naar een het Has-One gerelateerd object, dit gebeurt automatisch. - -#### Has-Many "Through" - -De Has-Many "through" relatie (ook bekend als Has-And-Belongs-To-Many) wordt gebruikt in het geval dat één object gerelateerd is met meerdere objecten van verschillende types en omgekeerd. Bijvoorbeeld, een student kan verschillende klassen volgen en een klass kan verschillende studenten hebben. In dit geval wordt een derde tabel gebruikt en een model die dienst doet als `pivot`. In dit geval noemen we het pivot object/model `enrollment` (=inschrijving). - - // In het model "student" - protected $_has_many = array('classes' => array('through' => 'enrollment')); - - // In het model "class" - protected $_has_many = array('students' => array('through' => 'enrollment')); - -De inschrijvingstabel (`enrollment`) moet twee foreign keys hebben, een voor `class_id` en de andere voor `student_id`. Deze kunnen worden overschreven door `foreign_key` en `far_key` te gebruiken bij het definiëren van de relatie. Bijvoorbeeld: - - // In het model "student" (de foreign key verwijst naar dit model [student], terwijl de far key verwijst naar het andere model [class]) - protected $_has_many = array('classes' => array('through' => 'enrollment', 'foreign_key' => 'studentID', 'far_key' => 'classID')); - - // In het model "class" - protected $_has_many = array('students' => array('through' => 'enrollment', 'foreign_key' => 'classID', 'far_key' => 'studentID')); - -Het inschrijvings model (enrollment) zal als volgt gedefinieerd worden: - - // Het model "enrollment" hoort bij zowel "student" als "class" - protected $_belongs_to = array('student' => array(), 'class' => array()); - -Om de gerelateerde objecten te bereiken, gebruik je: - - // Om de klassen van een student te verkrijgen - $student->classes->find_all(); - - // Om studenten te verkrijven vanuit de klas - $class->students->find_all(); - -### Validatie - -ORM werkt nauw samen met de [Validate] library. ORM biedt de volgende members aan voor validatie - -* _rules -* _callbacks -* _filters -* _labels - -#### `_rules` - - protected $_rules = array - ( - 'username' => array('not_empty' => array()), - 'email' => array('not_empty' => array(), 'email' => array()), - ); - -`username` zal gecontroleerd worden om zeker niet leeg te zijn. `email` zal ook gecontroleerd worden om te verzekeren dat het een geldig emailadres is. De lege arrays die als values worden meegestuurd, kunnen worden gebruikt om optionele parameters mee te geven aan deze functie aanroepen. - -#### `_callbacks` - - protected $_callbacks = array - ( - 'username' => array('username_unique'), - ); - -`username` zal worden meegestuurd naar een callback methode `username_unique`. Als de methode bestaat in het huidige model, zal het worden gebruikt, anders zal een globale functie worden opgeroepen. Hier is een voorbeeld van z'n methode: - - public function username_unique(Validate $data, $field) - { - // Logica om te controleren of de gebruikersnaam uniek is - ... - } - -#### `_filters` - - protected $_filters = array - ( - TRUE => array('trim' => array()), - 'username' => array('stripslashes' => array()), - ); - -`TRUE` slaat erop dat de `trim` filter wordt gebruikt voor alle velden. `username` zal ook gefilterd worden door `stripslashes` vooraleer het gevalideerd wordt. De lege arrays die als values worden meegestuurd, kunnen worden gebruikt om optionele parameters mee te geven aan deze filter-functie aanroepen. - -#### Controleren of een Object Valid is - -Gebruik [ORM::check] om te kijken of het object momenteel valid is. - - // Een object zijn values instellen en dan controleren of het valid is - if ($user->values($_POST)->check()) - { - $user->save(); - } - -Je kan de `validate()` methode gebruiken om een model zijn validatie object aan te roepen. - - // Een optionele filter manueel toevoegen - $user->validate()->filter('username', 'trim'); \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/nl/tutorials.removeindex.md b/includes/kohana/modules/userguide/guide/nl/tutorials.removeindex.md deleted file mode 100644 index dc8864c5..00000000 --- a/includes/kohana/modules/userguide/guide/nl/tutorials.removeindex.md +++ /dev/null @@ -1,88 +0,0 @@ -# `index.php` verwijderen uit de URL - -Om uw URLs proper te houden, wil je hoogtswaarschijnlijk je applicatie kunnen benaderen zonder /index.php/` in uw URL te gebruiken. Er zijn twee stappen om `index.php` te verwijderen uit de URL. - -1. Het bootstrap bestand aanpassen -2. Herschrijven van URL's instellen - -# Configuratie van de Bootstrap - -Het eerste dat je moet veranderen is de `index_file` instelling van [Kohana::init]: - - Kohana::init(array( - 'base_url' => '/myapp/', - 'index_file' => FALSE, - )); - -Nu zullen alle links die gegeneerd worden met [URL::site], [URL::base] en [HTML::anchor] niet meer "index.php" gebruiken in de URL. Alle gegenereerde links zullen starten met `/myapp/` in plaats van `/myapp/index.php/`. - -# URL Herschrijven - -Het herschrijven van URL kan verschillen, naargelang je web server. - -## Apache - -Hernoem `example.htaccess` naar `.htaccess` en verander de volgende regel code: - - RewriteBase /kohana/ - -Dit moet gelijk zijn met de `base_url` instelling van [Kohana::init]: - - RewriteBase /myapp/ - -In de meeste gevallen is dit het enige dat je moet veranderen. - -### Er loopt iets fout! - -Als je een "Internal Server Error" of "No input file specified" error krijgt, probeer dan hetvolgende te veranderen: - - RewriteRule ^(?:application|modules|system)\b - [F,L] - -Door enkel een slash te gebruiken: - - RewriteRule ^(application|modules|system)/ - [F,L] - -Als het nog steeds niet werkt, probeer dan hetvolgende te veranderen: - - RewriteRule .* index.php/$0 [PT] - -Naar iets simpeler: - - RewriteRule .* index.php [PT] - -### Nog steeds niet loopt het fout! - -Als je nog steeds fouten krijgt, controleer dan zeker dat je host wel URL `mod_rewrite` ondersteund. Als je de Apache configuratie kunt aanpassen, voeg dan deze lijnen toe aan de configuratie, meestal in `httpd.conf`: - - - Order allow,deny - Allow from all - AllowOverride All - - -## NGINX - -Het is moeilijk om voorbeelden te geven van een nginx configuratie, maar hier is een voorbeeld voor een server: - - location / { - index index.php index.html index.htm; - try_files $uri $uri/ index.php$uri?$args; - } - - location ~ ^(.+\.php)(.*)$ { - fastcgi_split_path_info ^(.+\.php)(.*)$; - fastcgi_param SCRIPT_NAME $fastcgi_script_name; - fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - - include fastcgi.conf; - - fastcgi_pass 127.0.0.1:9000; - fastcgi_index index.php; - } - -Er zijn twee dingen te melden: het gebruik van [try_files](http://wiki.nginx.org/NginxHttpCoreModule#try_files) en [fastcgi_split_path_info](http://wiki.nginx.org/NginxHttpFcgiModule#fastcgi_split_path_info). - -[!!] Dit in de veronderstelling dat je PHP draait als een FastCGI server op poort 9000 en dat je nginx v0.7.31 of later gebruikt. - -Als je problemen hebt om dit te laten werken, zet dan het deub level logging aan in nginx en controleer de toegangs- en foutenlogs. diff --git a/includes/kohana/modules/userguide/guide/nl/tutorials.urls.md b/includes/kohana/modules/userguide/guide/nl/tutorials.urls.md deleted file mode 100644 index e13ea751..00000000 --- a/includes/kohana/modules/userguide/guide/nl/tutorials.urls.md +++ /dev/null @@ -1,159 +0,0 @@ -# Routes, URLs en Links - -Dit onderdeel zal je een basis idee geven achter Kohana's request routing, de generatie van url's en links. - -## Routing - -Zoals gezegd in de [Request Flow](about.flow) sectie, wordt een request afgehandeld door de [Request] class die een juiste [Route] vindt en de juiste controller inlaadt om het request af te handelen. Dit systeem biedt veel flexibiliteit en een logische manier van werken. - -Als je kijkt in `APPPATH/bootstrap.php` zal je zien dat de volgende code onmiddelijk wordt aangeroepen vooraleer de request wordt toegewezen aan [Request::instance]: - - Route::set('default', '((/(/)))') - ->defaults(array( - 'controller' => 'welcome', - 'action' => 'index', - )); - -Dit stelt de `default` route in voor een uri met het formaat `((/(/)))`. De karakters omringd met `<>` zijn *keys* en de karakters omringd met `()` zijn optionele onderdelen van de uri. In dit geval is de gehele uri optioneel, zodat bij een lege uri de standaard controller en actie worden uitgevoerd wat ervoor zou zorgen dat de `Controller_Welcome` class wordt ingeladen en eventueel wordt de methode `action_index` aangeroepen om de request af te handelen. - -Merk op dat in Kohana routes, alle karakters zijn toegestaan behalve `()<>` en de `/`, die hebben namelijk een speciale betekenis. In de standaard route wordt de "/" gebruikt als scheidingsteken, maar zolang de reguliere expressie logisch en doordacht is, kan je kiezen hoe je routes er laat uitzien. - -### Folders - -Om je controllers wat meer te gaan organiseren kan je ervoor kiezen om ze te plaatsen in subfolders. Een veel voorkomend geval is voor een backend van je website: - - Route::set('admin', 'admin(/(/(/)))') - ->defaults(array( - 'directory' => 'admin', - 'controller' => 'home', - 'action' => 'index', - )); - -Deze route vereist dat de uri moet beginnen met `admin` en dat de folder statisch wordt toegewezen aan `admin` in de standaard instellingen van de route. Een request naar `admin/users/create` zal nu de `Controller_Admin_Users` class laden en de methode `action_create` aanroepen. - -### Patronen - -Het Kohana route systeem gebruikt perl compatibele reguliere expressies in zijn vergelijkings proces. Standaar worden de *keys* (omringd door `<>`) vergeleken met `[a-zA-Z0-9_]++` maar je kan je eigen patronen definiren voor elke key door een associatieve array mee te geven als extra argument aan [Route::set] met daarin de keys and patronen. We kunnen het vorige voorbeeld uitbreiden met een admin sectie en een filialen (affliates) sectie. Je kan deze in verschillende routes specificeren of je kan iets doen zoals dit: - - Route::set('sections', '(/(/(/)))', - array( - 'directory' => '(admin|affiliate)' - )) - ->defaults(array( - 'controller' => 'home', - 'action' => 'index', - )); - -Dit zorgt voor twee secties van uw site, 'admin' en 'affiliate', deze laten je toe om de controllers te organiseren in subfolders voor elk maar dat ze nog steeds blijven werken als de standaard route. - -### Meer Route voorbeelden - -Er zijn oneindig veel andere mogelijkheden voor routes. Hier zijn er enkele: - - /* - * Authenticatie - */ - Route::set('auth', '', - array( - 'action' => '(login|logout)' - )) - ->defaults(array( - 'controller' => 'auth' - )); - - /* - * Multi-formaat feeds - * 452346/comments.rss - * 5373.json - */ - Route::set('feeds', '(/).', - array( - 'user_id' => '\d+', - 'format' => '(rss|atom|json)', - )) - ->defaults(array( - 'controller' => 'feeds', - 'action' => 'status', - )); - - /* - * Statische pagina's - */ - Route::set('static', '.html', - array( - 'path' => '[a-zA-Z0-9_/]+', - )) - ->defaults(array( - 'controller' => 'static', - 'action' => 'index', - )); - - /* - * Je houdt niet van slashes? - * EditGallery:bahamas - * Watch:wakeboarding - */ - Route::set('gallery', '():', - array( - 'controller' => '[A-Z][a-z]++', - 'action' => '[A-Z][a-z]++', - )) - ->defaults(array( - 'controller' => 'Slideshow', - )); - - /* - * Vlug zoeken - */ - Route::set('search', ':', array('query' => '.*')) - ->defaults(array( - 'controller' => 'search', - 'action' => 'index', - )); - -Routes worden vergeleken in de gespecifieerde volgorde dus wees er van bewust dat als je routes insteld nadat de modules zijn ingeladen, een module een route kan specifiren dat voor een conflict zorgt met een route van jezelf. Dit is ook de reden waarom de standaard route als laatste wordt ingesteld, zodat zelfgeschreven routes eerst worden getest. - -### Request Parameters - -De directory, controller en action kunnen worden benaderd via de [Request] instantie op de volgende manieren: - - $this->request->action; - Request::instance()->action; - -Alle andere gespecifieerde keys in een route kunnen worden benaderd van binnenin de controller via: - - $this->request->param('key_name'); - -De [Request::param] methode heeft een optioneel tweede argument om een standaard waarde terug te geven indien de key niet is ingesteld door de route. Indien er geen argumenten worden gegeven, worden alle keys als teruggegeven als een associatieve array. - -### Conventie - -De gebruikelijke conventie is je eigen routes te plaatsen in het `MODPATH//init.php` bestand van je module als de routes bij een module horen, of gewoonweg te plaatsen in het `APPPATH/bootstrap.php` bestand boven de standaard route als de routes specifiek voor de applicatie zijn. Natuurlijk kunnen ze ook worden geimporteerd vanuit een extern bestand of zelfs dynamisch gegenereerd worden. - -## URLs - -Naast Kohana's sterke routing mogelijkheden zitten er ook enkele methodes in om URLs te genereren voor je routes' uris. Je kan je uris altijd specificeren als een string door gebruik te maken van [URL::site] om een volledige URL te maken: - - URL::site('admin/edit/user/'.$user_id); - -Kohana biedt echter ook een methode om de URI genereren op basis van de route's definitie. Dit is zeer handig als je routing ooit zou veranderen omdat het je zou verlossen van om overal uw code te veranderen waar je de URI als string hebt gespecificeerd. Hier is een voorbeeld van dynamische generatie die overeenkomt met het `feeds`-route voorbeeld van hierboven: - - Route::get('feeds')->uri(array( - 'user_id' => $user_id, - 'action' => 'comments', - 'format' => 'rss' - )); - -Laten we zeggen dat je later zou besluiten om die route definitie meer verstaanbaar te maken door ze te veranderen in `feeds/(/).`. Wanneer je je code hebt geschreven met de uri generatie methode van hierboven dan zal je niets moeten veranderen aan je code! Wanneer een deel van de URI tussen haakjes staat en waarvoor er geen waarde is meegegeven voor uri generatie en er geen standaard waarde is meegegeven in de route, dan zal dat stuk verwijderd worden van de uri. Een voorbeeld hiervan is het `(/)` deel van de standaard route, dit zal niet worden opgenomen in de gegenereerde uri als er geen id is voorzien. - -De methode [Request::uri] zal er n zijn dat je regelmatig zult gebruiken, het heeft dezelfde functionaliteit als hierboven maar het gaat gebruikt de huidige route, directory, controller en action. Als onze huidige route de standaard route is en de uri `users/list` is, dan kunnen we het volgende doen om uris te genereren in het formaat `users/view/$id`: - - $this->request->uri(array('action' => 'view', 'id' => $user_id)); - -Of een meer aangeraden methode voor in een view: - - Request::instance()->uri(array('action' => 'view', 'id' => $user_id)); - -## Links - -[!!] Nog geen informatie beschikbaar. diff --git a/includes/kohana/modules/userguide/guide/nl/using.autoloading.md b/includes/kohana/modules/userguide/guide/nl/using.autoloading.md deleted file mode 100644 index e92d5831..00000000 --- a/includes/kohana/modules/userguide/guide/nl/using.autoloading.md +++ /dev/null @@ -1,95 +0,0 @@ -# Laden van Classes - -Kohana maakt dankbaar gebruik van PHP [autoloading](http://php.net/manual/language.oop5.autoload.php). Dit zorgt ervoor dat je niet [include](http://php.net/include) of [require](http://php.net/require) moet gebruiken vooraleer je de klasse kunt gebruiken. Bijvoorbeeld als je de [Cookie::set] method wilt gebruiken doe je: - - Cookie::set('mycookie', 'any string value'); - -Of om een [Encrypt] instantie in te laten, gewoon [Encrypt::instance] aanroepen: - - $encrypt = Encrypt::instance(); - -Classes worden ingeladen via de [Kohana::auto_load] methode, deze maakt een simpele conversie van de class naam naar de naam van het bestand: - -1. Classes worden geplaatst in de `classes/` folder van het [bestandssysteem](about.filesystem) -2. Ieder underscore karakter wordt omgezet naar een slash. -2. De bestandsnaam is met kleine letters - -Wanneer je een class aanroept die nog niet is ingeladen (vb. `Session_Cookie`), zal Kohana zoeken in het bestandssysteem via [Kohana::find_file] voor een bestand met de naam `classes/session/cookie.php`. - -## Zelfgeschreven Autoloaders - -De standaard autoloader wordt ingesteld in `application/bootstrap.php` via [spl_autoload_register](http://php.net/spl_autoload_register): - - spl_autoload_register(array('Kohana', 'auto_load')); - -Dit laat [Kohana::auto_load] toe om te proberen eender welke class in te laden dat nog niet bestaat wanneer de class voor het eerst wordt gebruikt. - -# Transparante Class Uitbreiding {#class-extension} - -Het [cascading bestandssyteem](about.filesystem) laat transparante class uitbreiding toe. Bijvoorbeeld, de class [Cookie] is gedefinieerd in `SYSPATH/classes/cookie.php` als: - - class Cookie extends Kohana_Cookie {} - -De standaard Kohana classes, en vele uitbreidingen, gebruiken deze manier van definiren zodat bijna alle classes kunnen worden uitgebreid. Je kan elke class transparant uitbreiden, door een eigen class te definiren in `APPPATH/classes/cookie.php` om je eigen methodes toe te voegen. - -[!!] Je past best **nooit** bestanden aan die standaard in Kohana zitten. Maak aanpassingen aan classes altijd door ze uit te breiden om upgrade-problemen te vermijden. - -Bijvoorbeeld, als je een methode wilt maken dat gecodeerde cookies maakt via de [Encrypt] class: - - encode((string) $value); - - parent::set($name, $value, $expiration); - } - - /** - * Krijg de inhoud van een gecodeerde cookie. - * - * @uses Cookie::get - * @uses Encrypt::decode - */ - public static function decrypt($name, $default = NULL) - { - if ($value = parent::get($name, NULL)) - { - $value = Encrypt::instance(Cookie::$encryption)->decode($value); - } - - return isset($value) ? $value : $default; - } - - } // End Cookie - -Als je nu `Cookie::encrypt('secret', $data)` aanroept zal die een een gecodeerde cookie aanmaken die je kan decoderen met `$data = Cookie::decrypt('secret')`. - -## Meerdere niveau's van uitbreidingen {#multiple-extensions} - -Als je een Kohana class in een module uitbreidt, maak je best gebruik van transparante uitbreidingen. In plaats van de [Cookie] uitbreiding Kohana te laten uitbreiden, kan je `MODPATH/mymod/encrypted/cookie.php` aanmaken: - - class Encrypted_Cookie extends Kohana_Cookie { - - // Gebruik de encrypt() en decrypt() methodes van hierboven - - } - -En maak `MODPATH/mymod/cookie.php` aan: - - class Cookie extends Encrypted_Cookie {} - -Dit laat nog steeds toe om gebruikers hun eigen uitbreidingen te laten doen op [Cookie] zodat jouw uitbreidingen nog behouden blijven. Let wel, de volgende uitbreiding van [Cookie] zal `Encrypted_Cookie` moeten uitbreiden in plaats van `Kohana_Cookie`. diff --git a/includes/kohana/modules/userguide/guide/nl/using.configuration.md b/includes/kohana/modules/userguide/guide/nl/using.configuration.md deleted file mode 100644 index c9aa35db..00000000 --- a/includes/kohana/modules/userguide/guide/nl/using.configuration.md +++ /dev/null @@ -1,57 +0,0 @@ -# Algemene Configuratie - -Kohana gebruikt zowel static properties als bestanden worden gebruikt voor de configuratie. Static properties zijn worden meestal gebruikt voor static classes, zoals [Cookie], [Security] en [Upload]. Bestanden worden meestal gebruikt voor objecten zoals [Database], [Encrypt] en [Session]. - -Static properties kunnen ingesteld worden in `APPPATH/bootstrap.php` of door [class uitbreding](using.autoloading#class-extension). Het voordeel van static properties is dat er geen extra bestanden moeten worden ingeladen. Het probleem met deze methode is dat de class ingeladen word wanneer een property is ingesteld, als je geen uitbreiding gebruikt. Echter, met gebruik van uitbreidingen worden uitbreidingen uit modules overladen. Het is aanbevolen om static property te gebruiken voor configuraties in de bootstrap. - -[!!] Wanneer je opcode caching gebruikt, zoals [APC](http://php.net/apc) of [eAccelerator](http://eaccelerator.net/), dan is het inladen van classes merkbaar vermindert. Het is dan ook streng aanbevolen om opcode caching te bruiken bij *elke* website in productie, of die nu groot of klein is. - -## Noodzakelijke instellingen - -Bij iedere nieuwe Kohana installatie is het vereist om de [Kohana::init] instellingen aan te passen in `APPPATH/bootstrap.php`. Iedere instelling die niet specifiek is ingesteld zal de standaard instelling gebruiken. Deze instellingen kunnen aangeroepen worden en/of aangepast worden op een later tijdstip door de static property van de [Kohana] class te gebruiken. Bijvoorbeeld, om de huidige karakterset te verkrijgen lees je de [Kohana::$charset] property in. - -## Veiligheids instellingen - -Er zijn verschillende instellingen dat je moet veranden om Kohana veilig te maken. De belangrijkste is [Cookie::$salt], deze wordt gebruikt om een "handtekening" te maken op cookies zodat ze niet kunnen worden aangepast van buiten Kohana. - -Als je de [Encrypt] class wilt gebruiken, maak je best ook een `encrypt` configuratie bestand en stel je een encryption `key` in. Deze key bevat best letters, nummers en symbolen om de veiligheid te optimaliseren. - -[!!] **Gebruik geen hash als encryption key!** Indien je dit doet zal de encryption key gemakkelijker te kraken zijn. - -# Configuratie bestanden {#config-files} - -Configuratie bestanden zijn licht anders dan andere bestanden in het [cascading bestandssyteem](about.filesystem). Configuratie bestanden worden **gemerged** in plaats van overladen. Dit wil zeggen dat alle configuratie bestanden hetzelfde path worden gecombineerd om configuratie te vormen. Wat wil zeggen dat je *individuele* instellingen kan overladen in plaats van een volledig bestand te dupliceren. - -Configuratie bestanden zijn pure PHP bestanden, opgeslaan in de `config/` folder, die een associatieve array teruggeven: - - 'value', - 'options' => array( - 'foo' => 'bar', - ), - ); - -Als het bovenstaande bestand `myconf.php` werd genoemd, dan kon je deze benaderen via: - - $config = Kohana::config('myconf'); - $options = $config['options']; - -[Kohana::config] biedt ook een shortcut om individuele keys van configuratie arrays te benaderen door gebruik te maken van "dot paths". - -Verkrijg de "options" array: - - $options = Kohana::config('myconf.options'); - -Verkrijg de "foo" key van de "options" array: - - $foo = Kohana::config('myconf.options.foo'); - -Configuratie arrays kunnen ook worden benaderd als objecten, indien je deze manier wilt gebruiken: - - $options = Kohana::config('myconf')->options; - -Let wel, je kan enkel keys op het bovenste niveau aanspreken als object properties, alle lagere keys moeten benaderd worden via de standaard array syntax: - - $foo = Kohana::config('myconf')->options['foo']; diff --git a/includes/kohana/modules/userguide/guide/nl/using.messages.md b/includes/kohana/modules/userguide/guide/nl/using.messages.md deleted file mode 100644 index 2ba9a715..00000000 --- a/includes/kohana/modules/userguide/guide/nl/using.messages.md +++ /dev/null @@ -1,26 +0,0 @@ -# Berichten (Messages): de basis - -Kohana berichten zijn mensvriendelijke stukjes tekst voorgesteld door een korter woord of zin, een "key" genaamd. Berichten worden benaderd via de [Kohana::message] methode, die n enkel of een hele groep van berichten teruggeeft. - -Bijvoorbeeld, als een gebruiker niet is ingelogd en een pagina dat authenticatie vereist probeert te benaderen, dan moet een error zoals "U moet ingelogd zijn om toegang te hebben tot deze pagina" getoond worden. Dit bericht kan opgeslagen worden in het `auth` bestand met een `must_login` key: - - $message = Kohana::message('auth', 'must_login'); - -Berichten worden niet vertaald. Om een bericht te vertalen, gebruik dan de [translation function](using.translation): - - $translated = __(Kohana::message('auth', 'must_login')); - -[!!] In Kohana v2 werd het berichten-systeem gebruikt voor vertalingen. Echter is het ten zeerste aanbevolen om het nieuwe vertalingssysteem te gebruiken in plaats van berichten, aangezien het leesbare tekst teruggeeft wanneer zelfs geen vertaling beschikbaar is. - -## Berichten: de bestanden - -Alle berichten bestanden zijn pure PHP files, opgeslaan in de `messages/` folder, die een associatieve array teruggeven: - - 'U moet ingelogd zijn om toegang te hebben tot deze pagina', - 'no_access' => 'U heeft geen bevoegdheden om deze pagina te bekijken', - ); - -Berichten bestanden zijn gelijkaardig aan [configuratie bestanden](using.configuration#config-files) omdat ze ook worden samengevoegd. Dit betekent dat alle berichten die opgeslaan zijn in het bestand `auth` zullen worden gecombineerd in n enkele array, het is dus niet noodzakelijk om alle berichten te kopiren wanneer je een nieuw `auth` bestand aanmaakt. diff --git a/includes/kohana/modules/userguide/guide/nl/using.sessions.md b/includes/kohana/modules/userguide/guide/nl/using.sessions.md deleted file mode 100644 index cdc4b178..00000000 --- a/includes/kohana/modules/userguide/guide/nl/using.sessions.md +++ /dev/null @@ -1,223 +0,0 @@ -# Gebruik van Sessies en Cookies - -Kohana biedt een paar classes die het gemakkelijk maken om te werken met cookies en sessies. Op een hoog niveau, zowel sessies en cookies geven dezelfde functionaliteit. Ze laten de ontwikkelaar toe om tijdelijke of blijvende informatie over een specifieke klant voor later op te slaan. - -Cookies moeten worden gebruikt voor de opslag van niet-private gegevens die persistent is voor een lange periode van tijd. Bijvoorbeeld het opslaan van een gebruikers-id of een taalvoorkeur. Gebruik de [Cookie] class voor het verkrijgen en instellen van cookies. - -[!!] Kohana gebruikt "ondertekende" cookies. Elke cookie die wordt opgeslagen wordt gecombineerd met een veilige hash om een wijziging van de cookie te voorkomen. Deze hash wordt gegenereerd met behulp van [Cookie:: salt], die de [Cookie::$salt] property gebruikt. Je moet [deze instelling] (using.configuration) veranderen wanneer je applicatie live staat. - -Sessies worden gebruikt voor het opslaan van tijdelijke of prive-gegevens. Zeer gevoelige gegevens moeten worden opgeslagen met behulp van de [Session] class met de "database" of "native" adapters. Bij gebruik van de "cookie"-adapter, moet de sessie altijd worden versleuteld. - -[!!] Voor meer informatie over de beste manieren van werken met sessie-variabelen, zie [the seven deadly sins of sessions](http://lists.nyphp.org/pipermail/talk/2006-December/020358.html). - -# Het opslaan, ophalen en verwijderen van gegevens - -[Cookie] en [Session] bieden een zeer gelijkaardige API voor het opslaan van gegevens. Het belangrijkste verschil tussen hen is dat sessies benaderd kunnen worden met behulp van een object, en cookies met behulp van een statische class. - -De sessie instantie benaderen wordt gedaan met de [Session::instance] methode: - - // Verkrijg de sessie instantie - $session = Session::instance(); - -Bij het gebruik van sessies, kan je alle huidige sessiegegevens krijgen met behulp van de [Session::as_array] methode: - - // Verkrijg alle sessiegegevens als een array - $data = $session->as_array(); - -Je kan dit ook gebruiken om de `$_SESSION` global te overladen om data te krijgen en in te stellen in verlijkbare manier zoals standaard PHP: - - // Overlaad $_SESSION met sessiegegevens - $_SESSION =& $session->as_array(); - - // Stel de sessiegegevens in - $_SESSION[$key] = $value; - -## Gegevens opslaan {#setting} - -Het opslaan van sessie- of cookie-gegevens wordt gedaan met behulp van de `set`-methode: - - // Sla sessiegegevens op - $session->set($key, $value); - - // Sla cookiegegevens op - Cookie::set($key, $value); - - // Sla een gebruikers id op - $session->set('user_id', 10); - Cookie::set('user_id', 10); - -## Verkrijgen van gegevens {#getting} - -Verkrijgen van sessie- of cookie-gegevens wordt gedaan met behulp van de `get`-methode: - - // Verkrijg sessiegegevens - $data = $session->get($key, $default_value); - - // Verkrijg cookiegegevens - $data = Cookie::get($key, $default_value); - - // Verkrijg het gebruikers id - $user = $session->get('user_id'); - $user = Cookie::get('user_id'); - -## Verwijderen van gegevens {#deleting} - -Het verwijderen van sessie- of cookie-gegevens wordt gedaan met behulp van de `delete`-methode: - - // Verwijderen van sessiegegevens - $session->delete($key); - - // Verwijderen van cookiegegevens - Cookie::delete($key); - - // Verwijder een gebruikers id - $session->delete('user_id'); - Cookie::delete('user_id'); - -# Configuratie {#configuration} - -Zowel cookies als sessies hebben verschillende configuratie-instellingen die van invloed zijn hoe gegevens worden opgeslagen. Controleer altijd deze instellingen voordat u uw applicatie live zet, omdat veel van die instellingen een rechtstreeks effect zal hebben op de veiligheid van uw applicatie. - -## Cookie Instellingen {#cookie-settings} - -Al de cookie instellingen worden verandert met behulp van statische properties. Je kan deze instellingen veranderen in `bootstrap.php` of door een [class extension](using.autoloading#class-extension) te gebruiken. - -De meest belangrijke instelling is [Cookie::$salt], die wordt gebruikt om veilig te ondertekenen. Deze waarde zou moeten gewijzigd en geheim gehouden worden: - - Cookie::$salt = 'Uw geheim is veilig bij mij'; - -[!!] Door het veranderen van deze waarde zullen alle bestaande cookies niet meer geldig zijn. - -Standaard worden cookies bewaard tot het browservenster wordt gesloten. Om een specifieke leeftijd te gebruiken, verander de [Cookie::$expiration] instelling: - - // Stel in dat cookies vervallen na n week - Cookie::$expiration = 604800; - - // Alternatief voor het gebruik van getallen, voor meer duidelijkheid - Cookie::$expiration = Date::WEEK; - -Het path waarvan de cookie kan worden opgevraagd kan worden beperkt met behulp van de [Cookie::$path] instelling. - - // Enkel cookies toelaten wanneer je gaat naar /public/* - Cookie::$path = '/public/'; - -Het domein waarvan de cookie kan worden geopend kan ook worden beperkt, met behulp van de [Cookie::$domain] instelling. - - // Enkel cookies toelaten voor www.example.com - Cookie::$domain = 'www.example.com'; - -Als u de cookie toegankelijk wilt maken op alle subdomeinen, gebruik dan een punt aan het begin van het domein. - - // Cookies toegankelijk maken voor example.com en *.example.com - Cookie::$domain = '.example.com'; - -Als je de cookie alleen wilt kunnen benaderen via een beveiligde (HTTPS) verbinding, gebruik dan de [Cookie::$secure] instelling. - - // Cookies enkel toegangekijk maken via een beveiligde verbinding - Cookie::$secure = TRUE; - - // Cookies toegankelijk maken voor elke verbinding - Cookie::$secure = FALSE; - -Om te voorkomen dat cookies worden geopend met behulp van Javascript, kunt u de [Cookie::$httponly] instelling aanpassen. - - // Maak cookies niet toegankelijk via Javascript - Cookie::$httponly = TRUE; - -## Sessie Adapters {#adapters} - -Bij het maken van of het aanroepen van een instantie van de [Sessie] class kan je kiezen welke sessie adapter je wilt gebruiken. De sessie adapters die beschikbaar zijn voor je: - -Native -: Slaat sessiegegevens op in de standaard locatie voor uw web server. De opslaglocatie is gedefinieerd door [session.save_path](http://php.net/manual/session.configuration.php#ini.session.save-path) in `php.ini` of gedefinieerd door [ini_set](http://php.net/ini_set). - -Database -: Slaat de sessiesgegevens op in een database tabel door gebruik te maken van de [Session_Database] class. De [Database] module is vereist. - -Cookie -: Slaat de sessiegegevens op in een cookie door gebruikt te maken van de [Cookie] class. **Sessies hebben een 4KB limiet wanneer je deze adapter gebruikt.** - -De standaard adapter kan ingesteld worden door de waarde aan te passen van [Session::$default]. De standaard adapter is "native". - -[!!] Zoals bij cookies bekent een "lifetime" instelling van "0" dat de sessie zal vervallen bij het sluiten van de het browservenster. - -### Sessie Adapter Instellingen - -Je kan configuratie-instellingen voor elk van de sessie adapters instellen door het creren van een sessie configuratiebestand in `APPPATH/config/session.php`. Het volgende voorbeeld van een configuratie bestand definiert alle instellingen voor elke adapter: - - return array( - 'native' => array( - 'name' => 'session_name', - 'lifetime' => 43200, - ), - 'cookie' => array( - 'name' => 'cookie_name', - 'encrypted' => TRUE, - 'lifetime' => 43200, - ), - 'database' => array( - 'name' => 'cookie_name', - 'encrypted' => TRUE, - 'lifetime' => 43200, - 'group' => 'default', - 'table' => 'table_name', - 'columns' => array( - 'session_id' => 'session_id', - 'last_active' => 'last_active', - 'contents' => 'contents' - ), - 'gc' => 500, - ), - ); - -#### Native Adapter {#adapter-native} - -Type | Instelling | Omschrijving | Standaard -----------|------------|-----------------------------------------------------|----------- -`string` | name | naam van de sessie | `"session"` -`integer` | lifetime | aantal seconden dat de sessie moet bestaan | `0` - -#### Cookie Adapter {#adapter-cookie} - -Type | Instelling | Omschrijving | Standaard -----------|------------|-----------------------------------------------------|----------- -`string` | name | naam van de cookie om de sessiegegevens op te slaan | `"session"` -`boolean` | encrypted | de sessiegegevens coderen met [Encrypt]? | `FALSE` -`integer` | lifetime | aantal seconden dat de sessie moet bestaan | `0` - -#### Database Adapter {#adapter-database} - -Type | Instelling | Omschrijving | Standaard -----------|------------|-----------------------------------------------------|----------- -`string` | group | [Database::instance] groep naam | `"default"` -`string` | table | de tabelnaam waar de gegevens worden in opgeslagen | `"sessions"` -`array` | columns | associatieve array met kolom aliassen | `array` -`integer` | gc | 1:x kans dat de garbage collection uitgevoerd wordt | `500` -`string` | name | naam van de cookie om de sessiegegevens op te slaan | `"session"` -`boolean` | encrypted | de sessiegegevens coderen met [Encrypt]? | `FALSE` -`integer` | lifetime | aantal seconden dat de sessie moet bestaan | `0` - -##### Tabel Schema - -Je moet de sessie-opslag tabel in de database aanmaken. Dit is het standaard schema: - - CREATE TABLE `sessions` ( - `session_id` VARCHAR(24) NOT NULL, - `last_active` INT UNSIGNED NOT NULL, - `contents` TEXT NOT NULL, - PRIMARY KEY (`session_id`), - INDEX (`last_active`) - ) ENGINE = MYISAM; - -##### Tabel kolommen - -Je kunt de namen van kolommen aanpassen om overeen te komen met een bestaand database-schema. De standaard waarde is hetzelfde als de key waarde. - -session_id -: de naam van de "id" kolom - -last_active -: UNIX timestamp van het laatste tijdstip dat de sessie werd aangepast - -contents -: sessiongegevens opgeslaan in een serialized string, en optioneel gecodeerd diff --git a/includes/kohana/modules/userguide/guide/nl/using.views.md b/includes/kohana/modules/userguide/guide/nl/using.views.md deleted file mode 100644 index beef852b..00000000 --- a/includes/kohana/modules/userguide/guide/nl/using.views.md +++ /dev/null @@ -1,118 +0,0 @@ -# Het gebruik van Views - -Views zijn bestanden die de visuele informatie bevatten voor je applicatie. Dit is meestal HTML, CSS en Javascript maar kan van alles zijn die je nodig hebt zoals XML of JSON voor AJAX output. Het doel van views is om deze informatie af te scheiden van de applicatie logica zodat je nettere code hebt en deze gemakkelijker kunt hergebruiken. - -Hoewel dit waar is, kunnen views zelf ook code bevatten die je gebruikt om gegevens te tonen die je meegestuurd hebt met de view. Bijvoorbeeld, het loopen door een array met producten en voor elk product een nieuwe tabelrij tonen. Views zijn nog altijd PHP bestanden dus kan je erin coderen zoals je normaal zou doen. - -# Aanmaken van View bestanden - -De View bestanden worden opgeslagen in de `views` folder van het [bestandssysteem](about.filesystem). Je kan ook subfolders aanmaken in de `views` folder om je bestanden meer te organiseren. Alle mogelijkheden uit de volgende voorbeelden zijn goed: - - APPPATH/views/home.php - APPPATH/views/pages/about.php - APPPATH/views/products/details.php - MODPATH/error/views/errors/404.php - MODPATH/common/views/template.php - -## Inladen van Views - -[View] objecten worden gewoonlijk aangemaakt binnenin een [Controller] via de [View::factory] methode. De view wordt dan gewoonlijk aan de [Request::$response] property toegewezen of aan een andere view. - - public function action_about() - { - $this->request->response = View::factory('pages/about'); - } - -Wanneer een view wordt toegewezen aan de [Request::$response], zoals in bovenstaand voorbeeld, dan zal het automatisch worden gerenderd wanneer noodzakelijk. Om het gerenderde resultaat van een view te verkrijgen kan je de [View::render] methode aanspreken of gewoon laten casten naar een string. Wanneer een view gerenderd is, wordt de view ingeladen en wordt de HTML gegenereerd. - - public function action_index() - { - $view = View::factory('pages/about'); - - // View wordt gerenderd - $about_page = $view->render(); - - // Of gewoon laten casten naar een string - $about_page = (string) $view; - - $this->request->response = $about_page; - } - -## Variabelen in Views - -Eenmaal een view is ingeladen, kunnen variabelen eraan toegewezen worden door de [View::set] en [View::bind] methodes. - - public function action_roadtrip() - { - $view = View::factory('user/roadtrip') - ->set('places', array('Rome', 'Paris', 'London', 'New York', 'Tokyo')); - ->bind('user', $this->user); - - // De view zal de variabelen $places en $user hebben - $this->request->response = $view; - } - -[!!] Het enige verschil tussen `set()` en `bind()` is dat `bind()` de variabele toewijst via referentie. Als je een variabele `bind()` vooraleer ze gedefineerd is, zal de variable als `NULL` worden gecreerd. - -### Globale Variabelen - -Een applicatie kan verschillende views hebben die toegang hebben tot dezelfde variabelen. Bijvoorbeeld, een titel van een pagina wil je zowel tonen in de header van je template als in de body van de pagina inhoud. Je kan variabelen creren dat toegankelijk zijn in elke view dankzij de [View::set_global] en [View::bind_global] methoden. - - // Wijs $page_title toe aan alle views - View::bind_global('page_title', $page_title); - -Als de applicatie drie views heeft die gerenderd zijn voor de home-pagina: `template`, `template/sidebar` en `pages/home`. Eerst zal je een abstracte controller maken om de template te maken: - - abstract class Controller_Website extends Controller_Template { - - public $page_title; - - public function before() - { - parent::before(); - - // Maak $page_title toegankelijk in alle views - View::bind_global('page_title', $this->page_title); - - // Laad $sidebar in de template als een view - $this->template->sidebar = View::factory('template/sidebar'); - } - - } - -Dan moet de home controller de `Controller_Website` uitbreiden: - - class Controller_Home extends Controller_Website { - - public function action_index() - { - $this->page_title = 'Home'; - - $this->template->content = View::factory('pages/home'); - } - - } - -## Views in Views - -Als je een andere view wilt gebruiken in een view heb je twee keuzes. Door [View::factory] aan te roepen kan je de opgenomen view sandboxen. Dit betekent dat je alle variabelen moet meegeven aan de view door middel van [View::set] of [View::bind]: - - // Enkel de $user variabele zal toegankelijk zijn in "views/user/login.php" - bind('user', $user) ?> - -De andere optie is om de view rechtstreeks in te voegen, dat maakt alle huidige variabelen beschikbaar in de ingesloten view: - - // Elke variabele gedefinieerd in deze view zal worden ingesloten in "views/message.php" - - -Natuurlijk kan je ook een volledige [Request] inladen in een view: - - execute() ?> - -Dit is een voorbeeld van [HMVC](about.mvc), dit maakt het mogelijk om aanroepingen te maken en te lezen via andere URLs binnenin je applicatie. - -# Upgraden van v2.x - -In tegenstelling tot versie 2.x van Kohana, wordt de view niet ingeladen in de context van de [Controller], dus is het niet mogelijk om `$this` aan te spreken als controller binnenin de view. De controller doorgeven aan de view moet nu expliciet worden gedaan: - - $view->bind('controller', $this); diff --git a/includes/kohana/modules/userguide/guide/ru-ru/about.conventions.md b/includes/kohana/modules/userguide/guide/ru-ru/about.conventions.md deleted file mode 100644 index 24a6904e..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/about.conventions.md +++ /dev/null @@ -1,301 +0,0 @@ -# Соглашения - -При работе с фреймворком приветствуется использование Kohana [coding style](http://dev.kohanaphp.com/wiki/kohana2/CodingStyle). В нем используется [BSD/Allman стиль](http://ru.wikipedia.org/wiki/%D0%9E%D1%82%D1%81%D1%82%D1%83%D0%BF_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29#.D0.A1.D1.82.D0.B8.D0.BB.D1.8C_.D0.9E.D0.BB.D0.BC.D0.B0.D0.BD.D0.B0) расстановки фигурных скобок и прочего форматирования кода. - -## Имена классов и расположение файлов {#classes} - -Для облегчения работы [автозагрузки](about.autoloading) в Kohana, имена классов строго регламентированы. Имя класса должно начинаться с заглавной буквы, а для разделения слов в имени используется нижнее_подчёркивание. Нижнее подчёркивание отражает расположение файла в файловой структуре проекта. - -Данные соглашения предусматривают: - -1. Не рекомендуется использовать CamelCase в имени класса, за исключением случаев, когда нежелательно создавать дополнительные поддиректории. -2. Все файлы классов и директории должны быть в нижнем регистре. -3. Все классы должны располагаться в директории `classes`, которая может быть на любом уровне [каскадной файловой системы](about.filesystem) фреймворка. - -[!!] В отличие от Kohana версии 2.x, в Kohana 3 нет разделения между "типами" классов: будь то "контроллер", "модель", "библиотека" или "хелпер". Все классы располагаются в директории "classes/" вне зависимости от того, являются ли они статическими "хелперами" или объектами "библиотеки". Вы вправе реализовывать любой дизайн класса, который Вам необходим: статический, синглтон, адаптер и т.п. - -## Примеры - -Помните, нижнее подчёркивание в наименовании класса отвечает за разделение на директории и отражает расположение файла в файловой структуре проекта. - -Название класса | Файл -----------------------|------------------------------- -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} - -Для того, чтобы Ваш код был удобочитаемым и выглядел последовательным, мы просим всех на максимально придерживаться стандартов кодирования. - -### Фигурные скобки - -Используйте, пожалуйста, [BSD/Allman стиль](http://ru.wikipedia.org/wiki/%D0%9E%D1%82%D1%81%D1%82%D1%83%D0%BF_%28%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5%29#.D0.A1.D1.82.D0.B8.D0.BB.D1.8C_.D0.9E.D0.BB.D0.BC.D0.B0.D0.BD.D0.B0) расстановки фигурных скобок. - -### Соглашение в именовании классов - -В Kohana используется нижнее_подчёркивание в именовании классов. Именование с использованием camelCase не приветствуется. - -#### Классы - - // Корневые библиотеки используют суффикс _Core - class Beer_Core { - - // При расширение функционала библиотеки суффикс не используется - class Beer extends Beer_Core - - // Класс контроллера использует суффикс _Controller - class Apple_Controller extends Controller { - - // Класс модели использует суффикс _Model - class Cheese_Model extends Model { - - // Класс хелпера - class peanut { - -Если Вы не передаёте параметры в конструктор при создании класса, не используйте круглые скобки при его объявлении: - - // Правильно: - $db = new Database; - - // Не правильно: - $db = new Database(); - -#### Функции и методы - -Имена функций должны быть в нижнем регистре и использовать нижнее_подчёркивание для разделения слов: - - function drink_beverage($beverage) - { - -#### Переменные - -Все переменные должны быть в нижнем регистре и использовать нижнее_подчёркивание для разделения слов (camelCase использовать запрещено): - - // Правильно: - $foo = 'bar'; - $long_example = 'uses underscores'; - - // Не правильно: - $weDontWantThis = 'understood?'; - -### Отступы - -Используйте табуляцию для отступов в Вашем коде. Использование пробелов вместо табуляции строго запрещено. - -Вертикальные отступы (при многострочном выравнивании) формируются пробелами. Так как ширина табуляции может отличаться у разных людей, для вертикального выравнивания табуляция является не самым лучшем способом. - - $text = 'это разделённый на несколько строк длинный текст. Зачастую, ' - . 'при многострочном разделении используют ограничение в 80 знаков ' - . 'на строку. Для удобочитаемости кода крайне важно применять правильное ' - . 'вертикальное выравнивание текста. Помните, что любые отступы ' - . 'должны выполняться в виде табуляции, а вертикальное выравнивание уже ' - . 'должно завершаться пробелами, которые идут сразу после табов .'; - -### Конкатенация строк - -Не используйте пробелы вокруг оператора конкатенации: - - // Правильно: - $str = 'one'.$var.'two'; - - // Не правильно: - $str = 'one'. $var .'two'; - $str = 'one' . $var . 'two'; - -### Однострочные операторы - -Однострочные операторы IF могут быть использованы лишь в случае прерывания выполнения кода (например, return или continue): - - // Допустимо: - if ($foo == $bar) - return $foo; - - if ($foo == $bar) - continue; - - if ($foo == $bar) - break; - - if ($foo == $bar) - throw new Exception('You screwed up!'); - - // Не допустимо: - if ($baz == $bun) - $baz = $bar + 2; - -### Операторы сравнения - -Используйте, пожалуйста, для сравнения операторы OR и AND: - - // Правильно: - if (($foo AND $bar) OR ($b AND $c)) - - // Не правильно: - if (($foo && $bar) || ($b && $c)) - -Используйте, пожалуйста, elseif вместо else if: - - // Правильно: - elseif ($bar) - - // Не правильно: - else if($bar) - -### Конструкции switch - -Каждый оператор case, break и default должны располагаться на новой строке. Блок внутри case и default должны иметь отступ в 1 таб. - - switch ($var) - { - case 'bar': - case 'foo': - echo 'hello'; - break; - case 1: - echo 'one'; - break; - default: - echo 'bye'; - break; - } - -### Круглые скобки - -Необходимо отделять имя оператора и следующие за ним скобки пробелом. Оператор ! (оператор отрицания, восклицательный знак) для удобочитаемости должен быть выделен пробелом с обеих сторон. - - // Правильно: - if ($foo == $bar) - if ( ! $foo) - - // Не правильно: - if($foo == $bar) - if(!$foo) - if ((int) $foo) - if ( $foo == $bar ) - if (! $foo) - -### Тернарные операторы - -Все тернарные операции должны придерживаться стандартного формата. Используйте круглые скобки только для выделения условий, а не для выделения простых переменных. - - $foo = ($bar == $foo) ? $foo : $bar; - $foo = $bar ? $foo : $bar; - -Все сравнения и операции должны быть заключены в круглые скобки: - - $foo = ($bar > 5) ? ($bar + $foo) : strlen($bar); - -При многострочном разделении тернарного комплекса (при очень длинных условиях, превышающих длину в 80 знаков), для вертикального выравнивания стоит использовать пробелы. Операторы при этом должны располагаться один под другим: - - $foo = ($bar == $foo) - ? $foo - : $bar; - -### Приведение типов - -При приведении типов, следует использовать пробелы вокруг оператора приведения: - - // Правильно: - $foo = (string) $bar; - if ( (string) $bar) - - // Не правильно: - $foo = (string)$bar; - -По возможности, используйте приведение типов вместо тернарных операторов: - - // Правильно: - $foo = (bool) $bar; - - // Не правильно: - $foo = ($bar == TRUE) ? TRUE : FALSE; - -При приведение к числовому или булеву типам, используйте сокращённый формат: - - // Правильно: - $foo = (int) $bar; - $foo = (bool) $bar; - - // Не правильно: - $foo = (integer) $bar; - $foo = (boolean) $bar; - -### Константы - -Имена констант должны быть строго в верхнем регистре: - - // Правильно: - define('MY_CONSTANT', 'my_value'); - $a = TRUE; - $b = NULL; - - // Не правильно: - define('MyConstant', 'my_value'); - $a = True; - $b = null; - -При сравнении располагайте константы в конце: - - // Правильно: - if ($foo !== FALSE) - - // Не правильно: - if (FALSE !== $foo) - -Такой выбор немного спорный, но можно его объяснить следующим. Если вербализировать предыдущие условия и написать их, то можно их прочитать следующим образом для верного примера: - - если переменная $foo в точности не является FALSE - -И для неверного: - - если FALSE в точности не является переменной $foo - -Так как наш язык предусматривает чтение слева направо, то и нет причин для того, чтобы ставить константу первой при сравнении. - -### Комментарии - -#### Однострочные комментарии - -Используйте // перед строкой комментария, делайте отступ и начинайте комментарий с заглавной буквы. Никогда не используйте для комментариев #. - - // Правильно - - //Не правильно - // не правильно - # Не правильно - -### Регулярные выражения - -При использовании регулярных выражений, используйте синтаксис PCRE вместо POSIX. PCRE признан более мощной и быстрой библиотекой регулярных выражений. - - // Правильно: - if (preg_match('/abc/i'), $str) - - // Не правильно: - if (eregi('abc', $str)) - -Используйте одинарные кавычки вокруг регулярного выражения. Одинарные кавычки удобочитаемы ввиду их простоты. Строки, заключённые в одинарные кавычки, в отличие от двойных кавычек, не поддерживают интерполяцию переменных и конструкции с обратным слешем (\n, \t и т.д.). - - // Правильно: - preg_match('/abc/', $str); - - // Не правильно: - preg_match("/abc/", $str); - -При использовании регулярного выражения для поиска и замены, используйте $n нотацию для ссылок. Это более предпочтительно, нежели \\n. - - // Правильно: - preg_replace('/(\d+) dollar/', '$1 euro', $str); - - // Не правильно: - preg_replace('/(\d+) dollar/', '\\1 euro', $str); - -И в заключении, обратите внимание, что символ $ для определения позиции в конце строки не учитывает наличие символа новой строки. Используйте при необходимости модификатор D, чтобы этого избежать. [Подробная информация](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 \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/about.filesystem.md b/includes/kohana/modules/userguide/guide/ru-ru/about.filesystem.md deleted file mode 100644 index 03f90b07..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/about.filesystem.md +++ /dev/null @@ -1,59 +0,0 @@ -# Каскадная файловая система - -Файловая система Kohana представляет собой иерархическая структура каталогов. Когда файл загружается, используя [Kohana::find_file], он ищется в каталогах в следующем порядке: - -Application путь -: Определён как `APPPATH` в `index.php`. Значение по-умолчанию - `application`. - -Module путь -: Определён как ассоциативный массив [Kohana::modules] в `APPPATH/bootstrap.php`. Поиск каждого значение массива будет произведён в том порядке, в каком порядке они определены. - -System путь -: Определён как `SYSPATH` в `index.php`. Значение по-умолчанию - `system`. Все основные или "core" файлы и классы располагаются в этой категории. - -Файлы, находящиеся в каталогах выше уровнем, имеют приоритет над файлами, которые располагаются в таких же папках уровнем ниже, что позволяет перегружать любой файл, путём перемещения файла с таким же названием на уровень выше: - -![Каскадная файловая система](img/cascading_filesystem.png) - -Если у Вас имеется файл представления с названием `wellcome.php`, расположенный в `APPPATH/views` и `SYSPATH/views`, то при поиске файла с этим именем будет возвращен тот, который находится в папке `APPPATH/views` (как находящийся на высшем уровне иерархической системы). Если же удалить файл в каталоге `APPPATH/views`, то при очередном поиске этого файла будет вызван тот, что располагается в каталоге `SYSPATH/views`. - -## Типы файлов - -Верхний уровень каталогов application, module, и system путей, по-умолчанию имеет следующие директории: - -classes/ -: Все классы, которые должны быть [автоматически загружены](using.autoloading) должны располагаться тут. Это касается контроллеров, моделей и всех других классов. Наименования классов должны соответствовать [соглашению по именованию классов](about.conventions#classes). - -config/ -: Конфигурационные файлы возвращают ассоциативный массив опций, который может быть загружен с использованием метода [Kohana::config]. Для более подробной информации, обратитесь к разделу [Настройка](using.configuration). - -i18n/ -: Файлы перевода возвращают ассоциативный массив строк. Перевод осуществляется с использованием метода `__()`.Для того, чтобы перевести "Hello, world!" на Русский, нужно вызвать `__('Hello, world!')` c [I18n::$lang] определённом как "ru-ru". Для более подробной информации, обратитесь к разделу [Интернационализация](using.translation). - -messages/ -: Файлы сообщений возвращают ассоциативный массив строк, который может быть загружен с использованием [Kohana::message]. Разница между сообщениями и файлами интернационализации заключается в том, что сообщения никогда не переводятся, пишутся на языке, используемом по-умолчанию, и вызываются по односложному ключу. Для более подробной информации, обратитесь к разделу [Сообщения (Messages)](using.messages). - -views/ -: Файлы представления являются PHP файлами, которые используются для генерации HTML или другого вида вывода информации. Файлы представления загружаются в объект [View] и присваиваются переменным, которые в дальнейшем конвертируются во фрагменты HTML. Множественные файлы представления могут быть вызваны одни в других. Для более подробной информации, обратитесь к разделу [Представление и HTML](usings.views). - -## Поиск файлов - -Путь к любому файлу в файловой структуре приложения может быть найден путём вызова [Kohana::find_file]: - - // Ищет полный путь до "classes/cookie.php" - $path = Kohana::find_file('classes', 'cookie'); - - // Ищет полный путь до "views/user/login.php" - $path = Kohana::find_file('views', 'user/login'); - -# Сторонние библиотеки - -Мы называем библиотеки, которые не специфичны для Kohana "vendor" библиотеками. Например, если Вы хотите использовать [DOMPDF](http://code.google.com/p/dompdf), то Вам нужно скопировать эту библиотеку в `application/vendor/dompdf` и добавить автозагрузочный класс DOMPDF: - - require Kohana::find_file('vendor', 'dompdf/dompdf/dompdf_config.inc'); - -После этого, можно использовать DOMPDF без загрузки каких-либо других файлов: - - $pdf = new DOMPDF; - -[!!] Если Вы хотите конвертировать представление в PDF с использованием DOMPDF, используйте [PDFView](http://github.com/shadowhand/pdfview) модуль. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/about.flow.md b/includes/kohana/modules/userguide/guide/ru-ru/about.flow.md deleted file mode 100644 index 28c1186d..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/about.flow.md +++ /dev/null @@ -1,73 +0,0 @@ -# Порядок выполнения - -Каждое приложение выполняется в следующем порядке: - -1. Старт приложения из `index.php` -2. Установка путей для application, module, и system. -3. Установка уровня Error reporting. -4. Загружается файл установки, если таковой имеется. -5. Загружается класс [Kohana]. -6. Подключение `APPPATH/bootstrap.php` -7. Вызывается [Kohana::init], который устанавливает обработку ошибок, кэширование и логирование. -8. Подгружаются [Kohana_Config] и [Kohana_Log]. -9. Вызывается [Kohana::modules] для активации дополнительных модулей. - * Информация о пути к модулям добавляется в [каскадную файловую систему](about.filesystem). - * Если находится, подгружается файл `init.php` модуля. - * Файл `init.php` производит дополнительную настройку окружения, включая добавление маршрутов. -10. Несколько раз вызывается [Route::set], чтобы определить все [маршруты](using.routing) приложения. -11. Вызывается [Request::instance], чтобы начать обработку выполнения. - 1. Проверяет все маршруты, пока не найдёт совпадения с вызываемым. - 2. Создаёт инстанс контроллера и передаёт ему запрос. - 3. Вызывает метод [Controller::before]. - 4. Вызывает действие контроллера, которое генерирует ответа на запрос. - 5. Вызывает метод [Controller::after]. - * Предыдущие 5 шагов могут быть вызваны несколько раз при использовании [HMVC подзапросов](about.mvc). -12. Отображается результат ответа на запрос ([Request]). - -## index.php - -Kohana использует в работе паттерн [front controller], что означает, что все запросы направляются на `index.php`. Это позволяет использовать понятный и прозрачный дизайн [файловой системы](about.filesystem). `index.php` содержит лишь основные возможные конфигурационные свойства. Вы лишь можете изменить `$application`, `$modules`, и `$system` пути и выставить уровень оповещения об ошибках. - -Переменная `$application` позволяет определить директорию, которая содержит файлы Вашего приложения. По-умолчанию - это `application`. Переменная `$modules`, соответственно, указывает на директорию с файлами модулей, а `$system` - директорию с файлами ядра Kohana. - -Вы можете переместить эти директории куда угодно. Например, если Вы имеете такую структуру каталогов: - - www/ - index.php - application/ - modules/ - system/ - -То можете переместить директории на уровень выше корня web папки: - - application/ - modules/ - system/ - www/ - index.php - -После этого нужно привести установки в `index.php` к следующему виду: - - $application = '../application'; - $modules = '../modules'; - $system = '../system'; - -Теперь ни один из каталогов не может быть напрямую доступен для web сервера. Совсем не обязательно производить эти изменения, но, помимо прочего, это может быть полезно при использовании одного набора директорий среди множества приложений. - -[!!] В начале всех файлов Kohana присутствует проверка безопасности, дабы предотвратить доступ до файла без использования front контроллера. Однако, более безопасно разместить application, modules, и system директории таким образом, чтобы они были недоступны извне. - -### Сообщения об ошибках - -По-умолчанию, Kohana отображает все ошибки, включая strict mode предупреждения. Это устанавливается, используя [error_reporting](http://php.net/error_reporting): - - error_reporting(E_ALL | E_STRICT); - -Когда Ваше приложение опубликовывается в продуктив, то рекомендуется использовать более консервативные настройки, такие как игнорирование уведомлений: - - error_reporting(E_ALL & ~E_NOTICE); - -Если Вы получаете белый экран при ошибке, то это означает, что Ваш сервер имеет отключённое свойство отображение ошибок. Вы можете включить его, добавив эти строчки сразу после вызова `error_reporting`: - - ini_set('display_errors', TRUE); - -Ошибки должны **всегда** отображаться, даже в продуктиве, так как это позволяет использовать [исключения и обработку ошибок](debugging.errors), чтобы выдавать симпатичную страничку с ошибкой, нежели дезориентирующий белый экран. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/about.install.md b/includes/kohana/modules/userguide/guide/ru-ru/about.install.md deleted file mode 100644 index 7380a99a..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/about.install.md +++ /dev/null @@ -1,89 +0,0 @@ -# Установка - -1. Загрузите последний **стабильный** релиз с [сайта Kohana](http://kohanaframework.org/) -2. Распакуйте загруженный архив (появится директория `kohana`) -3. Загрузите содержание архива на Ваш web-сервер -4. Откройте файл `application/bootstrap.php` и произведите следующие изменения: - - Установите [часовой пояс](http://php.net/timezones) (timezone), который будет использоваться по-умолчанию в Вашем приложении - - Установите `base_url` в параметрах вызова [Kohana::init], чтобы обозначить расположение фреймворка на Вашем сервере -6. Убедитесь в том, что папки `application/cache` и `application/logs` доступны для записи (для *nix ОС воспользуйтесь командой `chmod application/{cache,logs} 0777`) -7. Проверьте правильность установки, открыв URL, указанный Вами ранее как `base_url` в Вашем любимом браузере - -[!!] В зависимости от платформы, установленные поддиректории могут потерять значения прав доступа из-за особенностей процесса zip распаковки. Чтобы выправить права доступа, измените права на 755, выполнив в командной строке `find . -type d -exec chmod 0755 {} \;` из корневой директории Kohana. - -Вы увидите страницу установки. Если будут отображены какие-либо ошибки, необходимо их устранить перед тем, как продолжать работать. - -![Страница установки](img/install.png "Пример страницы установки") - -После того, как Вы убедитесь, что все сконфигурировано правильно, переименуйте или удалите файл `install.php`. После этого Вы увидите приветственную страницу Kohana: - -![Страница приветствия](img/welcome.png "Example of welcome page") - -## Настройка продуктив-окружения - -Имеется несколько вещеё, которые Вы наверняка захотите сделать перед публикацией Вашего приложения. - -1. Прочитайте описание процесса [настройки](about.configuration) этой документации. Оно охватывает большинство глобальных настроек, которые требуют изменения при смене окружения. Основное правило для сайтов в продуктиве - это активация кэширования и отключение профилирования (свойства [Kohana::init]). [Кэширование маршрутов](api/Route#cache) так же может быть полезным при наличии большого числа маршрутов. -2. Обрабатывайте все исключения в `application/bootstrap.php` таким образом, чтобы не было утечки конфиденциальной информации при попытках трассировки запросов. Изучите нижеизложенный пример, который был взят из [исходных кодов сайта wingsc.com](http://github.com/shadowhand/wingsc), написанного Shadowhand'ом. -3. Включите APC или любой другой вид кэширования кода. Это единственный и самый простой способ увеличения производительности, который можно применить к самому PHP. Чем сложнее и больше Ваше приложение, тем больше выгода от использования кэширования кода. - - /** - * 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; - diff --git a/includes/kohana/modules/userguide/guide/ru-ru/about.kohana.md b/includes/kohana/modules/userguide/guide/ru-ru/about.kohana.md deleted file mode 100644 index 6367779e..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/about.kohana.md +++ /dev/null @@ -1,15 +0,0 @@ -# Что такое Kohana? - -Kohana это открытый, [объектно-ориентированный](http://ru.wikipedia.org/wiki/Объектно-ориентированное_программирование) [MVC](http://ru.wikipedia.org/wiki/Model–View–Controller "Model View Controller") web-фреймворк, построенный на [PHP5](http://docs.php.net/manual/ru/intro-whatis.php "PHP Hypertext Preprocessor") на общественных началах, основными целями которого являются скорость, безопасность и небольшой размер. - -[!!] Kohana использует лицензию [BSD](http://kohanaphp.com/license), так что Вы можете свободно использовать ее в любых своих открытых, коммерческих или персональных проектах. - -## Чем хороша Kohana? - -Что угодно может быть расширено с помощью уникальной [файловой системы](about.filesystem), требуется минимум [настроек](about.configuration), [перехват ошибок](debugging.errors) помогает быстро определить источник ошибок, а [отладка](debugging) и [профилирование](debugging.profiling) дают представление о происходящем внутри приложения. - -Чтобы обезопасить Ваши приложения, представлены инструменты для [защиты от XSS](security.xss), [проверки введенных данных](security.validation), работы с [cookies](security.cookies), генераторы [форм](security.forms) и [HTML](security.html). Слой [баз данных](security.database) предусматривает защиту от [SQL-инъекций](http://ru.wikipedia.org/wiki/SQL-инъекция). Разумеется, весь официальный код написан с душой и проверен на наличие уязвимостей. - -## Эта документация - г*вно! - -Мы очень активно работаем над тем, чтобы обеспечить полное документирование. В случае, если Вы не смогли найти ответ на свой вопрос, прочитайте [неофициальную wiki](http://kerkness.ca/wiki/doku.php). Если Вы хотели бы что-то добавить или изменить в Руководстве пользователя, пожалуйста [сделайте свой форк userguide'а](http://github.com/kohana/userguide), внесите свои изменения и пошлите pull request. Если Вы ещё не познакомились с работой с Git, Вы так же можете опубликовать [запрос на изменение](http://dev.kohanaframework.org/projects/kohana3/issues) (требуется регистрация). diff --git a/includes/kohana/modules/userguide/guide/ru-ru/about.mvc.md b/includes/kohana/modules/userguide/guide/ru-ru/about.mvc.md deleted file mode 100644 index 3d9e0d6c..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/about.mvc.md +++ /dev/null @@ -1,5 +0,0 @@ -# Модель-Представление-Контроллер - -Модель-Представление-Контроллер (сокращенно MVC) - это популярный паттерн проектирования, используя который источник данных (Модель) отделяется от шаблонов представления (Представление) и логики запроса (Контроллер). - -Это делает процесс разработки легче, т.к. облегчается повторное использование кода. Это означает, что писать придется намного меньше кода! \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/about.upgrading.md b/includes/kohana/modules/userguide/guide/ru-ru/about.upgrading.md deleted file mode 100644 index 86623ee8..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/about.upgrading.md +++ /dev/null @@ -1,292 +0,0 @@ -# Переход с 2.3.x - -Многое в Kohana v3 работает совсем по другому, нежели в Kohana 2.3, вот список самых популярных советов для обновляющихся. - -## Правила именования - -Ветка 2.x выделяет различные 'типы' классов (т.е. контроллер, модель и т.д.), используя для этого суффиксы. Директории внутри папок model / controller не влияют на имя класса. - -В 3.0 от данного подхода отказались в пользу файловых соглашений Zend framework , в котором имя класса является путем к файлу, разделенному знаками подчеркивания вместо слэщей (т.е. `/some/class/file.php` становится `Some_Class_File`) - -Смотри [описание соглашений](start.conventions) для получения подробной информации. - -## Библиотека Input - -Библиотека Input была исключена из 3.0, просто используйте `$_GET` и `$_POST`. - -### Защита от XSS - -Если Вам нужно обезопасить от XSS введенные пользователем данные, можете использовать [Security::xss_clean] : - - $_POST['description'] = security::xss_clean($_POST['description']); - -Также можно вызывать [Security::xss_clean] в качестве фильтра для объекта [Validate]: - - $validation = new Validate($_POST); - - $validate->filter('description', 'Security::xss_clean'); - -### POST & GET - -Одной из важнейших возможностей библиотеки Input было то, что если Вы попытаетесь обратиться к значению одного из суперглобальных массивов и оно не задано, библиотека Input возвратит значение по умолчанию, которое Вы зададите, например: - - $_GET = array(); - - // $id установлено в 1 - $id = Input::instance()->get('id', 1); - - $_GET['id'] = 25; - - // $id установлено в 25 - $id = Input::instance()->get('id', 1); - -В 3.0 Вы можете сделать то же самое с помощью [Arr::get]: - - $_GET = array(); - - // $id установлено в 1 - $id = Arr::get($_GET, 'id', 1); - - $_GET['id'] = 42; - - // $id установлено в 42 - $id = Arr::get($_GET, 'id', 1); - -## Библиотека ORM - -Произошло немало серьезных изменений в ORM после версии 2.3, вот список наиболее известных проблем после обновления. - -### Свойства - -Все свойства модели теперь начинаются со знака подчеркивания (_) и больше не доступны через метод `__get()`. Вместо этого Вы должны вызвать метод с именем свойства, но без подчеркивания. - -Например, свойство, бывшее в 2.3 `loaded`, теперь называется `_loaded` и извне класса доступно через `$model->loaded()`. - -### Связи - -В 2.3, если Вы хотели пройтись по связанным с моделью объектам, надо было использовать: - - foreach($model->{relation_name} as $relation) - -Однако в новой системе это не будет работать. В версии 2.3 любой запрос с использованием библиотеки Database, был сгенерирован глобально, т.е. у Вас не получится создать одновременно два запроса. Вот пример: - -# TODO: Нужен достойный пример!!!! - -Этот запрос приведет к ошибке, т.к. второй запрос будет 'наследовать' условия первого, тем самым вызывая чертовщину. -В v3.0 это было исправлено выделением каждого запроса в свою собственную 'песочницу', это приводит к тому, что некоторые вещи работают не так, как ожидается. Пример: - - foreach(ORM::factory('user', 3)->where('post_date', '>', time() - (3600 * 24))->posts as $post) - { - echo $post->title; - } - -[!!] (Смотри описание нового синтаксиса запросов в [руководстве по Database](tutorials.databases)) - -В 2.3 данный запрос вернет объект-итератор всех записей пользователя с id=3, где поле `post_date` лежит в диапазоне последних 24 часов. Однако новая версия применит условия where к пользовательской модели и вернет объединенную через join модель `Model_Post`. - -Для достижения нужного эффекта необходимо перераспределить порядок вызовов: - - foreach(ORM::factory('user', 3)->posts->where('post_date', '>', time() - (36000 * 24))->find_all() as $post) - { - echo $post->title; - } - -Аналогично со связями `has_one`: - - // Неправильно - $user = ORM::factory('post', 42)->author; - // Правильно - $user = ORM::factory('post', 42)->author->find(); - -### Связи много-ко-многим - -В 2.3 Вы можете указать `has_and_belongs_to_many` тип связи. В 3.0 эта функциональность была переработана в связь *сквозное* `has_many`. - -В моделях определяется связь `has_many` с другой моделью, но добавляется атрибут `'through' => 'table'` , где `'table'` - имя промежуточной таблицы. Например (в контексте области записи<>категории): - - $_has_many = array - ( - 'categories' => array - ( - 'model' => 'category', // внешняя модель - 'through' => 'post_categories' // промежуточная модель - ), - ); - -Если Вы настроили kohana с использованием табличных префиксов, то не стоит беспокоиться о явном указании префиксов в модели. - -### Внешние ключи - -Если Вы хотели переопределить внешний ключ в ORM ветки 2.x, надо было указать в принадлежащей (слабой) модели свойство `$foreign_keys` со значением имени внешнего ключа. - -В 3.0 Вы определяется ключ `foreign_key` в самом объявлении связи, вот так: - - Class Model_Post extends ORM - { - $_belongs_to = array - ( - 'author' => array - ( - 'model' => 'user', - 'foreign_key' => 'user_id', - ), - ); - } - -В данном примере мы настроили поле `user_id` для таблицы записей. - - - -В связях has_many атрибут `far_key` (дальний ключ) является полем в промежуточной таблице, которое связано с внешней (для текущей) таблицей, а внешний ключ является полем в промежуточной таблице, которое связано с "этой" таблицей. - -Следуя вышесказанному, "posts" связаны много-ко-многим с "categories" через `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', - ), - ); - } - - -Очевидно, что настройки псевдонимов выглядят несколько неадекватными, но это хороший пример того, как работает схема внешний/дальний ключ. - -### ORM Iterator - -Стоит также отметить, что от класса `ORM_Iterator` отказались в пользу `Database_Result`. - -Если надо получить массив объектов ORM с ключами из первичных ключей, надо вызвать [Database_Result::as_array], вот так: - - $objects = ORM::factory('user')->find_all()->as_array('id'); - -Здесь `id` является первичным ключом таблицы. - -## Библиотека Router - -В версии 2 была библиотека Router, которая обрабатывала основной запрос приложения. Она позволяла определить базовые маршруты в файле `config/routes.php` и использовать собственные регулярные выражения для них, однако этого было недостаточно для описания чего-нибудь нестандартного. - -## Маршруты - -Система маршрутизации (теперь логичнее называть ее системой запросов) в версии 3.0 стала намного более гибкой. Маршруты объявляются в загрузочном файле (`application/bootstrap.php`) и скриптах init.php модулей (`modules/module/init.php`). (Стоит также отметить, что маршруты рассматриваются в том же порядке, в каком были определены). - -Вместо объявления массива маршрутов теперь необходимо создавать новый объект [Route] на каждый маршрут. В отличие от ветки 2.x нет необходимости отделять один URI от другого. Вместо этого Вы определяете шаблон с использованием переменных для обозначения секций (таких как контроллер, метод, id). - -К примеру, в предыдущей системе данное выражение: - - $config['([a-z]+)/?(\d+)/?([a-z]*)'] = '$1/$3/$1'; - -подменит URI `controller/id/method` на `controller/method/id`. В 3.0 следует использовать: - - Route::set('reversed','((/(/)))') - ->defaults(array('controller' => 'posts', 'action' => 'index')); - -[!!] Каждому маршруту назначается уникальное имя (в данном случае он называется `reversed`), причины описаны в [учебнике по URL](tutorials.urls). - -Угловые скобки являются признаком динамических секций, которые будут сохранены в виде переменных. Круглые скобки обозначают необязательные участки. Если Вы хотите обрабатывать только адреса, начинающиеся с `admin`, используйте: - - Rouse::set('admin', 'admin(/(/(/)))'); - -А если надо заставить пользователя указать контроллер: - - Route::set('admin', 'admin/(/(/))'); - -Также Kohana не устанавливает сама значений по умолчанию. Если Вы хотите, чтобы Kohana установила метод 'index' как дефолтный, необходимо указать это в явном виде! Сделайте это с помощью [Route::defaults]. Когда надо указать регулярное выражение для отдельных сегментов uri, добавьте параметр - массив вида `segment => regex`. Например: - - Route::set('reversed', '((/(/)))', array('id' => '[a-z_]+')) - ->defaults(array('controller' => 'posts', 'action' => 'index')) - -Значение сегмента `id` теперь должно состоять только из маленьких латинских букв и знака подчеркивания. - -### Экшены - -Еще один момент, который необходимо отметить - методы контроллера, которые должны быть доступны через url теперь называются "экшены" ("actions"), и начинаются с префикса 'action_'. В вышеуказанном примере, если пользователь введет `admin/posts/1/edit`, то экшен будет называться `edit`, но вызываемый метод контроллера получится `action_edit`. Подробности в [учебнике url](tutorials.urls). - -## Сессии - -Больше нет методов Session::set_flash(), Session::keep_flash() и Session::expire_flash(), вместо них используйте [Session::get_once]. - -## Хэлпер URL - -Изменилось немногое - `url::redirect()` перемещен в `$this->request->redirect()` (при вызове из контроллера) / `Request::instance()->redirect()` - -`url::current` заменен на `$this->request->uri()` - -## Valid / Validation - -Эти два класса были объединены в единый класс `Validate`. - -Немного изменился синтаксис для валидации массивов: - - $validate = new Validate($_POST); - - // Применяем фильтр на все элементы массива - $validate->filter(TRUE, 'trim'); - - // Для указания специфических правил используйте rule() - $validate - ->rule('field', 'not_empty') - ->rule('field', 'matches', array('another_field')); - - // Устанавливайте множество правил для одного поля через rules(), передавая массив вида rules => params в качестве второго параметра - $validate->rules('field', array( - 'not_empty' => NULL, - 'matches' => array('another_field') - )); - -Стандартное правило 'required' было переименовано в 'not_empty' для ясности. - -## Библиотека View - -Сделано несколько незначительных изменений, которые стоит отметить. - -В 2.3 представления формировались в зоне видимости контроллера, что позволяло в представлении использовать `$this` как ссылку на контроллер, и в 3.0 теперь по-другому. Представления теперь генерируются в пустом окружении. Если необходимо использовать `$this` в шаблоне, создайте ссылку с помощью [View::bind]: `$view->bind('this', $this)`. - -Тем не менее, стоит отметить, что это *очень* плохая привычка, т.к. повышает сцепление представления с контроллером и усложняет повторное использование. Рекомендуется подключать необходимые переменные таким образом: - - $view = View::factory('my/view'); - - $view->variable = $this->property; - - // ИЛИ если нравится запись по цепочке - - $view - ->set('variable', $this->property) - ->set('another_variable', 42); - - // НЕ рекомендуется - $view->bind('this', $this); - -Так как представление формируется в пустом окружении, `Controller::_kohana_load_view` теперь избыточно. Если надо изменить представление до его генерации (например, добавить меню сайта), используйте [Controller::after]. - - template->menu = '...'; - - return parent::after(); - } - } diff --git a/includes/kohana/modules/userguide/guide/ru-ru/debugging.code.md b/includes/kohana/modules/userguide/guide/ru-ru/debugging.code.md deleted file mode 100644 index b4ba01d2..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/debugging.code.md +++ /dev/null @@ -1,18 +0,0 @@ -# Отладка - -Kohana включает несколько удобных инструментов для отладки Вашего приложения. - -Основной из них - [Kohana::debug]. Этот простой метод показывает любое количество переменных, аналогично [var_export] или [print_r], но с использованием HTML для дополнительного форматирования. - - // Показывает дамп переменных $foo и $bar - echo Kohana::debug($foo, $bar); - -Kohana также предоставляет метод для отображения исходного кода отдельного файла, используя [Kohana::debug_source]. - - // Показывает текущую линию исходного кода - echo Kohana::debug_source(__FILE__, __LINE__); - -Если вы хотите показать информацию о файлах приложения, не показывая реального пути, вы можете использвать [Kohana::debug_path]: - - // Показывает "APPPATH/cache" вместо реального пути - echo Kohana::debug_file(APPPATH.'cache'); diff --git a/includes/kohana/modules/userguide/guide/ru-ru/debugging.errors.md b/includes/kohana/modules/userguide/guide/ru-ru/debugging.errors.md deleted file mode 100644 index 7ec04b04..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/debugging.errors.md +++ /dev/null @@ -1,22 +0,0 @@ -# Обработка ошибок/исключений - -Kohana предоставляет обработчик как для исключений, так и для ошибок (он превращает ошибку в исключение с помощью стандартного PHP-класса [ErrorException](http://php.net/errorexception)). Обработчик показывает множество подробностей и внутреннее состояние приложения: - -1. Класс исключения -2. Уровень ошибки -3. Текст ошибки -4. Исходный код, вызвавший ошибку, соответствующая строка подсвечивается -5. [Трассировка](http://php.net/debug_backtrace) хода выполнения -6. Подключенные файлы, загруженные расширения и глобальные переменные - -## Пример - -Нажмите по любой ссылке для раскрытия блока дополнительной информации: - -
      {{userguide/examples/error}}
      - -## Отключение обработчика ошибок/исключений - -Если Вы не хотите использовать встроенный обработчик ошибок, отключите его с помощью [Kohana::init]: - - Kohana::init(array('errors' => FALSE)); diff --git a/includes/kohana/modules/userguide/guide/ru-ru/debugging.profiling.md b/includes/kohana/modules/userguide/guide/ru-ru/debugging.profiling.md deleted file mode 100644 index 020bac18..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/debugging.profiling.md +++ /dev/null @@ -1,20 +0,0 @@ -# Профилирование - -Kohana предлагает очень простой способ для отображения статистики Вашего приложения: - -1. Системных вызовов [Kohana] -2. Запросов (Requests) -3. Запросов к [базам данных](Database) -4. Среднего времени выполнения Вашего приложения - -## Пример - -Вы можете отобразить или собрать текущую статистику [профилировщика](profiler) в любое время: - -
      - -
      - -## Что получится - -{{profiler/stats}} \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/features.md b/includes/kohana/modules/userguide/guide/ru-ru/features.md deleted file mode 100644 index 76f3fa7c..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/features.md +++ /dev/null @@ -1 +0,0 @@ -Эта страница перечисляет возможности Kohana v3 \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/menu.md b/includes/kohana/modules/userguide/guide/ru-ru/menu.md deleted file mode 100644 index d8cf8eee..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/menu.md +++ /dev/null @@ -1,32 +0,0 @@ -1. **Первые шаги** - - [Что такое Kohana?](about.kohana) - - [Соглашения и стили](about.conventions) - - [Модель-Представление-Контроллер](about.mvc) - - [Файловая система](about.filesystem) - - [Порядок выполнения](about.flow) - - [Установка](about.install) - - [Обновление](about.upgrading) - - [Обзор API](api) -2. **Основные операции** - - [Настройка](using.configuration) - - [Автозагрузка](using.autoloading) - - [Представление и HTML](using.views) - - [Сессии и Cookies](using.sessions) - - [Сообщения (Messages)](using.messages) - - [Интернационализация](using.translation) -3. **Отладка** - - [Отладка кода](debugging.code) - - [Обработка ошибок](debugging.errors) - - [Профилирование](debugging.profiling) -4. **Безопасность** - - [XSS](security.xss) - - [Валидация](security.validation) - - [Cookies](security.cookies) - - [База данных](security.database) -5. **Обучение** - - [Hello, World](tutorials.helloworld) - - [Маршруты, URL и ссылки](tutorials.urls) - - [Очистка URL, ЧПУ](tutorials.removeindex) - - [Базы данных](tutorials.databases) - - [ORM](tutorials.orm) - - [Работа с Git](tutorials.git) \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/security.cookies.md b/includes/kohana/modules/userguide/guide/ru-ru/security.cookies.md deleted file mode 100644 index 13a8480d..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/security.cookies.md +++ /dev/null @@ -1,3 +0,0 @@ -# Безопасность Cookie - -[!!] заглушка diff --git a/includes/kohana/modules/userguide/guide/ru-ru/security.database.md b/includes/kohana/modules/userguide/guide/ru-ru/security.database.md deleted file mode 100644 index 504a2740..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/security.database.md +++ /dev/null @@ -1,3 +0,0 @@ -# Безопасность Database - -[!!] заглушка diff --git a/includes/kohana/modules/userguide/guide/ru-ru/security.validation.md b/includes/kohana/modules/userguide/guide/ru-ru/security.validation.md deleted file mode 100644 index 4c0d21bb..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/security.validation.md +++ /dev/null @@ -1,243 +0,0 @@ -# Валидация - -С использованием [Validate] класса можно произвести валидацию любого массива. По ключу значения массива ("наименование поля" для валидатора), к объекту валидации можно добавить ярлыки, фильтры, правила и функции обратного вызова. - -labels (ярлыки) -: Ярлык - это удобочитаемая интерпретация имени поля. - -filters (фильтры) -: Фильтр видоизменяет значение поля перед применением к нему правил и функций обратного вызова. - -rules (правила) -: Правило - это проверка значения поля, которая возвращает `TRUE` или `FALSE` в результате проверки. Если правило возвращает `FALSE`, то полю будет добавлена информация об ошибке. - -callbacks (функция обратного вызова) -: Функция обратного вызова - это пользовательский метод, который имеет доступ до содержания объекта валидации. Возвращаемое значение функции игнорируется, ввиду этого, функция должна сама добавлять ошибку к полу объекта валидации, используя метод [Validate::error], при возникновении ошибки. - -[!!] Заметьте, что функции обратного вызова объекта [Validate] и функции обратного вызова PHP ([PHP callbacks](http://php.net/manual/language.pseudo-types.php#language.types.callback)) - это не одно и то же. - -Если вместо имени поля при добавлении фильтра, правила или функции обратного вызова использовать значение `TRUE`, то этот фильтр, правило или функция будет применена ко всем полям объекта Validate. - -**В мерах предосторожности, объект [Validate] удалит все поля из массива, которым не присвоен ярлык, фильтр, правило или функция обратного вызова. Это предотвращает доступ до полей, которые не участвуют в валидации.** - -Создание объекта валидации производится с использованием метода [Validate::factory]: - - $post = Validate::factory($_POST); - -[!!] Далее в данном руководстве будет использован объект `$post`. Как пример, будет рассмотрена валидация регистрации нового пользователя. - -### Стандартные правила - -Класс валидации содержит следующие правила: - -Наименование правила | Действие -------------------------- |------------------------------------------------- -[Validate::not_empty] | Значение не должно быть пустым -[Validate::regex] | Проверяется значение на совпадение с регулярным выражением -[Validate::min_length] | Минимальная длина значения (минимальное количество знаков) -[Validate::max_length] | Максимальная длина значения (максимальное количество знаков) -[Validate::exact_length] | Длина значения должна быть равна указанному числу -[Validate::email] | Значение должно представлять собой emal адрес -[Validate::email_domain] | Проверяет существование email домена -[Validate::url] | Значение должно представлять собой URL -[Validate::ip] | Значение должно представлять собой IP адрес -[Validate::phone] | Значение должно представлять собой номер телефона -[Validate::credit_card] | Значение должно представлять собой номер кредитной карты -[Validate::date] | Значение должно представлять собой дату (и время) -[Validate::alpha] | Допустимы только буквенные значения -[Validate::alpha_dash] | Допустимы значения, состоящие из букв и тире -[Validate::alpha_numeric] | Допустимы только буквенные и числовые значения -[Validate::digit] | Значение должно представлять собой целое число -[Validate::decimal] | Значение должно представлять собой число десятичное число или число с плавающей точкой -[Validate::numeric] | Допустимы только цифровые символы -[Validate::range] | Значение должно быть в указанных пределах -[Validate::color] | Значение должно представлять собой правильное значение цвета в HEX -[Validate::matches] | Значение должно совпадать со значением другого поля - -[!!] Любой метод [Validate] класса может быть использован как правило валидации без определения полного обратного вызова (callback). Например, добавление `'not_empty'` - то же самое, что и `array('Validate', 'not_empty')`. - -## Добавление фильтров - -Фильтр валидации задаётся как имя поля, метод или функция (используя синтаксис [PHP callback](http://ru2.php.net/callback)) и массив параметров: - - $object->filter($field, $callback, $parameters); - -Фильтры изменяют значение поля перед проверкой правилами или функциями обратного вызова. - -Для того, чтобы конвертировать значение поля "username" в нижний регистр: - - $post->filter('username', 'strtolower'); - -Если мы хотим удалить все пробелы до и после значения у *всех* полей: - - $post->filter(TRUE, 'trim'); - -## Добавление правил - -Все правила валидации задаются как имя поля, метод или функция (используя синтаксис [PHP callback](http://ru2.php.net/callback)) и массива параметров: - - $object->rule($field, $callback, $parameters); - -Для начала, инициируем валидацию `$_POST` массива, который содержит информацию о регистрации: - - $post = Validate::factory($_POST); - -Далее, нам необходимо обработать полученные данные, используя [Validate] класс. Во-первых, добавим несколько правил: - - $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'); - -В виде правила можно использовать практически все функции PHP. Например, можно проверить, верное ли значение ввёл пользователь на SSL вопрос: - - $post->rule('use_ssl', 'in_array', array(array('yes', 'no'))); - -Имейте в виду, что все параметры должны быть в виде массива! Если параметры были не в виде массива, то функция `in_array` была бы вызвана как `in_array($value, 'yes', 'no')`, что привело бы к PHP ошибке. - -Пользовательские правила могут быть добавлены, используя синтаксис [PHP callback](http://ru2.php.net/callback): - - $post->rule('username', array($model, 'unique_username')); - -Метод `$model->unique_username()` определяется следующим образом: - - public function unique_username($username) - { - // Проверка на то, имеется ли указанное значение username в БД - return ! DB::select(array(DB::expr('COUNT(username)'), 'total')) - ->from('users') - ->where('username', '=', $username) - ->execute() - ->get('total'); - } - -[!!] Пользовательские правила позволяют производить большое количество дополнительных проверок и могут быть использованы для различных целей множество раз. Зачастую, они создаются как методы модели, однако, если необходимо, могут быть определены в любом классе. - -## Добавление функций обратного вызова (callbacks) - -Все функции обратного вызова (callback) определяются как имя поля, метод или функция (используя синтаксис [PHP callback](http://ru2.php.net/callback)) и массива параметров: - - $object->callback($field, $callback, $parameters); - -[!!] До версии kohana 3.0.7, функции обратного вызова не обрабатывали входных параметров, в отличие от фильтров и правил. Если Вы используете старую версию, эти параметры будут проигнорированы. - -Пароль пользователя должен быть захэширован, если он прошёл валидацию, поэтому это можно сделать, используя функцию обратного вызова: - - $post->callback('password', array($model, 'hash_password')); - -Это подразумевает, что метод `$model->hash_password()` будет работать следующим образом: - - public function hash_password(Validate $array, $field) - { - if ($array[$field]) - { - // Хэшировать пароль, если он присутствует - $array[$field] = sha1($array[$field]); - } - } - -# Полный пример - -Во-первых, нам понадобится представление ([View]), которое содержит HTML форму и которое будет располагаться в `application/views/user/register.php`: - - - -

      Были допущены следующие ошибки:

      -
        - -
      • - - - -
        -
        -
        - -
        -
        -
        Пароль должен быть длиной как минимум в 6 знаков.
        -
        -
        - -
        -
        'Всегда', 'no' => 'По необходимости'), $post['use_ssl']) ?>
        -
        В целях безопасности, при проведении платежей всегда используется протокол SSL.
        -
        - - - - -[!!] В этом примере повсеместно используется хелпер [Form]. Использование [Form] вместо формирования HTML кода формы вручную, гарантирует корректную обработку входящих данных. Если Вы предпочитаете писать HTML собственноручно, используйте метод [HTML::chars], чтобы обезопасить приложение от введённых пользователем данных. - -Во-вторых, нам потребуется контроллер и действие этого контроллера, чтобы произвести регистрацию, которые будут располагаться в файле `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()) - { - // Данные прошли проверку, теперь можно зарегистрировать пользователя - $user->register($post); - - // Всегда делайте редирект после успешного POST запроса, чтобы избежать - // повторного ввода информации при обновлении страницы - $this->request->redirect('user/profile'); - } - - // Валидация не прошла, собираем ошибки - $errors = $post->errors('user'); - - // Отображаем форму регистрации - $this->request->response = View::factory('user/register') - ->bind('post', $post) - ->bind('errors', $errors); - } - - } - -Так же нам потребуется модель пользователя, которую поместим в `application/classes/model/user.php`: - - class Model_User extends Model { - - public function register($array) - { - // Создание нового пользователя в БД - $id = DB::insert(array_keys($array)) - ->values($array) - ->execute(); - - // Сохраняем id нового пользователя в cookie - cookie::set('user', $id); - - return $id; - } - - } - -Вот и всё, у нас имеется готовый пример для регистрации пользователя, который правильно проверяет введённые пользователем данные! \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/security.xss.md b/includes/kohana/modules/userguide/guide/ru-ru/security.xss.md deleted file mode 100644 index 428c958c..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/security.xss.md +++ /dev/null @@ -1,15 +0,0 @@ -# Защита от межсайтового скриптинга (XSS) - -Первый шаг для предотвращения [XSS](http://ru.wikipedia.org/wiki/Xss) атак - необходимо знать, когда и от чего себя защищать. XSS может быть выполнен тогда, когда он отображается внутри HTML-содержимого, иногда после введения данных через форму или выборки из базы данных. Любая глобальная переменная, содержащая информацию от клиента, может быть заражена. Это касается данных из `$_GET`, `$_POST` и `$_COOKIE`. - -## Предотвращение - -Существует несколько простых правил, защищающих ваше приложение от XSS. Первое - использование метода [Security::xss] для очистки любых входящих данных, полученных из глобальных переменных. Если вы не ожидаете HTML код в переменной, используйте [strip_tags](http://php.net/strip_tags) для удаления нежелательных HTML тэгов. - -[!!] Если вы позволяете пользователям передавать HTML в ваше приложение, настоятельно рекомендуется использовать утилиты для очистки HTML кода, такие как [HTML Purifier](http://htmlpurifier.org/) или [HTML Tidy](http://php.net/tidy). - -Второй шаг - всегда очищать данные перед их вставкой в HTML код. Класс [HTML] предоставляет возможность создавать наиболее употребляемые тэги, включая ссылки на скрипты и таблицы стилей, гиперссылки, изображения, ссылки на адреса электронной почты (mailto). Все подозрительные данные должны быть экранированы с помощью [HTML::chars]. - -## Ссылки - -* [OWASP XSS Cheat Sheet](http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) diff --git a/includes/kohana/modules/userguide/guide/ru-ru/start.autoloading.md b/includes/kohana/modules/userguide/guide/ru-ru/start.autoloading.md deleted file mode 100644 index b3ad1dc8..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/start.autoloading.md +++ /dev/null @@ -1,17 +0,0 @@ -# Автозагрузка - -Kohana использует все преимущества [автозагрузки](http://php.net/manual/language.oop5.autoload.php) в PHP. Это позволяет не использовать функций [include](http://php.net/include) или [require](http://php.net/require) перед использованием класса. - -Классы подгружаются с помощью метода [Kohana::auto_load], который использует простое соотношение имени класса с именим файла этого класса: - -1. Классы располагаются в категории `classes/` в [файловой системе](start.filesystem) фреймворка -2. Все нижние подчёркивания в имени класса конвертируются в слеши -2. Имя файла пишется в нижнем регистре - -При вызове ещё не подгружённого класса (например, `Session_Cookie`), Kohana будет искать с помощью [Kohana::find_file] файл `classes/session/cookie.php`. - -## Пользовательские автозагрузчики - -[!!] Автозагрузчик по-умолчанию активирован в `application/bootstrap.php`. - -Дополнительные загрузчики классов могут быть добавлены с использованием [spl_autoload_register](http://php.net/spl_autoload_register). diff --git a/includes/kohana/modules/userguide/guide/ru-ru/start.configuration.md b/includes/kohana/modules/userguide/guide/ru-ru/start.configuration.md deleted file mode 100644 index 45ccc566..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/start.configuration.md +++ /dev/null @@ -1,92 +0,0 @@ -# Общие настройки - -[!!] TODO: описание преимуществ статических свойств конфигурации - -## Настройки ядра - -Первой задачей конфигурирования новой установки Kohana является изменение параметров [Kohana::init] в `application/bootstrap.php`. Вот эти параметры: - -`boolean` errors -: Использование встроенного обработчика ошибок и исключений. (По-умолчанию: `TRUE`) Установите в `FALSE`, чтобы отменить перехват ошибок и исключений фреймворком. - -`boolean` profile -: Использовать возможности встроенного бенчмаркинга. (По-умолчанию: `TRUE`) Установите в `FALSE`, чтобы отменить профилирование. Для увеличения производительности на стадии production данный параметр рекомендуется отключать. - -`boolean` caching -: Кэширование информации о расположении файлов между запросами. (По-умолчанию: `FALSE`) Установите в `TRUE`, чтобы включить кэширование значений абсолютных путей исполняемых файлов. Это значительно ускоряет [Кохана::find_file] и может иногда оказать серьезное влияние на производительность. Используйте на этапе production или для тестирования. - -`string` charset -: Кодировка, используемая во всех операциях ввода-вывода. (По-умолчанию: `"utf-8"`) Должна поддерживаться как [htmlspecialchars](http://php.net/htmlspecialchars), так и [iconv](http://php.net/iconv). - -`string` base_url -: Базовый URL для приложения. (По-умолчанию: `"/"`) Может быть как абсолютным, так и относительным URL. Например, "http://example.com/kohana/" или просто "/kohana/": подходят оба варианта. - -`string` index_file -: Имя PHP файла, который запускает приложение (фронтенд). (По-умолчанию: `"index.php"`) Установите в `FALSE`, если намереваетесь использовать URL rewriting. - -`string` cache_dir -: Директория для хранения файлового кэша. (По-умолчанию: `"application/cache"`) Директория должна быть **доступна для записи**. - -## Настройки Cookie - -Перед запуском production-версии сайта следует установить значения некоторых статических свойств [Cookie] класса. - -`string` salt -: Уникальная строка salt-значения, которая используется для работы [cookies](security.cookies) - -`integer` expiration -: По-умолчанию: время жизни cookies в секундах - -`string` path -: URL, ограничивающий доступ к cookies - -`string` domain -: Домен, ограничивающий доступ к cookies - -`boolean` secure -: Позволить использовать cookies только по протоколу HTTPS - -`boolean` httponly -: Позволить использовать cookies только по протоколу HTTP (также закрывается доступ через Javascript) - -# Конфигурационные файлы - -Настройки хранятся в виде PHP файлов примерно такого вида: - -~~~ - 'value', - 'options' => array( - 'foo' => 'bar', - ), -); -~~~ - -Если конфигурационный файл был назван `myconf.php`, то для доступа к нему можно использовать следующий код: - -~~~ -$config = Kohana::config('myconf'); -$options = $config['options']; -~~~ - -[Kohana::config] позволяет так же использовать "пути с точкой" для доступа к отдельным ключам конфигурационного массива. - -Для получения массива "options": - -~~~ -$options = Kohana::config('myconf.options'); -~~~ - -Для получения значения ключа "foo" массива "options": - -~~~ -$foo = Kohana::config('myconf.options.foo'); -~~~ - -Вы можете работать с настроечными массивами как с объектами, если это будет удобнее: - -~~~ -$options = Kohana::config('myconf')->options; -~~~ \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/start.controllers.md b/includes/kohana/modules/userguide/guide/ru-ru/start.controllers.md deleted file mode 100644 index 189c7390..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/start.controllers.md +++ /dev/null @@ -1,104 +0,0 @@ -# Контроллеры - -Контроллеры являются промежуточным звеном между моделью и представлением. Они передают информацию в модель для изменения данных, и запрашивают информацию от модели. Например, операции работы с базой данных: вставка (insert), изменение (update) и удаление (delete) как операции редактирования данных, и выборка (select) для извлечения данных. Информацию, полученную от модели, контроллеры перенаправляют в представления, которые содержат конечный результат, предназначенный для отображения пользователям. - -Контроллеры вызываются с помощью URL. За более подробной информацией обратитесь к разделу [URL и ссылки](start.urls). - - - -## Название контроллера и его содержание - -Имя класса контроллера должно соответствовать имени файла. - -**Соглашения при использовании контроллеров** - -* имя файла должно быть в нижнем регистре, например: `articles.php` -* файл контроллера должен располагаться в (под-)директории **classes/controller**, например: `classes/controller/articles.php` -* имя класса контроллера должно соответствовать имени файла, начинаться с заглавной буквы и должно начинаться с префикса **Controller_**, например: `Controller_Articles` -* класс контроллера должен быть потомком класса Controller. -* методы контроллера, предназначенные для вызова через URI, должны начинаться с префикса **action_** (например: `action_do_something()` ) - - - -### Пример простейшего контроллера - -Создадим простой контроллер, который будет выводить на экран 'Hello World!'. - -**application/classes/controller/article.php** -~~~ - MODPATH.'database', - ... - )); - -## Настройка {#configuration} - -После подключения модуля необходимо создать файл настроек, чтобы модуль знал как соединиться с базой данных. Пример конфигурационного файла можно найти в `modules/database/config/database.php`. - -Структура группы настроек базы данных ("instance") выглядит следующим образом: - - 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, - ), - -[!!] В одном конфигурационном файле можно определить несколько таких групп. - -Очень важно понимать каждый параметр конфигурации. - -INSTANCE_NAME -: Соединения могут быть названы как Вы захотите, но одно из них обязательно должно называться "default" (группа по умолчанию). - -DATABASE_TYPE -: Один из установленных драйверов баз данных. Kohana поставляется с драйверами "mysql" и "pdo". - -CONNECTION_ARRAY -: Специфические настройки драйвера для соединения с БД. (Настройки драйвера описаны [ниже](#connection_settings).) - -TABLE_PREFIX -: Префикс, который будет добавлен к названиям таблиц классом [query builder](#query_building). - -QUERY_PROFILING -: Включает [профилирование](debugging.profiling) запросов к БД. - -### Пример - -Ниже описаны два соединения с MySQL, одно локальное, а другое удаленное. - - 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, - ), - ); - -### Настройки соединения {#connection_settings} - -Каждый драйвер БД имеет свои настройки соединения. - -#### MySQL - -БД MySQL поддерживает следующие параметры массива `connection`: - -Тип | Параметр | Описание | Значение по умолчанию -----------|------------|-----------------------------| ------------------------- -`string` | hostname | Имя сервера или IP-адрес | `localhost` -`integer` | port | Номер порта | `NULL` -`string` | socket | сокет UNIX | `NULL` -`string` | username | Имя пользователя | `NULL` -`string` | password | Пароль | `NULL` -`boolean` | persistent | Постоянное соединение | `FALSE` -`string` | database | Имя базы данных (схемы) | `kohana` - -#### PDO - -База данных PDO database принимает следующие опции массива `connection`: - -Тип | Параметр | Описание | Значение по умолчанию -----------|------------|-----------------------------| ------------------------- -`string` | dsn | Идентификатор источника PDO | `localhost` -`string` | username | Имя пользователя | `NULL` -`string` | password | Пароль | `NULL` -`boolean` | persistent | Постоянное соединение | `FALSE` - -!! Если Вы используете PDO и не уверены, что прописывать в параметре `dsn`, ознакомьтесь с [PDO::__construct](http://php.net/pdo.construct). - -## Соединения и сущности {#connections} - -Каждая группа настроек связана с экземпляром базы данных ("сущность"). Каждая сущность может быть получена через вызов [Database::instance]: - - $default = Database::instance(); - $remote = Database::instance('remote'); - -Чтобы порвать соединение с базой данных, просто уничтожьте объект: - - unset($default, Database::$instances['default']); - -Если Вы хотите разорвать соединения со всеми сущностями за раз: - - Database::$instances = array(); - -## Создаем запросы {#making_queries} - -Существует два способа создать запросы. Простейший путь - использование [Database_Query] для создания запросов, через [DB::query]. Эти запросы называются "подготовленные выражения" и позволяют устанавливать параметры, которые автоматически экранируются. Второй путь - построение через специальные методы. Это возможно с помощью объекта [query builder](#query_building). - -[!!] Все запросы выполняются методом `execute`, который принимает объект [Database] или имя сущности. Смотри [Database_Query::execute]. - -### Подготовленные выражения - -Подготовленные выражения позволяют писать SQL-запросы вручную, в то же время значения будут автоматически экранированы, чтобы избежать [SQL-инъекций](http://wikipedia.org/wiki/SQL_Injection). Создать запрос просто: - - $query = DB::query(Database::SELECT, 'SELECT * FROM users WHERE username = :user'); - -Фабричный метод [DB::query] создает новый класс [Database_Query] и возвращает его, поддерживая цепочки вызовов. Запрос содержит параметр `:user`, которому будет назначено значение: - - $query->param(':user', 'john'); - -[!!] Имя параметра может быть любой строкой, в дальнейшем оно будет заменено функцией [strtr](http://php.net/strtr). Рекомендуется **не** использовать знак доллара в составе имени параметра во избежание путаницы. - -Если Вы хотите увидеть SQL, предназначенный для выполнения, просто преобразуйте объект в строку: - - echo Kohana::debug((string) $query); - // выведет: - // SELECT * FROM users WHERE username = 'john' - -Также Вы можете изменить параметр `:user`, снова вызвав [Database_Query::param]: - - $query->param(':user', $_GET['search']); - -[!!] Для задания нескольких параметров за раз используйте [Database_Query::parameters]. - -После установки всех параметров можно выполнить запрос: - - $query->execute(); - -Также допустимо привязать параметр к переменной, используя [ссылки на переменные]((http://php.net/language.references.whatdo)). Это может стать очень полезным при многократном выполнении схожих запросов: - - $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(); - } - -В данном примере переменные `$username` и `$password` меняются в каждой итерации цикла `foreach`. Когда переменные меняются, также изменяют значение и параметры запроса `:user` и `:pass`. Правильное и уместное использование привязки параметров может сделать код более компактным. - -### Конструктор запросов {#query_building} - -Динамическое создание запросов с использованием объектов и методов позволяет писать запросы очень быстро и предсказуемо. Построитель запросов также заключает в кавычки идентификаторы (имена таблиц и полей), также как и экранирует значения. - -[!!] На данный момент невозможно комбинировать построитель запросов с подготовленными выражениями. - -#### Выборка (SELECT) - -Каждый тип запросов представлен отдельным классом со своими методами. К примеру, чтобы создать запрос типа SELECT, используем [DB::select]: - - $query = DB::select()->from('users')->where('username', '=', 'john'); - -По умолчанию, [DB::select] будет запрашивать все поля (`SELECT * ...`), но можно указать, какие столбцы извлекать: - - $query = DB::select('username', 'password')->from('users')->where('username', '=', 'john'); - -А теперь посмотрим, к чему привела эта цепочка вызовов. Сперва мы создаем новый объект выборки методом [DB::select]. Далее, устанавливаем таблицу(ы) с помощью метода `from`. И напоследок, ищем конкретные записи через метод `where`. Можно посмотреть генерируемый код SQL просто преобразовывая объект к строке: - - echo Kohana::debug((string) $query); - // Покажет: - // SELECT `username`, `password` FROM `users` WHERE `username` = 'john' - -Обратили внимание, что имена полей и таблиц автоматически экранированы, также как и значения? Это одно из ключевых преимуществ использования построителя запросов. - -Также допустимо создавать псевдонимы `AS` для выборки: - - $query = DB::select(array('username', 'u'), array('password', 'p'))->from('users'); - -Сгенерируется следующий SQL-запрос: - - SELECT `username` AS `u`, `password` AS `p` FROM `users` - -#### Вставка (INSERT) - -Чтобы создать записи в базе данных, используйте [DB::insert], создающий запросы INSERT: - - $query = DB::insert('users', array('username', 'password'))->values(array('fred', 'p@5sW0Rd')); - -Запрос сформирует код: - - INSERT INTO `users` (`username`, `password`) VALUES ('fred', 'p@5sW0Rd') - -#### Обновление (UPDATE) - -Для редактирования существующей записи предназначен метод [DB::update], он возвращает запрос UPDATE: - - $query = DB::update('users')->set(array('username' => 'jane'))->where('username', '=', 'john'); - -В результате получим запрос: - - UPDATE `users` SET `username` = 'jane' WHERE `username` = 'john' - -#### Удаление (DELETE) - -Для удаления записи используется [DB::delete], он создает запрос DELETE: - - $query = DB::delete('users')->where('username', 'IN', array('john', 'jane')); - -Получим следующий запрос: - - DELETE FROM `users` WHERE `username` IN ('john', 'jane') - -#### Функции работы с базами данных {#database_functions} - -Иногда Вы можете столкнуться с ситуацией, когда надо вызвать `COUNT` или другую функцию СУБД внутри запроса. Построитель запросов позволяет использовать эти функции двумя способами. Первый - применение кавычек внутри псевдонимов: - - $query = DB::select(array('COUNT("username")', 'total_users'))->from('users'); - -Это выглядит почти также, как и стандартные псевдонимы, но имя поля обрамлено двойными кавычками. Каждый раз, когда значение в двойных кавычках обнаруживается внутри имени столбца, **только** часть внутри этих кавычек будет экранирована. Сгенерируется код SQL: - - SELECT COUNT(`username`) AS `total_users` FROM `users` - -#### Сложные выражения - -"Закавыченные" псевдонимы могут решить многие проблемы, но время от времени может понадобиться сложное выражение. В таких случаях надо использовать выражения, создаваемые методом [DB::expr]. Выражение используется для прямого вывода, экранирование не происходит. - diff --git a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.git.md b/includes/kohana/modules/userguide/guide/ru-ru/tutorials.git.md deleted file mode 100644 index 4d158f10..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.git.md +++ /dev/null @@ -1,149 +0,0 @@ -# Работа с Git - -Kohana применяет [git](http://git-scm.com/) для контроля версий и [github](http://github.com/kohana) для совместной разработки. Данная статья покажет Вам как использовать git и github для создания простейшего приложения. - -## Установка и настройка Git на Вашей машине - -### Установка Git - -- для OSX: [Git-OSX](http://code.google.com/p/git-osx-installer/) -- для Windows: [Msygit](http://code.google.com/p/msysgit/) -- Или загрузите git с [официального сайта](http://git-scm.com/) и установите его самостоятельно (подробности установки смотрите на сайт Git) - -### Основные глобальные настройки - - git config --global user.name "Your Name" - git config --global user.email "youremail@website.com" - -### Дополнительные, но предпочтимые настройки - -Для лучшей визуализации команд и репозиторий в командной строке, используйте следующее: - - git config --global color.diff auto - git config --global color.status auto - git config --global color.branch auto - -### Настройка автозавершения - -[!!] Следующие строки применимы только для OSX машин - -Эти строки сделают всю грязную работу за вас и после этого Вы сможете спокойно работать с git-окружением, используя автозавершение команд: - - 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 - -### Всегда используйте LF в окончаниях строк - -Это соглашение, которое было принято Kohana сообществом. Выставьте эту настройку во имя Вашего Господа, особенно если хотите участвовать в kohana коммьюнити! - - git config --global core.autocrlf input - git config --global core.savecrlf true - -[!!] Более подробную информацию об окончаниях строк читайте на [GitHub'е](http://help.github.com/dealing-with-lineendings/) - -### Информация для размышления - -- [Git скринкасты](http://www.gitcasts.com/) -- [Git справочник](http://gitref.org/) -- [Pro Git book](http://progit.org/book/) - -## Основная структура - -[!!] Предполагается, что Ваш web-сервер уже настроен, и Вы будете использовать адрес для нового приложения. - -Откройте консоль, перейдите в пустую директорию `gitorial` и выполните команду `git init`. Она создаст заготовку под новый git-репозиторий. - -Далее, мы создадим подпроект ([submodule](http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html)) для директории `system`. Откройте и скопируйте значение Clone URL: - -![Github Clone URL](http://img.skitch.com/20091019-rud5mmqbf776jwua6hx9nm1n.png) - -Используйте скопированный URL для создания подпроекта `system`: - - git submodule add git://github.com/kohana/core.git system - -[!!] Будет создана связь с текущей разрабатываемой версией следующего стабильного релиза. Эта версия должна практически всегда быть безопасна для использования, иметь тот же API, что в текущем стабильном релизе с исправленными ошибками. - -Теперь добавьте остальные необходимые подпроекты. Например, если нужен модуль [Database](http://github.com/kohana/database): - - git submodule add git://github.com/kohana/database.git modules/database - -После добавления модули должны быть проиниализированы: - - git submodule init - -Теперь мы должны зафиксировать текущее состояние: - - git commit -m 'Added initial submodules' - -Следующий шаг - создание структуры папок для приложения. Вот необходимый минимум: - - mkdir -p application/classes/{controller,model} - mkdir -p application/{config,views} - mkdir -m 0777 -p application/{cache,logs} - -Если запустить команду `find application`, Вы должны увидеть такой список: - - application - application/cache - application/config - application/classes - application/classes/controller - application/classes/model - application/logs - application/views - -Мы не хотим, чтобы git обрабатывал логи или файлы кэша, поэтому добавим файл `.gitignore` в соответствуюшие директории logs и cache. Теперь все нескрытые (non-hidden) файлы будут проигнорированы git'ом: - - echo '[^.]*' > application/{logs,cache}/.gitignore - -[!!] Git пропускает пустые папки, так что добавляя файл `.gitignore`, мы дополнительно заставляем git учитывать данную директорию, но не файлы внутри нее. - -Теперь загружаем файлы `index.php` и `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 - -Фиксируем эти изменения: - - git add application - git commit -m 'Added initial directory structure' - -Это все необходимые изменения. Теперь у Вас имеется приложение, использующее Git для контроля версий. - -## Обновление подмодулей - -Скорее всего, на определенном этапе Вы захотите обновить свои подпроекты. Чтобы обновить все модули до последних версий `HEAD`, введите: - - git submodule foreach 'git checkout master && git pull origin master' - -Для синхронизации подпроекта `system` выполните: - - cd system - git checkout master - git pull - cd .. - git add system - git commit -m 'Updated system directory' - -Обновление отдельного модуля до определенной ревизии: - - cd modules/database - git fetch - git checkout fbfdea919028b951c23c3d99d2bc1f5bbeda0c0b - cd ../.. - git add database - git commit -m 'Updated database module' - -Заметьте, что можно так же загрузить коммит по официальной метке релиза. Например: - - git checkout 3.0.7 - -Для того, чтобы увидеть все метки, просто запустите `git tag` без дополнительных аргументов. - -Вот и всё! \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.helloworld.md b/includes/kohana/modules/userguide/guide/ru-ru/tutorials.helloworld.md deleted file mode 100644 index 48d98119..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.helloworld.md +++ /dev/null @@ -1,105 +0,0 @@ -# Hello, World - -Каждый фреймворк располагает примером написания приложения hello world, так что не будем нарушать традицию! - -Мы начнем с создания простейшего hello world, а затем расширим его согласно принципам MVC. - -## Основа - -Сперва надо создать контроллер, который Kohana будет использовать для обработки запроса - -Создайте файл `application/classes/controller/hello.php` в директории application и вставьте туда такой текст: - - template->message = 'hello, world!'; - } - } - -`extends Controller_Template` -: Теперь мы расширяем шаблонный контроллер (template controller), что делает работу контроллера с представлениями более удобной. - -`public $template = 'site';` -: Шаблонный контроллер должен знать, какое представление использовать. Он автоматически загрузит указанное представление в данную переменную в виде объекта. - -`$this->template->message = 'hello, world!';` -: `$this->template` является ссылкой на наш шаблон. Мы присваиваем переменной "message" значение "hello, world!", и добавляем ее в шаблон template. - -А теперь попробуем выполнить наш код... - -
        {{userguide/examples/hello_world_error}}
        - -По каким-то причинам kohana генерирует ошибку и не хочет показать наше восхитительное сообщение. - -Если мы посмотрим на сообщение с ошибкой, то увидим, что библиотека View не смогла найти наш главный шаблон, скорее всего потому что мы его еще не создали - *черт*! - -Давайте добавим файл представления `application/views/site.php` для нашего сообщения: - - - - We've got a message for you! - - - -

        -

        We just wanted to say it! :)

        - - - -Если обновить страницу, то мы увидим увидим результаты наших усилий: - -![hello, world! Мы просто хотели это произнести!](img/hello_world_2.png "hello, world! Мы просто хотели это произнести!") - -## Этап 3 - Итого! - -В данной статье Вы изучили, как создать контроллер и использовать шаблоны для отделения логики от представления. - -Очевидно, что это было всего-навсего упрощенное вступление, и оно не отражает даже малой части всех возможностей, доступных при разработке приложений с помощью kohana. diff --git a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.orm.md b/includes/kohana/modules/userguide/guide/ru-ru/tutorials.orm.md deleted file mode 100644 index 14d2096e..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.orm.md +++ /dev/null @@ -1,312 +0,0 @@ -# ORM {#top} - -Kohana 3.0 включает мощный модуль ORM, который использует паттерн Active Record и автоопределение информации о списке полей БД модели. - -Модуль ORM включен в дистрибутив Kohana 3.0, но нуждается в подключении перед его использованием. В файле `application/bootstrap.php` отредактируйте вызов [Kohana::modules] и добавьте модуль ORM: - - Kohana::modules(array( - ... - 'orm' => MODPATH.'orm', - ... - )); - -## Настройка {#configuration} - -ORM требует небольшую настройку перед использованием. Наследуйте Вашу модуль от ORM: - - class Model_User extends ORM - { - ... - } - -В примере выше, модель будет искать таблицу `users` в БД по умолчанию. - -### Свойства модели, отвечающие за конфигурацию - -Следующие свойства используются для настройки каждой модели: - -Тип | Название | Описание | Значение по умолчанию -----------|---------------------|-------------------------------------|--------------------------------- -`string` | _table_name | Используемая таблица БД | `имя модели в единственном числе` -`string` | _db | Название БД | `default` -`string` | _primary_key | Поле - первичный ключ | `id` -`string` | _primary_val | Титульное поле | `name` -`bool` | _table_names_plural | Имя таблицы во множественном числе | `TRUE` -`array` | _sorting | Сортировка (столбец => направление) | `primary key => ASC` -`string` | _foreign_key_suffix | Суффикс внешнего ключа | `_id` - -## Использование ORM - -### Загрузка записи - -Для создания экземпляра модели используйте метод [ORM::factory] или конструктор [ORM::__construct]: - - $user = ORM::factory('user'); - // или - $user = new Model_User(); - -Конструктор и фабричный метод также поддерживают значение первичного ключа для загрузки конкретной записи: - - // Загружаем пользователя с ID 5 - $user = ORM::factory('user', 5); - - // Проверяем успешность загрузки объекта пользователя - if ($user->loaded()) { ... } - -Опционально, Вы можете передать массив с парами ключ => значение для загрузки данных объекта по совпадающим критериям, указанным в массиве: - - // Загрузка пользователя с email joe@example.com - $user = ORM::factory('user', array('email' => 'joe@example.com')); - -### Поиск записи - -ORM поддерживает большинство методов класса [Database] для полноценного поиска данных модели. В свойстве `_db_methods` перечислен полный список поддерживаемых методов. Записи извлекаются после вызовов [ORM::find] или [ORM::find_all]. - - // Извлекаем первого активного пользователя по имени Bob - $user = ORM::factory('user') - ->where('active', '=', TRUE) - ->where('name', '=', 'Bob') - ->find(); - - // Ищем всех активных пользователей по имени Bob - $users = ORM::factory('user') - ... - ->find_all(); - -Когда Вы запрашиваете список моделей через [ORM::find_all], перебирать его можно аналогично обычным выборкам из БД: - - foreach ($users as $user) - { - ... - } - -Мощным инструментом ORM является метод [ORM::as_array], который возвращает полученные записи в виде массива. При использовании совместно с [ORM::find_all], будет возвращён массив всех записей. Хороший пример использование этого метода - когда необходимо передать значения для выпадающего списка: - - // Отображается выпадающий список пользователей - // (используется id в качестве значения select option) - form::select('user', ORM::factory('user')->find_all()->as_array('id', 'username') ... - -### Подсчёт записей - -Для получения количества записей для данного запроса, используйте [ORM::count_all]. - - // Число активных пользователей - $count = ORM::factory('user')->where('active', '=', TRUE)->count_all(); - -Если требуется подсчитать общее количество пользователей для данного запроса при лимитировании количества возвращаемых записей, используйте метод [ORM::reset] с параметром `FALSE` перед использованием `count_all`: - - $user = ORM::factory('user'); - - // Общее число пользователей (reset FALSE предотвращает объект от очистки перез запросом) - $count = $user->where('active', '=', TRUE)->reset(FALSE)->count_all(); - - // Получаем только первые 10 результатов - $users = $user->limit(10)->find_all(); - -### Доступ к свойствам модели - -Все свойства модели доступны через "магические" методы `__get` и `__set`. - - $user = ORM::factory('user', 5); - - // Выводит имя пользователя - echo $user->name; - - // Изменяет имя пользователя - $user->name = 'Bob'; - -Для хранения данных/свойств, которые отсутствуют в таблице модели, надо использовать атрибут `_ignored_columns`. - - class Model_User extends ORM - { - ... - protected $_ignored_columns = array('field1', 'field2', ...) - ... - } - -Множественные пары ключ => значение могут быть заданы с использованием метода [ORM::values]: - - $user->values(array('username' => 'Joe', 'password' => 'bob')); - -### Создаем и сохраняем записи - -Метод [ORM::save] используется как для создания новых записей, так и для обновления существующих. - - // Создаем запись - $user = ORM::factory('user'); - $user->name = 'New user'; - $user->save(); - - // Редактируем запись - $user = ORM::factory('user', 5); - $user->name = 'User 2'; - $user->save(); - - // Проверяем, сохранена ли запись - if ($user->saved()) { ... } - -Вы можете обновить множество записей с помощью метода [ORM::save_all]: - - $user = ORM::factory('user'); - $user->name = 'Bob'; - - // Все активные пользователи получат имя 'Bob' - $user->where('active', '=', TRUE)->save_all(); - -#### Использование `Updated` и `Created` для столбцов БД - -Свойства `_updated_column` и `_created_column` позволяют производить автоматическое обновление модели при её обновлении и сохранении. Это используется не по-умолчанию. Чтобы использовать эти свойства, следует их указать: - - // date_created является столбцом таблицы, в котором хранится дата создания. - // Для сохранения метки времени, используем TRUE - protected $_created_column = array('date_created' => TRUE); - - // date_modified является столбцом таблицы, в котором хранится дата изменения. - // В этом случае используется строка, определяющая формат для функции date() - protected $_updated_column = array('date_modified' => 'm/d/Y'); - -### Удаление записей - -Записи удаляются методами [ORM::delete] и [ORM::delete_all]. Эти методы работают аналогично описанному выше сохранению, за исключением того, что [ORM::delete] принимает необязательный параметр `id` для удаляемой записи. - -### Отношения - -ORM предоставляет мощную поддержку отношений таблиц. Прочитать про отношения можно в [справочнике по Ruby](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html) - -#### Belongs-To и Has-Many - -Допустим, мы работаем со школой, которая имеет много учеников (has many). Каждый студент приписан к одной школе (принадлежит - belongs to). Необходимо определить отношения моделей следующим образом: - - // В модели school - protected $_has_many = array('students' => array()); - - // В модели student - protected $_belongs_to = array('school' => array()); - -Получаем информацию о школе студента: - - $school = $student->school; - -Ищем всех студентов школы: - - // Учтите, что после students следует вызвать метод find_all - $students = $school->students->find_all(); - - // Чтобы сузить результаты поиска: - $students = $school->students->where('active', '=', TRUE)->find_all(); - -По-умолчанию, ORM будет искать поле `school_id` в таблице модели student. Это можно изменить, используя аттрибут `foreign_key`: - - protected $_belongs_to = array('school' => array('foreign_key' => 'schoolID')); - -Внешний ключ будет перегружен как в модели student, так и в school. - -#### Has-One - -Has-One - это частный случай Has-Many, единственным отличаем которого является то, что в отношении участвует только одна запись. В дополнении к приведённому выше примеру школы, каждая школа будет иметь (has-one) только одного директора, который принадлежит (belongs-to) школе. - - // Inside the school model - protected $_has_one = array('principal' => array()); - -Как и для Belongs-To, Вам не нужно использовать метод `find` для получение объекта, ссылающегося на Has-One объект - это будет сделано автоматически. - -#### Has-Many "через" (through) - -Отношение Has-Many "through" (так же известное как Has-And-Belongs-To-Many) оспользуется в случае если объект связан с несколькими объектами другого типа и наоборот. Например, студент записан на многие занятия и на занятие ходит много студентов. В этом случаеи используется `промежуточная` таблица. Используем для нашего примера промежуточную таблицу и модель - журнал (`enrollment`). - - // В модели student - protected $_has_many = array('classes' => array('through' => 'enrollment')); - - // В модели class - protected $_has_many = array('students' => array('through' => 'enrollment')); - -Таблица enrollment должна содержать 2 внешних ключа: для занятий `class_id` и для студентов `student_id`. Наименование внешних и дальних ключей (`foreign_key` и `far_key`) могут быть переопределены при определении отношений. Например: - - // В модели student (внешний ключ ссылается на модель student, - // в то время, как дальний ключ - на class) - protected $_has_many = array( - 'classes' => array( - 'through' => 'enrollment', - 'foreign_key' => 'studentID', - 'far_key' => 'classID' - )); - - // В модели class - protected $_has_many = array( - 'students' => array( - 'through' => 'enrollment', - 'foreign_key' => 'classID', - 'far_key' => 'studentID' - )); - -Определяем в модели enrollment: - - // Журнал принадлежит как студенту, так и занятию - protected $_belongs_to = array('student' => array(), 'class' => array()); - -Для доступа к связанным объектам: - - // Для получение занятий студента - $student->classes->find_all(); - - // Для получения студентов, записанных на занятие - $class->students->find_all(); - -### Валидация - -ORM тесно взимодействует с [Validate] библиотекой, позволяя использовать возможности этого класса в следующих свойствах: - -* _rules -* _callbacks -* _filters -* _labels - -#### `_rules` - - protected $_rules = array - ( - 'username' => array('not_empty' => array()), - 'email' => array('not_empty' => array(), 'email' => array()), - ); - -`username` будет проверяться на то, что значение этого поля не является пустым. `email` поле будет проверено на соответствие значения валидному email адресу. Ввиду возможности передачи дополнительных опций для правил, значения правил задаются как пустые массивы. - -#### `_callbacks` - - protected $_callbacks = array - ( - 'username' => array('username_unique'), - ); - -Значение поля `username` будет передано методы `username_unique`. Если метод не существует в текущей модели, то будет вызвана глобальная функция. Вот пример описания этого метода: - - public function username_unique(Validate $data, $field) - { - // Логика, проверяющая уникальность имени пользователя - ... - } - -#### `_filters` - - protected $_filters = array - ( - TRUE => array('trim' => array()), - 'username' => array('stripslashes' => array()), - ); - -`TRUE` Указывает на то, что фильтр `trim` будет применён ко всем полям. Значение поля `username` будет отфильтровано с помощью функции `stripslashes` перед процессом валидации. Ввиду возможности передачи дополнительных опций для фильтров, значения фильтра задаются как пустые массивы. - -#### Проверка объекта - -Для проверки объекта, используйте [ORM::check]: - - // Задание значений объекта и дальнейшая их валидация - if ($user->values($_POST)->check()) - { - $user->save(); - } - -Для доступа к объекту валидации данной модели, можно использовать метод `validate()`: - - // Ручное добавление дополнительного фильтра - $user->validate()->filter('username', 'trim'); \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.removeindex.md b/includes/kohana/modules/userguide/guide/ru-ru/tutorials.removeindex.md deleted file mode 100644 index 96789c90..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.removeindex.md +++ /dev/null @@ -1,88 +0,0 @@ -# Удаление из URL `index.php` - -Для чистоты URL, Вам наверняка захочется иметь доступ до разделов Вашего приложения без `/index.php/` в адресной строке. Для этого необходимо выполнить 2 действия. - -1. Откорректировать bootstrap файл -2. Установить возможности rewriting'а на Вашем веб-сервере - -# Конфигурирование Bootstrap - -Первое, что следует сделать - это изменить значение `index_file` в [Kohana::init]: - - Kohana::init(array( - 'base_url' => '/myapp/', - 'index_file' => FALSE, - )); - -Теперь все ссылки, генерируемые методами [URL::site], [URL::base], и [HTML::anchor] не будут использовать "index.php" при построении URL. Все генерируемые ссылки будут начинаться с `/myapp/` вместо `/myapp/index.php/`. - -# URL Rewriting - -В зависимости от Вашего сервера, rewriting активируется по разному. - -## Apache - -Переименуйте `example.htaccess` в `.htaccess` и измените следующую строчку кода: - - RewriteBase /kohana/ - -RewriteBase должен совпадать со значением, указанным у Вас в `base_url` свойстве [Kohana::init]: - - RewriteBase /myapp/ - -В большинстве случаев - это всё, что необходимо сделать. - -### Ошибка! - -Если вдруг Вы стали получать ошибки в виде "Internal Server Error" или "No input file specified", попытайтесь изменить `.htaccess` следующее: - - RewriteRule ^(?:application|modules|system)\b - [F,L] - -Вместо параметра `\b` попробуйте использовать слеш: - - RewriteRule ^(application|modules|system)/ - [F,L] - -Если это не поможет, попробуйте изменить следующее: - - RewriteRule .* index.php/$0 [PT] - -На что-то более простое: - - RewriteRule .* index.php [PT] - -### Всё равно ошибка! - -Если всё ещё получаете ошибки, убедитесь, что Ваш хостинг предоставляет поддержку Apache `mod_rewrite`. Если у Вас есть доступ до изменения настроек Apache, то добавьте следующие строки в конфигурационный файл (зачастую это `httpd.conf`): - - - Order allow,deny - Allow from all - AllowOverride All - - -## NGINX - -Тяжело дать пример конфигурации nginx сервера, но можно использовать следующий пример для server блока: - - location / { - index index.php index.html index.htm; - try_files $uri $uri/ index.php$uri?$args; - } - - location ~ ^(.+\.php)(.*)$ { - fastcgi_split_path_info ^(.+\.php)(.*)$; - fastcgi_param SCRIPT_NAME $fastcgi_script_name; - fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - - include fastcgi.conf; - - fastcgi_pass 127.0.0.1:9000; - fastcgi_index index.php; - } - -Заметьте, что в данном примере используются [try_files](http://wiki.nginx.org/NginxHttpCoreModule#try_files) и [fastcgi_split_path_info](http://wiki.nginx.org/NginxHttpFcgiModule#fastcgi_split_path_info) свойства. - -[!!] Этот пример подразумевает, что Вы запускаете PHP как FastCGI сервер на порту 9000 и используете nginx v0.7.31 и выше. - -Если с этой конфигурацией Вы получаете ошибки, установите для nginx уровень логов в debug и проверьте access и error логи на предмет ошибок. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.urls.md b/includes/kohana/modules/userguide/guide/ru-ru/tutorials.urls.md deleted file mode 100644 index d90e3371..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/tutorials.urls.md +++ /dev/null @@ -1,160 +0,0 @@ -# Маршруты, URL, и Ссылки - -В данном разделе будет раскрыты фундаментальные основы маршрутизации запросов Kohana, формирования URL и ссылок. - -## маршрутизация - -Как уже говорилось в секции [порядок выполнения](about.flow), запрос обрабатывается классом [Request], который ищет подходящий маршрут ([Route]) и загружает соответствующий контроллер для выполнения. Таким образом, система обеспечивает большую гибкость, а также интуитивно понятное поведение по умолчанию. - -Если Вы заглянете в `APPPATH/bootstrap.php`, то увидите следующий участок кода, который будет выполнен непосредственно до передачи запроса в вызов [Request::instance]: - - Route::set('default', '((/(/)))') - ->defaults(array( - 'controller' => 'welcome', - 'action' => 'index', - )); - -Так устанавливается машрут по умолчанию (`default`) с адресом по шаблону `((/(/)))`. Символы, заключенные в угловые скобки `<>`, являются *ключами*, а круглыми скобками - *необязательные* части адреса. В данном случае весь адрес является опциональным, так что и пустой адрес будет отработан, а дефолтные контроллер и экшен приведут к тому, что для обработки запроса загрузится класс `Controller_Welcome` и выполнится метод `action_index`. - -Заметьте, что в маршрутах Kohana вне `()<>` допустимы любые символы, а `/` не имеет специального значения. В маршруте по умолчанию `/` используется как разделитель, но пока регулярное выражение имеет смысл, нет никаких ограничений на форматирование Ваших маршрутов. - -### Директории - -Вы можете захотеть разместить некоторые из контроллеров в поддиректориях. Типовое решение для админской части сайта: - - Route::set('admin', 'admin(/(/(/)))') - ->defaults(array( - 'directory' => 'admin', - 'controller' => 'home', - 'action' => 'index', - )); - -Этот маршрут определяет, что адрес должен начинаться с `admin`, в результате значение директории (`admin`) будет взято из дефолтовых значений. Запрос к `admin/users/create` загрузит класс `Controller_Admin_Users` и вызовет метод `action_create`. - -### Шаблоны - -Система маршрутизации Kohana при поиске совпадений использует perl-совместимые регулярные выражения. По умолчанию ключи (окруженные `<>`) определяются шаблоном `[a-zA-Z0-9_]++`, но Вы можете указать свой шаблон для каждого используемого ключа. Для этого заполняется массив ключей и шаблонов, передающийся как дополнительный аргумент метода [Route::set]. Чтобы усложнить предыдущий пример, давайте представим, что у Вас есть админский раздел и секция подразделений (affiliates). Вы можете разделить их по разным маршрутам, а можете объявить как-то так: - - Route::set('sections', '(/(/(/)))', - array( - 'directory' => '(admin|affiliate)' - )) - ->defaults(array( - 'controller' => 'home', - 'action' => 'index', - )); - -Таким образом мы выделили два раздела сайта, 'admin' и 'affiliate', которые позволят разместить контроллеры по поддиректориям, в остальных случаях будет работать маршрут по умолчанию. - -### Еще примеры маршрутов - -Существует бесчисленное количество возможностей маршрутизации. Вот еще некоторые из них: - - /* - * Короткие адреса для авторизации - */ - Route::set('auth', '', - array( - 'action' => '(login|logout)' - )) - ->defaults(array( - 'controller' => 'auth' - )); - - /* - * Разноформатные ленты новостей - * 452346/comments.rss - * 5373.json - */ - Route::set('feeds', '(/).', - array( - 'user_id' => '\d+', - 'format' => '(rss|atom|json)', - )) - ->defaults(array( - 'controller' => 'feeds', - 'action' => 'status', - )); - - /* - * Статичные страницы - */ - Route::set('static', '.html', - array( - 'path' => '[a-zA-Z0-9_/]+', - )) - ->defaults(array( - 'controller' => 'static', - 'action' => 'index', - )); - - /* - * Не нравятся слэши? - * EditGallery:bahamas - * Watch:wakeboarding - */ - Route::set('gallery', '():', - array( - 'controller' => '[A-Z][a-z]++', - 'action' => '[A-Z][a-z]++', - )) - ->defaults(array( - 'controller' => 'Slideshow', - )); - - /* - * Быстрый поиск - */ - Route::set('search', ':', array('query' => '.*')) - ->defaults(array( - 'controller' => 'search', - 'action' => 'index', - )); - -Маршруты анализируются в том же порядке, в котором были добавлены, так что имейте в виду, что если Вы установили маршрут после загрузки модулей, в одном из загруженных модулей может быть определен маршрут, конфликтующий с Вашим. Поэтому дефолтный маршрут устанавливается последним, так что все пользовательские маршруты будут проверены до него. - -### Параметры запроса - -Директория, контроллер и экшен могут быть доступны через экземпляр класса [Request] одним из двух способов: - - $this->request->action; - Request::instance()->action; - -Все прочие ключи маршрута могут быть получены из контроллера так: - - $this->request->param('key_name'); - -Метод [Request::param] принимает дополнительный параметр, определяющий возвращаемое по умолчанию значение, если оно не было передано в адресе. Если метод вызван без параметром, все ключи будут возвращены в ассоциативном массиве. - -### Соглашения - -Установлено соглашение размещать Ваши маршруты в файле `MODPATH//init.php` модуля, если маршрут относится к данному модулю. Или просто вставить его в файл `APPPATH/bootstrap.php` до дефолтного маршрута, если он относится к приложению в целом. Конечно, они могут быть подгружены из внешнего файла или сгенерированы динамически. - -## Адреса URL - -Помимо мощных возможностей Kohana, есть методы для генерирования URL для Ваших маршрутов. Вы всегда можете определить адрес как строку с помощью [URL::site] для создания URL, примерно так: - - URL::site('admin/edit/user/'.$user_id); - -Однако Kohana дает возможность генерировать URL с учетом определенного маршрута. Это очень полезно, если Ваша маршрутизация может поменяться, поскольку это избавит от необходимости заново редактировать весь код, меняя прописанный там адрес. Вот пример динамической генерации, который использует приведенный ранее маршрут `feeds`: - - Route::get('feeds')->uri(array( - 'user_id' => $user_id, - 'action' => 'comments', - 'format' => 'rss' - )); - -Предположим, Вы решите позже сделать определение маршрута более говорящим, заменив его на `feeds/(/).`. Если Вы будете писать код с генерацией адресов как в примере выше, то не придется менять ни одной строчки кода! Если в адресе есть заключенный в скобки (опциональный) ключ, для которого не передано значение при генерации, и не приведено значение по умолчанию, то данная часть будет исключена из адреса. Примером будет ключ `(/)` дефолтного маршрута; он не будет присутствовать в сгенерированном URL если id не указан. - -Еще Вы можете часто использовать метод [Request::uri], который по сути делает то же самое, что вышеуказанный метод, только он подставляет текущие значения маршрута, директории, контроллера и экшена. Если текщий маршрут дефолтный, и адрес был `users/list`, для формирования адреса вида `users/view/$id` можно сделать так: - - $this->request->uri(array('action' => 'view', 'id' => $user_id)); - -Из шаблона предпочтительнее вызывать: - - Request::instance()->uri(array('action' => 'view', 'id' => $user_id)); - -## Ссылки - -[!!] Заглушка - diff --git a/includes/kohana/modules/userguide/guide/ru-ru/using.autoloading.md b/includes/kohana/modules/userguide/guide/ru-ru/using.autoloading.md deleted file mode 100644 index 778658ef..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/using.autoloading.md +++ /dev/null @@ -1,96 +0,0 @@ -# Загрузка классов - -Kohana использует все преимущества [автозагрузки](http://php.net/manual/language.oop5.autoload.php) в PHP. -Это позволяет не использовать вызовы [include](http://php.net/include) или [require](http://php.net/require) перед использованием класса. К примеру, когда Вы хотите использовать метод [Cookie::set], Вы всего лишь вызываете: - - Cookie::set('mycookie', 'any string value'); - -А для получения объекта [Encrypt] просто используйте [Encrypt::instance]: - - $encrypt = Encrypt::instance(); - -Классы загружаются с помощью метода [Kohana::auto_load], который осуществляет простое преобразование из имени класса в имя файла: - -1. Классы располагаются в директории `classes/` [файловой системы](about.filesystem) -2. Все знаки подчеркивания заменяются слэшами -2. Имена файлов должны быть в нижнем регистре - -Когда вызывается класс, который еще не был загружен (например `Session_Cookie`), Kohana будет искать файл под именем `classes/session/cookie.php` в файловой системе, с помощью [Kohana::find_file]. - -## Собственные загрузчики - -Системный загрузчик добавляется в файле `application/bootstrap.php` через вызов [spl_autoload_register](http://php.net/spl_autoload_register): - - spl_autoload_register(array('Kohana', 'auto_load')); - -Теперь [Kohana::auto_load] будет пытаться загрузить любой несуществующий класс при его первом использовании. - -# Прозрачное расширение классов {#class-extension} - -[Каскадная файловая система](about.filesystem) поддерживает прозрачное расширение классов. Например, класс [Cookie] определен в `SYSPATH/classes/cookie.php` так: - - class Cookie extends Kohana_Cookie {} - -Системные классы Kohana, как и многие модули, используют такое определение, так что практически все классы могут быть расширены. Это делается прозрачно для системы, создайте свой класс в `APPPATH/classes/cookie.php` для добавления собственных методов. - -[!!] **Никогда** не изменяйте файлы дистрибутива Kohana. Всегда вносите изменения в классы, используя расширения, так Вы избавитесь от головной боли при обновлении. - -К примеру, Вы хотите создать метод, который устанавливает зашифрованную куку с помощью класса [Encrypt]: - - encode((string) $value); - - parent::set($name, $value, $expiration); - } - - /** - * Gets an encrypted cookie. - * - * @uses Cookie::get - * @uses Encrypt::decode - */ - public static function decrypt($name, $default = NULL) - { - if ($value = parent::get($name, NULL)) - { - $value = Encrypt::instance(Cookie::$encryption)->decode($value); - } - - return isset($value) ? $value : $default; - } - - } // End Cookie - -Теперь вызов `Cookie::encrypt('secret', $data)` будет создавать шифрованную куку, которую можно расшифровать так: `$data = Cookie::decrypt('secret')`. - -## Многоуровневое расширение {#multiple-extensions} - -Если Вы расширяете классы Kohana в модуле, следует поддерживать прозрачное расширение. Вместо того, чтобы наследовать расширение [Cookie] от [Kohana_Cookie], создайте `MODPATH/mymod/encrypted/cookie.php`: - - class Encrypted_Cookie extends Kohana_Cookie { - - // Используйте методы encrypt() and decrypt(), описанные выше - - } - -Теперь создайте `MODPATH/mymod/cookie.php`: - - class Cookie extends Encrypted_Cookie {} - -Таким образом, пользователи смогут добавлять свои расширения в класс [Cookie], не затрагивая Ваши изменения. Однако, при следующем расширении класса [Cookie] придется наследоваться от `Encrypted_Cookie`, а не от `Kohana_Cookie`. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/using.configuration.md b/includes/kohana/modules/userguide/guide/ru-ru/using.configuration.md deleted file mode 100644 index 1b8f7d96..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/using.configuration.md +++ /dev/null @@ -1,58 +0,0 @@ -# Основы - -Kohana использует для конфигурации как статические свойства, так и файлы. Статические свойства обычно применяются для статических классов, таких как [Cookie], [Security], и [Upload]. Файлы используются для объектов типа [Database], [Encrypt], и [Session]. - -Статические свойства могут быть установлены в `APPPATH/bootstrap.php` или с помощью [расширения классов](using.autoloading#class-extension). Преимущество статических свойств в том, что не требуется загрузки дополнительных файлов. Недостаток в том, что инициируется загрузка класса, когда свойство устанавливается (если Вы не используете для этого расширения). С другой стороны, использование расширений переопределит возможные расширения из других модулей. Так что рекомендуется выносить установку статических свойств в bootstrap. - -[!!] При использовании opcode-кэширования, например [APC](http://php.net/apc) или [eAccelerator](http://eaccelerator.net/), время загрузки класса значительно уменьшается. Настойчиво рекомендуем использовать opcode-кэширование на любом работающем сайте, независимо от размера. - -## Параметры инициализации - -Для каждой новой установки Kohana потребуется изменить настройки [Kohana::init] в `APPPATH/bootstrap.php`. Все опущенные настройки будут использовать дефолтные значения. Настройки могут быть получены и изменены позже, с помощью статических свойств класса [Kohana]. К примеру, для получения текущей кодировки, обратитесь к свойству [Kohana::$charset]. - -## Настройки безопасности - -Существует несколько параметров, которые необходимо поменять, чтобы сделать Kohana более защищенной. Самый важный из них - [Cookie::$salt], который используется для "подписывания" куков, что защищает их от подмены вне Kohana. - -Если Вы планируете использовать класс [Encrypt], Вам также понадобится создать файл конфигурации `encrypt` и установить значение `ключа` шифрования. Шифровальный ключ должен включать буквы, цифры и знаки для повышения безопасности. - - -[!!] **Не используйте хэш для ключа шифрования!** Поступая таким образом, Вы облегчаете его взлом. - -# Файлы конфигурации {#config-files} - -Файлы конфигурации несколько отличаются от прочих файлов [каскадной файловой системы](about.filesystem) тем, что они **сливаются** вместо того, чтобы переопределяться. Это означает, что все конфигурационные файлы с одинаковым путем будут объединены для получения итоговой конфигурации. Как результат, Вы можете перезаписать *отдельные* параметры вместо того, чтобы дублровать все содержимое файла. - -Файлы конфигурации являются обычными PHP-файлами, хранимыми в директории `config/`, они должны возвращать ассоциативный массив: - - 'value', - 'options' => array( - 'foo' => 'bar', - ), - ); - -В данном примере файл называется `myconf.php`, и Вы можете получить доступ к нему так: - - $config = Kohana::config('myconf'); - $options = $config['options']; - -[Kohana::config] также предоставляет быстрый доступ к отдельным ключам массива конфигурации, используя "точечные пути". - -Получим доступ к массиву "options": - - $options = Kohana::config('myconf.options'); - -А так извлечем ключ "foo" из массива "options": - - $foo = Kohana::config('myconf.options.foo'); - -Также массивы могут выступать в качестве объектов, если Вам так больше нравится: - - $options = Kohana::config('myconf')->options; - -Пожалуйста, обратите внимание, что Вы можете получить доступ только к корневым ключам через свойства объекта, все дочерние ключи доступны через стандартный синтаксис работы с массивами: - - $foo = Kohana::config('myconf')->options['foo']; diff --git a/includes/kohana/modules/userguide/guide/ru-ru/using.messages.md b/includes/kohana/modules/userguide/guide/ru-ru/using.messages.md deleted file mode 100644 index baf08e41..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/using.messages.md +++ /dev/null @@ -1,26 +0,0 @@ -# Основы - -Сообщения Kohana - это понятные человеку строки, представленные в виде короткого слова или фразы, называемой "ключ". Сообщения извлекают с помощью метода [Kohana::message], который возвращает либо группу сообщений целиком, либо отдельное сообщение. - -Например, когда пользователь не вошел в систему и пытается зайти на страницу, требующую аутентифицикации, должна быть отображена ошибка типа "Вы должны залогиниться для доступа к данной странице". Это сообщение может храниться в файле `auth` под ключом `must_login`: - - $message = Kohana::message('auth', 'must_login'); - -Сообщения не переводятся автоматически. Для осуществления перевода используйте [функции перевода](using.translation): - - $translated = __(Kohana::message('auth', 'must_login')); - -[!!] В Kohana v2 система сообщений использовалась для перевода. Однако, рекомендуется использовать новую систему перевода вместо системы сообщений, так как она выведет понятный текст даже если перевод не найден. - -## Файлы сообщений - -Все файлы сообщений являются PHP-файлами, хранимыми в директории `messages/`, и возвращают ассоциативные массивы: - - 'Вы должны залогиниться для доступа к этой странице', - 'no_access' => 'У Вас недостаточно прав для доступа к странице', - ); - -Файлы сообщений похожи на [файлы настроек](using.configuration#config-files) - они тоже собираются вместе. Это означает, что все сообщения, хранимые в файлах с именем `auth`, будут объединены в один массив, так что нет необходимости дублировать все сообщения, если Вы создаете новый файл `auth`. diff --git a/includes/kohana/modules/userguide/guide/ru-ru/using.sessions.md b/includes/kohana/modules/userguide/guide/ru-ru/using.sessions.md deleted file mode 100644 index bddfd5fe..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/using.sessions.md +++ /dev/null @@ -1,223 +0,0 @@ -# Сессии и Куки - -Kohana предоставляет пару классов, которые облегчают работу с куками и сессиями. На верхнем уровне и сессии, и куки обеспечивают одни и те же функции. Они позволяют разработчику хранить временную или постоянную инфомацию о конкретном клиенте для дальнейшего использования. - -Куки следует использовать для хранения публичных (некритичных) данных, неизменных в течении длительного времени. Например, хранить идентификатор пользователя или предпочитаемый язык. Используйте класс [Cookie] для установки и получения кук. - -[!!] Kohana работает с "подписанными" куками. Каждая хранимая кука содержит хэша для предотвращения подмены значения куки. Этот хэш генерируется методом [Cookie::salt], который учитывает свойство [Cookie::$salt]. Вам следует [изменить настройки](using.configuration), когда будете опубликовывать свое приложение. - -Сессии лучше использовать для хранения временных или секретных данных. Крайне критичную информацию стоит хранить в классе [Session] с драйвером "database" или "native". Когда используется драйвер "cookie", сессия должна быть зашифрована. - -[!!] Больше информации о работе с переменными сессии Вы можете получить в статье [семь смертных грехов сессий](http://lists.nyphp.org/pipermail/talk/2006-December/020358.html). - -# Хранение, извлечение и удаление данных - -[Cookie] и [Session] предоставляют очень схожий API для хранения данных. Главное отличие между ними в том, что доступ к сессии осуществляется как к объекту, а к кукам - как статическому классу (хэлпер). - -Получить объект сессии можно посредством метода [Session::instance]: - - // Get the session instance - $session = Session::instance(); - -Вы можете также получить все данные сессии с помощью метода [Session::as_array]: - - // Get all of the session data as an array - $data = $session->as_array(); - -Также есть возможность переписать глобальную переменную `$_SESSION`. чтобы работать с сессиями в более привычном, стандартном для PHP стиле: - - // Overload $_SESSION with the session data - $_SESSION =& $session->as_array(); - - // Set session data - $_SESSION[$key] = $value; - -## Хранение данных {#setting} - -Для сохранения данных сессии или куки применяется метод `set`: - - // Set session data - $session->set($key, $value); - - // Set cookie data - Cookie::set($key, $value); - - // Store a user id - $session->set('user_id', 10); - Cookie::set('user_id', 10); - -## Получение данных {#getting} - -Извлечение данных сессии или кук возможно посредством метода `get`: - - // Get session data - $data = $session->get($key, $default_value); - - // Get cookie data - $data = Cookie::get($key, $default_value); - - // Get the user id - $user = $session->get('user_id'); - $user = Cookie::get('user_id'); - -## Удаление данных {#deleting} - -Метод `delete` позволяет удалить данные из сессии или кук: - - // Delete session data - $session->delete($key); - - // Delete cookie data - Cookie::delete($key); - - // Delete the user id - $session->delete('user_id'); - Cookie::delete('user_id'); - -# Настройка {#configuration} - -И куки, и сессии имеют несколько параметров, которые влияют на механизм хранение данных. Всегда проверяйте их перед завершением приложения, так как многие из них будут напрямую влиять на безопасность Вашего приложения. - -## Настройка кук - -Все настройки изменяются через статические свойства. Вы можете изменить их либо через `bootstrap.php`, либо посредством [расширения классов](using.autoloading#class-extension). - -Наиболее важный параметр это [Cookie::$salt], он используется для шифрования подписи. Значение необходимо поменять и держать в тайне: - - Cookie::$salt = 'your secret is safe with me'; - -[!!] Изменение данного значения сделает недействительными все сохраненные ранее куки. - -По умолчанию куки хранятся до закрытия браузера. Чтобы указать свое значение для времени жизни, измените параметр [Cookie::$expiration]: - - // Set cookies to expire after 1 week - Cookie::$expiration = 604800; - - // Alternative to using raw integers, for better clarity - Cookie::$expiration = Date::WEEK; - -Адрес, с которого куки могут быть доступны, может быть ограничен параметром [Cookie::$path]. - - // Allow cookies only when going to /public/* - Cookie::$path = '/public/'; - -Домен, на котором куки будут доступны, указан в свойстве [Cookie::$domain]. - - // Allow cookies only on the domain www.example.com - Cookie::$domain = 'www.example.com'; - -Если Вы хотите сделать куку доступной для всех поддоменов, поставьте точку перед началом домена - - // Allow cookies to be accessed on example.com and *.example.com - Cookie::$domain = '.example.com'; - -Чтобы разрешить куки только по защищенному (HTTPS) соединению, установите [Cookie::$secure] параметр. - - // Allow cookies to be accessed only on a secure connection - Cookie::$secure = TRUE; - - // Allow cookies to be accessed on any connection - Cookie::$secure = FALSE; - -Защитите куки от доступа через Javascript, изменив параметр [Cookie::$httponly]. - - // Make cookies inaccessible to Javascript - Cookie::$httponly = TRUE; - -## Драйверы сессии {#adapters} - -При создании или доступе к объекту класс [Session] Вы можете выбрать, какой драйвер использовать. Доступны следующие драйверы: - -Native -: Хранит данные в стандартном месте на диске web-сервера. Путь указывается в параметре [session.save_path](http://php.net/manual/session.configuration.php#ini.session.save-path) файла `php.ini` или переопределяется методом [ini_set](http://php.net/ini_set). - -Database -: Хранит информацию в базе данных с помощью класса [Session_Database]. Для работы требуется подключенный модуль [Database]. - -Cookie -: Хранит данные в куках, с помощью класса [Cookie]. **Для данного драйвера предельный размер сессии будет равен 4Кб ** - -Драйвер по умолчанию может быть установлен в [Session::$default]. Изначально это драйвер "native". - -[!!] Как и с куками, установка параметра "lifetime" в "0" означает, что сессия будет уничтожена после закрытия браузера. - -### Настройка драйвера сессии - -Вы можете применить настройки для каждого драйвера, создав конфигурационный файл `APPPATH/config/session.php`. Следующий пример настроек определяет конфигурацию для каждого драйвера: - - return array( - 'native' => array( - 'name' => 'session_name', - 'lifetime' => 43200, - ), - 'cookie' => array( - 'name' => 'cookie_name', - 'encrypted' => TRUE, - 'lifetime' => 43200, - ), - 'database' => array( - 'name' => 'cookie_name', - 'encrypted' => TRUE, - 'lifetime' => 43200, - 'group' => 'default', - 'table' => 'table_name', - 'columns' => array( - 'session_id' => 'session_id', - 'last_active' => 'last_active', - 'contents' => 'contents' - ), - 'gc' => 500, - ), - ); - -#### Драйвер Native {#adapter-native} - -Тип | Параметр | Описание | По умолчанию -----------|-----------|---------------------------------------------------|----------- -`string` | name | имя сессии | `"session"` -`integer` | lifetime | время жизни сессии (в секундах) | `0` - -#### Cookie Adapter {#adapter-cookie} - -Тип | Параметр | Описание | По умолчанию -----------|-----------|---------------------------------------------------|----------- -`string` | name | имя куки, используемой для хранения сессии | `"session"` -`boolean` | encrypted | шифровать данные с помощью [Encrypt]? | `FALSE` -`integer` | lifetime | время жизни сессии (в секундах) | `0` - -#### Database Adapter {#adapter-database} - -Тип | Параметр | Описание | По умолчанию -----------|-----------|---------------------------------------------------|----------- -`string` | group | название группы [Database::instance] | `"default"` -`string` | table | имя таблицы, в которой хранить данные | `"sessions"` -`array` | columns | ассоциативный массив псевдонимов полей | `array` -`integer` | gc | дает 1:x шанс, что запустится сборка мусора | `500` -`string` | name | имя куки, используемой для хранения сессии | `"session"` -`boolean` | encrypted | шифровать данные с помощью [Encrypt]? | `FALSE` -`integer` | lifetime | время жизни сессии (в секундах) | `0` - -##### Структура таблицы - -Вам придется создать таблицу для хранения сессии в базе данных. Вот структура по умолчанию: - - CREATE TABLE `sessions` ( - `session_id` VARCHAR(24) NOT NULL, - `last_active` INT UNSIGNED NOT NULL, - `contents` TEXT NOT NULL, - PRIMARY KEY (`session_id`), - INDEX (`last_active`) - ) ENGINE = MYISAM; - -##### Поля таблицы - -Вы можете изменить имя полей, чтобы использовать существующую таблицу. По умолчанию используется имя ключа. - -session_id -: название поля "id" - -last_active -: метка времени UNIX для последнего времени обновления сессии - -contents -: данные сессии, хранимые в виде сериализованной и (необязательно) зашифрованной строки diff --git a/includes/kohana/modules/userguide/guide/ru-ru/using.translation.md b/includes/kohana/modules/userguide/guide/ru-ru/using.translation.md deleted file mode 100644 index a98ecbbf..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/using.translation.md +++ /dev/null @@ -1 +0,0 @@ -# Интернационализация, перевод \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/ru-ru/using.views.md b/includes/kohana/modules/userguide/guide/ru-ru/using.views.md deleted file mode 100644 index a519bd3d..00000000 --- a/includes/kohana/modules/userguide/guide/ru-ru/using.views.md +++ /dev/null @@ -1,118 +0,0 @@ -# Использование представлений - -Представления - файлы, содержащие отображаемую информацию Вашего приложения. Чаще всего это HTML, CSS и Javascript, но может быть чем угодно, например XML или JSON для AJAX-вызовов. Цель представлений - хранить эту информацию отдельно от логики приложения для облегчения повторного использования и более чистого кода. - -Несмотря на это, представления сами по себе могут содержать код, используемый для отображения сохраненных в них данных. Например, циклический перебор элементов массива данных о продукте и отображение каждого в отдельном табличном ряду. Представления есть PHP-файлы, так что Вы можете свободно использовать там любой код, как обычно. - -# Создание файлов представлений - -Файлы представлений располагаются в директории `views` [файловой системы](about.filesystem). Вы также можете создавать поддиректории в ней для упорядочивания файлов. Все приведенные ниже примеры файлов являются допустимыми: - - APPPATH/views/home.php - APPPATH/views/pages/about.php - APPPATH/views/products/details.php - MODPATH/error/views/errors/404.php - MODPATH/common/views/template.php - -## Загрузка представлений - -Объект [View] обычно создается в контроллере ([Controller]) с помощью метода [View::factory]. Чаще всего представление записывается в свойство [Request::$response] или в другое представление. - - public function action_about() - { - $this->request->response = View::factory('pages/about'); - } - -Когда представление сохранено в [Request::$response], как в примере выше, оно будет автоматически отображено при необходимости. Для получения сгенерированного вывода представления используйте метод [View::render] или просто преобразуйте в строку. Когда представление генерируется, файл представления загружается, и формируется HTML. - - public function action_index() - { - $view = View::factory('pages/about'); - - // Render the view - $about_page = $view->render(); - - // Or just type cast it to a string - $about_page = (string) $view; - - $this->request->response = $about_page; - } - -## Переменные в представлениях - -Как только представление было загружено, к нему могут быть присоединены переменные, методами [View::set] и [View::bind]. - - public function action_roadtrip() - { - $view = View::factory('user/roadtrip') - ->set('places', array('Rome', 'Paris', 'London', 'New York', 'Tokyo')); - ->bind('user', $this->user); - - // The view will have $places and $user variables - $this->request->response = $view; - } - -[!!] Единственная разница между `set()` и `bind()` в том, что `bind()` присоединяет переменную по ссылке. Если Вы вызываете `bind()` переменной до того, как она определена, переменная будет создана со значением `NULL`. - -### Глобальные переменные - -Приложение может иметь несколько представлений, которым нужен доступ к одним и тем же переменным. Например, чтобы отобразить заголовок страницы и в шапке представления, и в теле содержимого страницы. Вы можете создать переменные, которые будут доступны в любом представлении, используя [View::set_global] и [View::bind_global]. - - // Assign $page_title to all views - View::bind_global('page_title', $page_title); - -Пусть приложение имеет три представления, которые генерируют главную страницу: `template`, `template/sidebar`, и `pages/home`. Сперва, напишем абстрактный контроллер для создания шаблона: - - abstract class Controller_Website extends Controller_Template { - - public $page_title; - - public function before() - { - parent::before(); - - // Make $page_title available to all views - View::bind_global('page_title', $this->page_title); - - // Load $sidebar into the template as a view - $this->template->sidebar = View::factory('template/sidebar'); - } - - } - -Далее, главный контроллер будет расширять `Controller_Website`: - - class Controller_Home extends Controller_Website { - - public function action_index() - { - $this->page_title = 'Home'; - - $this->template->content = View::factory('pages/home'); - } - - } - -## Представления внутри представлений - -Если Вы хотите вложить одно представление в другое, есть два варианта. Используя [View::factory], Вы можете его заключить в текущем представлении. Это означает, что Вы должны будут передать в него все необходимые переменные методами [View::set] и [View::bind]: - - // Only the $user variable will be available in "views/user/login.php" - bind('user', $user) ?> - -Другой способ - подключение представлений напрямую, что делает все текущие переменные доступными в подключаемом представлении: - - // Any variable defined in this view will be included in "views/message.php" - - -Естественно, Вы также можете загрузить объект [Request] в представление: - - execute() ?> - -Это пример [HMVC](about.mvc), который делает возможным создавать и считывать вызовы других URL Вашего приложения. - -# Переход с версии 2.x - -В отличие от версии Kohana 2.x, представления не создаются в контексте текущего контроллера, так что Вы не сможете использовать `$this` в качестве контроллера, в который загружено данное представление. Контроллер должен быть передан туда явно: - - $view->bind('controller', $this); diff --git a/includes/kohana/modules/userguide/guide/security.cookies.md b/includes/kohana/modules/userguide/guide/security.cookies.md deleted file mode 100644 index 920e9c18..00000000 --- a/includes/kohana/modules/userguide/guide/security.cookies.md +++ /dev/null @@ -1,3 +0,0 @@ -# Cookie Security - -[!!] stub diff --git a/includes/kohana/modules/userguide/guide/security.database.md b/includes/kohana/modules/userguide/guide/security.database.md deleted file mode 100644 index f1d09bb5..00000000 --- a/includes/kohana/modules/userguide/guide/security.database.md +++ /dev/null @@ -1,3 +0,0 @@ -# Database Security - -[!!] stub diff --git a/includes/kohana/modules/userguide/guide/tutorials.databases.md b/includes/kohana/modules/userguide/guide/tutorials.databases.md deleted file mode 100644 index c611d3b2..00000000 --- a/includes/kohana/modules/userguide/guide/tutorials.databases.md +++ /dev/null @@ -1,248 +0,0 @@ -# Databases {#top} - -Kohana 3.0 comes with a robust module to working with databases. By default the database module supports drivers for [MySQL](http://php.net/mysql) and [PDO](http://php.net/pdo). - -The database module is included with the Kohana 3.0 install but needs to be enabled before you can use it. In your `application/bootstrap.php` file modify the call to [Kohana::modules] and include the database module: - - Kohana::modules(array( - ... - 'database' => MODPATH.'database', - ... - )); - -## Configuration {#configuration} - -After the module has been enabled you will need to provide a configuration file so that the module knows how to connect to your database. An example config file can be found at `modules/database/config/database.php`. - -The structure of a database configuration group, called an "instance", looks like this: - - 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, - ), - -[!!] Multiple instances of these settings can be defined within the configuration file. - -Understanding each of these settings is important. - -INSTANCE_NAME -: Connections can be named anything you want, but you should always have at least one connection called "default". - -DATABASE_TYPE -: One of the installed database drivers. Kohana comes with "mysql" and "pdo" drivers. - -CONNECTION_ARRAY -: Specific driver options for connecting to your database. (Driver options are explained [below](#connection_settings).) - -TABLE_PREFIX -: Prefix that will be added to all table names by the [query builder](#query_building). - -QUERY_PROFILING -: Enables [profiling](debugging.profiling) of database queries. - -### Example - -The example file below shows 2 MySQL connections, one local and one remote. - - 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, - ), - ); - -### Connection Settings {#connection_settings} - -Every database driver has different connection settings. - -#### MySQL - -A MySQL database can accept the following options in the `connection` array: - -Type | Option | Description | Default value -----------|------------|----------------------------| ------------------------- -`string` | hostname | Hostname of the database | `localhost` -`integer` | port | Port number | `NULL` -`string` | socket | UNIX socket | `NULL` -`string` | username | Database username | `NULL` -`string` | password | Database password | `NULL` -`boolean` | persistent | Persistent connections | `FALSE` -`string` | database | Database name | `kohana` - -#### PDO - -A PDO database can accept these options in the `connection` array: - -Type | Option | Description | Default value -----------|------------|----------------------------| ------------------------- -`string` | dsn | PDO data source identifier | `localhost` -`string` | username | Database username | `NULL` -`string` | password | Database password | `NULL` -`boolean` | persistent | Persistent connections | `FALSE` - -[!!] If you are using PDO and are not sure what to use for the `dsn` option, review [PDO::__construct](http://php.net/pdo.construct). - -## Connections and Instances {#connections} - -Each configuration group is referred to as a database instance. Each instance can be accessed by calling [Database::instance]: - - $default = Database::instance(); - $remote = Database::instance('remote'); - -To disconnect the database, simply destroy the object: - - unset($default, Database::$instances['default']); - -If you want to disconnect all of the database instances at once: - - Database::$instances = array(); - -## Making Queries {#making_queries} - -There are two different ways to make queries. The simplest way to make a query is to use the [Database_Query], via [DB::query], to create queries. These queries are called "prepared statements" and allow you to set query parameters which are automatically escaped. The second way to make a query is by building the query using method calls. This is done using the [query builder](#query_building). - -[!!] All queries are run using the `execute` method, which accepts a [Database] object or instance name. See [Database_Query::execute] for more information. - -### Prepared Statements - -Using prepared statements allows you to write SQL queries manually while still escaping the query values automatically to prevent [SQL injection](http://wikipedia.org/wiki/SQL_Injection). Creating a query is simple: - - $query = DB::query(Database::SELECT, 'SELECT * FROM users WHERE username = :user'); - -The [DB::query] factory method creates a new [Database_Query] class for us, to allow method chaining. The query contains a `:user` parameter, which we can assign to a value: - - $query->param(':user', 'john'); - -[!!] Parameter names can be any string, as they are replaced using [strtr](http://php.net/strtr). It is highly recommended to **not** use dollars signs as parameter names to prevent confusion. - -If you want to display the SQL that will be executed, simply cast the object to a string: - - echo Kohana::debug((string) $query); - // Should display: - // SELECT * FROM users WHERE username = 'john' - -You can also update the `:user` parameter by calling [Database_Query::param] again: - - $query->param(':user', $_GET['search']); - -[!!] If you want to set multiple parameters at once, you can use [Database_Query::parameters]. - -Once you have assigned something to each of the parameters, you can execute the query: - - $query->execute(); - -It is also possible to bind a parameter to a variable, using a [variable reference]((http://php.net/language.references.whatdo)). This can be extremely useful when running the same query many times: - - $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 the above example, the variables `$username` and `$password` are changed for every loop of the `foreach` statement. When the parameter changes, it effectively changes the `:user` and `:pass` query parameters. Careful parameter binding can save a lot of code when it is used properly. - -### Query Building {#query_building} - -Creating queries dynamically using objects and methods allows queries to be written very quickly in an agnostic way. Query building also adds identifier (table and column name) quoting, as well as value quoting. - -[!!] At this time, it is not possible to combine query building with prepared statements. - -#### SELECT - -Each type of database query is represented by a different class, each with their own methods. For instance, to create a SELECT query, we use [DB::select]: - - $query = DB::select()->from('users')->where('username', '=', 'john'); - -By default, [DB::select] will select all columns (`SELECT * ...`), but you can also specify which columns you want returned: - - $query = DB::select('username', 'password')->from('users')->where('username', '=', 'john'); - -Now take a minute to look at what this method chain is doing. First, we create a new selection object using the [DB::select] method. Next, we set table(s) using the `from` method. Last, we search for a specific records using the `where` method. We can display the SQL that will be executed by casting the query to a string: - - echo Kohana::debug((string) $query); - // Should display: - // SELECT `username`, `password` FROM `users` WHERE `username` = 'john' - -Notice how the column and table names are automatically escaped, as well as the values? This is one of the key benefits of using the query builder. - -It is also possible to create `AS` aliases when selecting: - - $query = DB::select(array('username', 'u'), array('password', 'p'))->from('users'); - -This query would generate the following SQL: - - SELECT `username` AS `u`, `password` AS `p` FROM `users` - -#### INSERT - -To create records into the database, use [DB::insert] to create an INSERT query: - - $query = DB::insert('users', array('username', 'password'))->values(array('fred', 'p@5sW0Rd')); - -This query would generate the following SQL: - - INSERT INTO `users` (`username`, `password`) VALUES ('fred', 'p@5sW0Rd') - -#### UPDATE - -To modify an existing record, use [DB::update] to create an UPDATE query: - - $query = DB::update('users')->set(array('username' => 'jane'))->where('username', '=', 'john'); - -This query would generate the following SQL: - - UPDATE `users` SET `username` = 'jane' WHERE `username` = 'john' - -#### DELETE - -To remove an existing record, use [DB::delete] to create a DELETE query: - - $query = DB::delete('users')->where('username', 'IN', array('john', 'jane')); - -This query would generate the following SQL: - - DELETE FROM `users` WHERE `username` IN ('john', 'jane') - -#### Database Functions {#database_functions} - -Eventually you will probably run into a situation where you need to call `COUNT` or some other database function within your query. The query builder supports these functions in two ways. The first is by using quotes within aliases: - - $query = DB::select(array('COUNT("username")', 'total_users'))->from('users'); - -This looks almost exactly the same as a standard `AS` alias, but note how the column name is wrapped in double quotes. Any time a double-quoted value appears inside of a column name, **only** the part inside the double quotes will be escaped. This query would generate the following SQL: - - SELECT COUNT(`username`) AS `total_users` FROM `users` - -#### Complex Expressions - -Quoted aliases will solve most problems, but from time to time you may run into a situation where you need a complex expression. In these cases, you will need to use a database expression created with [DB::expr]. A database expression is taken as direct input and no escaping is performed. diff --git a/includes/kohana/modules/userguide/guide/tutorials.orm.md b/includes/kohana/modules/userguide/guide/tutorials.orm.md deleted file mode 100644 index 3fef93f4..00000000 --- a/includes/kohana/modules/userguide/guide/tutorials.orm.md +++ /dev/null @@ -1,298 +0,0 @@ -# ORM {#top} - -Kohana 3.0 includes a powerful ORM module that uses the active record pattern and database introspection to determine a model's column information. - -The ORM module is included with the Kohana 3.0 install but needs to be enabled before you can use it. In your `application/bootstrap.php` file modify the call to [Kohana::modules] and include the ORM module: - - Kohana::modules(array( - ... - 'orm' => MODPATH.'orm', - ... - )); - -## Configuration {#configuration} - -ORM requires little configuration to get started. Extend your model classes with ORM to begin using the module: - - class Model_User extends ORM - { - ... - } - -In the example above, the model will look for a `users` table in the default database. - -### Model Configuration Properties - -The following properties are used to configure each model: - -Type | Option | Description | Default value -----------|---------------------|----------------------------------| ------------------------- -`string` | _table_name | Table name to use | `singular model name` -`string` | _db | Name of the database to use | `default` -`string` | _primary_key | Column to use as primary key | `id` -`string` | _primary_val | Column to use as primary value | `name` -`bool` | _table_names_plural | Whether tables names are plural | `TRUE` -`array` | _sorting | Array of column => direction | `primary key => ASC` -`string` | _foreign_key_suffix | Suffix to use for foreign keys | `_id` - -## Using ORM - -### Loading a Record - -To create an instance of a model, you can use the [ORM::factory] method or the [ORM::__construct]: - - $user = ORM::factory('user'); - // or - $user = new Model_User(); - -The constructor and factory methods also accept a primary key value to load the given model data: - - // Load user ID 5 - $user = ORM::factory('user', 5); - - // See if the user was loaded successfully - if ($user->loaded()) { ... } - -You can optionally pass an array of key => value pairs to load a data object matching the given criteria: - - // Load user with email joe@example.com - $user = ORM::factory('user', array('email' => 'joe@example.com')); - -### Searching for a Record or Records - -ORM supports most of the [Database] methods for powerful searching of your model's data. See the `_db_methods` property for a full list of supported method calls. Records are retrieved using the [ORM::find] and [ORM::find_all] method calls. - - // This will grab the first active user with the name Bob - $user = ORM::factory('user') - ->where('active', '=', TRUE) - ->where('name', '=', 'Bob') - ->find(); - - // This will grab all users with the name Bob - $users = ORM::factory('user') - ->where('name', '=', 'Bob') - ->find_all(); - -When you are retrieving a list of models using [ORM::find_all], you can iterate through them as you do with database results: - - foreach ($users as $user) - { - ... - } - -A powerful feature of ORM is the [ORM::as_array] method which will return the given record as an array. If used with [ORM::find_all], an array of all records will be returned. A good example of when this is useful is for a select list: - - // Display a select field of usernames (using the id as values) - echo Form::select('user', ORM::factory('user')->find_all()->as_array('id', 'username')); - -### Counting Records - -Use [ORM::count_all] to return the number of records for a given query. - - // Number of users - $count = ORM::factory('user')->where('active', '=', TRUE)->count_all(); - -If you wish to count the total number of users for a given query, while only returning a certain subset of these users, call the [ORM::reset] method with `FALSE` before using `count_all`: - - $user = ORM::factory('user'); - - // Total number of users (reset FALSE prevents the query object from being cleared) - $count = $user->where('active', '=', TRUE)->reset(FALSE)->count_all(); - - // Return only the first 10 of these results - $users = $user->limit(10)->find_all(); - -### Accessing Model Properties - -All model properties are accessible using the `__get` and `__set` magic methods. - - $user = ORM::factory('user', 5); - - // Output user name - echo $user->name; - - // Change user name - $user->name = 'Bob'; - -To store information/properties that don't exist in the model's table, you can use the `_ignored_columns` data member. Data will be stored in the internal `_object` member, but ignored at the database level. - - class Model_User extends ORM - { - ... - protected $_ignored_columns = array('field1', 'field2', ...); - ... - } - -Multiple key => value pairs can be set by using the [ORM::values] method. - - $user->values(array('username' => 'Joe', 'password' => 'bob')); - -### Creating and Saving Records - -The [ORM::save] method is used to both create new records and update existing records. - - // Creating a record - $user = ORM::factory('user'); - $user->name = 'New user'; - $user->save(); - - // Updating a record - $user = ORM::factory('user', 5); - $user->name = 'User 2'; - $user->save(); - - // Check to see if the record has been saved - if ($user->saved()) { ... } - -You can update multiple records by using the [ORM::save_all] method: - - $user = ORM::factory('user'); - $user->name = 'Bob'; - - // Change all active records to name 'Bob' - $user->where('active', '=', TRUE)->save_all(); - -#### Using `Updated` and `Created` Columns - -The `_updated_column` and `_created_column` members are provided to automatically be updated when a model is updated and created. These are not used by default. To use them: - - // date_created is the column used for storing the creation date. Use format => TRUE to store a timestamp. - protected $_created_column = array('column' => 'date_created', 'format' => TRUE); - - // date_modified is the column used for storing the modified date. In this case, a string specifying a date() format is used. - protected $_updated_column = array('column' => 'date_modified', 'format' => 'm/d/Y'); - -### Deleting Records - -Records are deleted with [ORM::delete] and [ORM::delete_all]. These methods operate in the same fashion as saving described above with the exception that [ORM::delete] takes one optional parameter, the `id` of the record to delete. Otherwise, the currently loaded record is deleted. - -### Relationships - -ORM provides for powerful relationship support. Ruby has [a great tutorial on relationships](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html). - -#### Belongs-To and Has-Many - -We'll assume we're working with a school that has many students. Each student can belong to only one school. You would define the relationships in this manner: - - // Inside the school model - protected $_has_many = array('students' => array()); - - // Inside the student model - protected $_belongs_to = array('school' => array()); - -To access a student's school you use: - - $school = $student->school; - -To access a school's students, you would use: - - // Note that find_all is required after students - $students = $school->students->find_all(); - - // To narrow results: - $students = $school->students->where('active', '=', TRUE)->find_all(); - -By default, ORM will look for a `school_id` model in the student table. This can be overriden by using the `foreign_key` attribute: - - protected $_belongs_to = array('school' => array('foreign_key' => 'schoolID')); - -The foreign key should be overridden in both the student and school models. - -#### Has-One - -Has-One is a special case of Has-Many, the only difference being that there is one and only one record. In the above example, each school would have one and only one student (although this is a poor example). - - // Inside the school model - protected $_has_one = array('student' => array()); - -Like Belongs-To, you do not need to use the `find` method when referencing the Has-One related object - it is done automatically. - -#### Has-Many "Through" - -The Has-Many "through" relationship (also known as Has-And-Belongs-To-Many) is used in the case of one object being related to multiple objects of another type, and visa-versa. For instance, a student may have multiple classes and a class may have multiple students. In this case, a third table and model known as a `pivot` is used. In this case, we will call the pivot object/model `enrollment`. - - // Inside the student model - protected $_has_many = array('classes' => array('through' => 'enrollment')); - - // Inside the class model - protected $_has_many = array('students' => array('through' => 'enrollment')); - -The enrollment table should contain two foreign keys, one for `class_id` and the other for `student_id`. These can be overriden using `foreign_key` and `far_key` when defining the relationship. For example: - - // Inside the student model (the foreign key refers to this model [student], while the far key refers to the other model [class]) - protected $_has_many = array('classes' => array('through' => 'enrollment', 'foreign_key' => 'studentID', 'far_key' => 'classID')); - - // Inside the class model - protected $_has_many = array('students' => array('through' => 'enrollment', 'foreign_key' => 'classID', 'far_key' => 'studentID')); - -The enrollment model should be defined as such: - - // Enrollment model belongs to both a student and a class - protected $_belongs_to = array('student' => array(), 'class' => array()); - -To access the related objects, use: - - // To access classes from a student - $student->classes->find_all(); - - // To access students from a class - $class->students->find_all(); - -### Validation - -ORM is integrated tightly with the [Validate] library. The ORM provides the following members for validation: - -* _rules -* _callbacks -* _filters -* _labels - -#### `_rules` - - protected $_rules = array - ( - 'username' => array('not_empty' => array()), - 'email' => array('not_empty' => array(), 'email' => array()), - ); - -`username` will be checked to make sure it's not empty. `email` will be checked to also ensure it is a valid email address. The empty arrays passed as values can be used to provide optional additional parameters to these validate method calls. - -#### `_callbacks` - - protected $_callbacks = array - ( - 'username' => array('username_unique'), - ); - -`username` will be passed to a callback method `username_unique`. If the method exists in the current model, it will be used, otherwise a global function will be called. Here is an example of the definition of this method: - - public function username_unique(Validate $data, $field) - { - // Logic to make sure a username is unique - ... - } - -#### `_filters` - - protected $_filters = array - ( - TRUE => array('trim' => array()), - 'username' => array('stripslashes' => array()), - ); - -`TRUE` indicates that the `trim` filter is to be used on all fields. `username` will be filtered through `stripslashes` before it is validated. The empty arrays passed as values can be used to provide additional parameters to these filter method calls. - -#### Checking if the Object is Valid - -Use [ORM::check] to see if the object is currently valid. - - // Setting an object's values, then checking to see if it's valid - if ($user->values($_POST)->check()) - { - $user->save(); - } - -You can use the `validate()` method to access the model's validation object. - - // Add an additional filter manually - $user->validate()->filter('username', 'trim'); diff --git a/includes/kohana/modules/userguide/guide/tutorials.urls.md b/includes/kohana/modules/userguide/guide/tutorials.urls.md deleted file mode 100755 index b03befac..00000000 --- a/includes/kohana/modules/userguide/guide/tutorials.urls.md +++ /dev/null @@ -1,159 +0,0 @@ -# Routes, URLs, and Links - -This section will provide you with the basic idea behind Kohana's request routing, url generation and links. - -## Routing - -As mentioned in the [Request Flow](about.flow) section, a request is handled by the [Request] class which finds a matching [Route] and loads the appropriate controller to handle the request. This system provides much flexibility as well as a common sense default behavior. - -If you look in `APPPATH/bootstrap.php` you will see the following code which is run immediately before the request is handed off to [Request::instance]: - - Route::set('default', '((/(/)))') - ->defaults(array( - 'controller' => 'welcome', - 'action' => 'index', - )); - -This sets the `default` route with a uri in the format of `((/(/)))`. The tokens surrounded with `<>` are *keys* and the tokens surrounded with `()` are *optional* parts of the uri. In this case, the entire uri is optional, so a blank uri would match and the default controller and action would be assumed resulting in the `Controller_Welcome` class being loaded and eventually the `action_index` method being called to handle the request. - -Notice that in Kohana routes, any characters are allowed aside from `()<>` and the `/` has no special meaning. In the default route the `/` is used as a static separator but as long as the regex makes sense there is no restriction to how you can format your routes. - -### Directories - -For organizational purposes you may wish to place some of your controllers in subdirectories. A common case is for an admin backend to your site: - - Route::set('admin', 'admin(/(/(/)))') - ->defaults(array( - 'directory' => 'admin', - 'controller' => 'home', - 'action' => 'index', - )); - -This route specifies that the uri must begin with `admin` to match and the directory is statically assigned to `admin` in the defaults. Now a request to `admin/users/create` would load the `Controller_Admin_Users` class and call the `action_create` method. - -### Patterns - -The Kohana route system uses perl compatible regular expressions in its matching process. By default the keys (surrounded by `<>`) are matched by `[a-zA-Z0-9_]++` but you can define your own patterns for each key by passing an associative array of keys and patterns as an additional argument to [Route::set]. To extend our previous example let's say you have an admin section and an affiliates section. You could specify those in separate routes or you could do something like this: - - Route::set('sections', '(/(/(/)))', - array( - 'directory' => '(admin|affiliate)' - )) - ->defaults(array( - 'controller' => 'home', - 'action' => 'index', - )); - -This would provide you with two sections of your site, 'admin' and 'affiliate' which would let you organize the controllers for each into subdirectories but otherwise work like the default route. - -### More Route Examples - -There are countless other possibilities for routes. Here are some more examples: - - /* - * Authentication shortcuts - */ - Route::set('auth', '', - array( - 'action' => '(login|logout)' - )) - ->defaults(array( - 'controller' => 'auth' - )); - - /* - * Multi-format feeds - * 452346/comments.rss - * 5373.json - */ - Route::set('feeds', '(/).', - array( - 'user_id' => '\d+', - 'format' => '(rss|atom|json)', - )) - ->defaults(array( - 'controller' => 'feeds', - 'action' => 'status', - )); - - /* - * Static pages - */ - Route::set('static', '.html', - array( - 'path' => '[a-zA-Z0-9_/]+', - )) - ->defaults(array( - 'controller' => 'static', - 'action' => 'index', - )); - - /* - * You don't like slashes? - * EditGallery:bahamas - * Watch:wakeboarding - */ - Route::set('gallery', '():', - array( - 'controller' => '[A-Z][a-z]++', - 'action' => '[A-Z][a-z]++', - )) - ->defaults(array( - 'controller' => 'Slideshow', - )); - - /* - * Quick search - */ - Route::set('search', ':', array('query' => '.*')) - ->defaults(array( - 'controller' => 'search', - 'action' => 'index', - )); - -Routes are matched in the order specified so be aware that if you set routes after the modules have been loaded a module could specify a route that conflicts with your own. This is also the reason that the default route is set last, so that custom routes will be tested first. - -### Request Parameters - -The directory, controller and action can be accessed from the [Request] instance in either of these two ways: - - $this->request->action; - Request::instance()->action; - -All other keys specified in a route can be accessed from within the controller via: - - $this->request->param('key_name'); - -The [Request::param] method takes an optional second argument to specify a default return value in case the key is not set by the route. If no arguments are given, all keys are returned as an associative array. - -### Convention - -The established convention is to either place your custom routes in the `MODPATH//init.php` file of your module if the routes belong to a module, or simply insert them into the `APPPATH/bootstrap.php` file above the default route if they are specific to the application. Of course, they could also be included from an external file or even generated dynamically. - -## URLs - -Along with Kohana's powerful routing capabilities are included some methods for generating URLs for your routes' uris. You can always specify your uris as a string using [URL::site] to create a full URL like so: - - URL::site('admin/edit/user/'.$user_id); - -However, Kohana also provides a method to generate the uri from the route's definition. This is extremely useful if your routing could ever change since it would relieve you from having to go back through your code and change everywhere that you specified a uri as a string. Here is an example of dynamic generation that corresponds to the `feeds` route example from above: - - Route::get('feeds')->uri(array( - 'user_id' => $user_id, - 'action' => 'comments', - 'format' => 'rss' - )); - -Let's say you decided later to make that route definition more verbose by changing it to `feeds/(/).`. If you wrote your code with the above uri generation method you wouldn't have to change a single line! When a part of the uri is enclosed in parentheses and specifies a key for which there in no value provided for uri generation and no default value specified in the route, then that part will be removed from the uri. An example of this is the `(/)` part of the default route; this will not be included in the generated uri if an id is not provided. - -One method you might use frequently is the shortcut [Request::uri] which is the same as the above except it assumes the current route, directory, controller and action. If our current route is the default and the uri was `users/list`, we can do the following to generate uris in the format `users/view/$id`: - - $this->request->uri(array('action' => 'view', 'id' => $user_id)); - -Or if within a view, the preferable method is: - - Request::instance()->uri(array('action' => 'view', 'id' => $user_id)); - -## Links - -[!!] links stub diff --git a/includes/kohana/modules/userguide/guide/userguide/adding.md b/includes/kohana/modules/userguide/guide/userguide/adding.md new file mode 100644 index 00000000..7a5ec689 --- /dev/null +++ b/includes/kohana/modules/userguide/guide/userguide/adding.md @@ -0,0 +1,41 @@ +# Adding your module to the userguide + +Making your module work with the userguide is simple. + +First, copy this config and place in it `/config/userguide.php`, replacing anything in `<>` with the appropriate things: + + return array + ( + // Leave this alone + 'modules' => array( + + // This should be the path to this modules userguide pages, without the 'guide/'. Ex: '/guide/modulename/' would be 'modulename' + '' => array( + + // Whether this modules userguide pages should be shown + 'enabled' => TRUE, + + // The name that should show up on the userguide index page + 'name' => '', + + // A short description of this module, shown on the index page + 'description' => '', + + // Copyright message, shown in the footer for this module + 'copyright' => '© 2010–2011 ', + ) + ) + ); + +Next, create a folder in your module directory called `guide/` and create `index.md` and `menu.md`. All userguide pages use [Markdown](markdown). The index page is what is shown on the index of your module, the menu is what shows up in the side column. The menu should be formatted like this: + + ## [Module Name]() + - [Page name](page-path) + - [This is a Category](category) + - [Sub Page](category/sub-page) + - [Another](category/another) + - [Sub sub page](category/another/sub-page) + - Categories do not have to be a link to a page + - [Etcetera](etc) + +Page paths are relative to `guide/`. So `[Page name](path-path)` would look for `guide//page-name.md` and `[Another](category/another)` would look for `guide//page-name.md`. The guide pages can be named or arranged any way you want within that folder (with the exception of `menu.md` and `index.md`). The breadcrumbs and page titles are pulled from the `menu.md file`, not the file names or paths. You can have items that are not pages (a category that doesn't have a corresponding page). To link to the `index.md` page, you should have an empty link, e.g. `[Module Name]()`. Do not include `.md` in your links. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/userguide/config.md b/includes/kohana/modules/userguide/guide/userguide/config.md new file mode 100644 index 00000000..a566040f --- /dev/null +++ b/includes/kohana/modules/userguide/guide/userguide/config.md @@ -0,0 +1,35 @@ +# Configuration + +The userguide has the following config options, available in `config/userguide.php`. + + return array + ( + // 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, + + ); + +You can enable or disabled the entire api browser, or limit it to only show certain packages. To disable a module from showing pages in the userguide, simply change that modules `enabled` option using the cascading filesystem. For example: + + `application/config/userguide.php` + + return array + ( + 'modules' => array + ( + 'kohana' => array + ( + 'enabled' => FALSE, + ), + 'database' => array + ( + 'enabled' => FALSE, + ) + ) + ) + +Using this you could make the userguide only show your modules and your classes in the api browser, if you wanted to host your own documentation on your site. Feel free to change the styles and views as well, but be sure to give credit where credit is due! \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/userguide/contributing.md b/includes/kohana/modules/userguide/guide/userguide/contributing.md new file mode 100644 index 00000000..fcf4e613 --- /dev/null +++ b/includes/kohana/modules/userguide/guide/userguide/contributing.md @@ -0,0 +1,66 @@ +[!!] When the docs get merged these images/links should be update + +# Contributing + +Kohana is community driven, and we rely on community contributions for the documentation. + +## Guidelines + +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. + +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. Bad: "Added docs", Good: "Added initial draft of hello world tutorial", Bad: "Fixed typos", Good: "Fixed typos on the query builder page" + +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. + +## Quick Method + +To quickly point out something that needs improvement, report a [bug report](http://dev.kohanaframework.org/projects/userguide3/issues/new). + +If you want to contribute some changes, you can do so right from your browser without even knowing git! + +First create an account on [Github](https://github.com/signup/free). + +You will need to fork the module for the area you want to improve. For example, to improve the [ORM documentation](../orm) fork . To improve the [Kohana documentation](../kohana), fork , etc. So, find the module you want to improve and click on the Fork button in the top right. + +![Fork the module](contrib-github-fork.png) + +The files that make the User Guide portion are found in `guide//`, and the API browser portion is made from the comments in the source code itself. Navigate to one of the files you want to change and click the edit button in the top right of the file viewer. + +![Click on edit to edit the file](contrib-github-edit.png) + +Make the changes and add a **detailed commit message**. Repeat this for as many files as you want to improve. (Note that you can't preview what the changes will look unless you actually test it locally.) + +After you have made your changes, send a pull request so your improvements can be reviewed to be merged into the official documentation. + +![Send a pull request](contrib-github-pull.png) + +Once your pull request has been accepted, you can delete your repository if you want. Your commit will have been copied to the official branch. + +## 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 git@github.com:/core.git + + # (make some changes to the docs) + + # now commit the changes and push to your repo + git commit + git push 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. diff --git a/includes/kohana/modules/userguide/guide/userguide/index.md b/includes/kohana/modules/userguide/guide/userguide/index.md new file mode 100644 index 00000000..810f8d72 --- /dev/null +++ b/includes/kohana/modules/userguide/guide/userguide/index.md @@ -0,0 +1,3 @@ +# Userguide + +The userguide module provides documentation viewing including browsing the source code comments. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/userguide/markdown.md b/includes/kohana/modules/userguide/guide/userguide/markdown.md new file mode 100644 index 00000000..3367fbd5 --- /dev/null +++ b/includes/kohana/modules/userguide/guide/userguide/markdown.md @@ -0,0 +1,235 @@ +# Markdown Syntax + +The userguide uses [Markdown](http://daringfireball.net/projects/markdown/) and [Markdown Extra](http://michelf.com/projects/php-markdown/extra/) for the userguide pages, and the in-code comments used to generate the API browser. This is a brief summary of most of Markdown and Markdown extra features. It does not cover everything, and it does not cover all the caveats. + +[!!] Be sure to check out the **[Userguide Specific Syntax](#userguide-specific-syntax)** for things that Userguide adds to markdown. + +## Headers + + # Header 1 + + ## Header 2 + + ### Header 3 + + #### Header 4 + +## Paragraphs +~~~ +Regular text will be transformed into paragraphs. +Single returns will not make a new paragraph, this +allows for wrapping (especially for in-code +comments). + +A new paragraph will start if there is a blank line between +blocks of text. Chars like > and & are escaped for you. + +To make a line break, +put two spaces at the +end of a line. +~~~ +Regular text will be transformed into paragraphs. +Single returns will not make a new paragraph, this +allows for wrapping (especially for in-code +comments). + +A new paragraph will start if there is a blank line between +blocks of text. Chars like > and & are escaped for you. + +To make a line break, +put two spaces at the +end of a line. + +## Links +~~~ +This is a normal link: [Kohana](http://kohanaframework.org). + +This link has a title: [Kohana](http://kohanaframework.org "The swift PHP framework") +~~~ +This is a normal link: [Kohana](http://kohanaframework.org) + +This link has a title: [Kohana](http://kohanaframework.org "The swift PHP framework") + +## Code blocks + + For inline code simply surround some `text with tick marks.` + +For inline code simply surround some `text with tick marks.` + + // For a block of code, + // indent in four spaces, + // or with a tab + +You can also do a "fenced" code block: + + ~~~ + A fenced code block has tildes + above and below it + This is sometimes useful when code is near lists + ~~~ +~~~ +A fenced code block has tildes + above and below it +This is sometimes useful when code is near lists +~~~ + +## Unordered Lists + +~~~ +* To make a unordered list, put an asterisk, minus, or + at the beginning +- of each line, surrounded by spaces. You can mix * - and +, but it ++ makes no difference. +~~~ +* To make a unordered list, put an asterisk, minus, or + at the beginning +- of each line, surrounded by spaces. You can mix * - and +, but it ++ makes no difference. + +## Ordered Lists + +~~~ +1. For ordered lists, put a number and a period +2. On each line that you want numbered. +9. It doesn't actually have to be the correct number order +5. Just as long as each line has a number +~~~ +1. For ordered lists, put a number and a period +2. On each line that you want numbered. +9. It doesn't actually have to be the correct number order +5. Just as long as each line has a number + +## Nested Lists + +~~~ +* To nest lists you just add four spaces before the * or number + 1. Like this + * It's pretty basic, this line has eight spaces, so its nested twice + 1. And this line is back to the second level + * Out to third level again +* And back to the first level +~~~ +* To nest lists you just add four spaces before the * or number + 1. Like this + * It's pretty basic, this line has eight spaces, so its nested twice + 1. And this line is back to the second level + * Out to third level again +* And back to the first level + +## Italics and Bold + +~~~ +Surround text you want *italics* with *asterisks* or _underscores_. + +**Double asterisks** or __double underscores__ makes text bold. + +***Triple*** will do *both at the same **time***. +~~~ +Surround text you want *italics* with *asterisks* or _underscores_. + +**Double asterisks** or __double underscores__ makes text **bold**. + +___Triple___ will do *both at the same **time***. + +## Horizontal Rules + +Horizontal rules are made by placing 3 or more hyphens, asterisks, or underscores on a line by themselves. +~~~ +--- +* * * * +_____________________ +~~~ +--- +* * * * +_____________________ + +## Images + +Image syntax looks like this: + + ![Alt text](/path/to/img.jpg) + + ![Alt text](/path/to/img.jpg "Optional title") + +[!!] Note that the images in userguide are [namespaced](#namespacing). + +## Tables +~~~ +First Header | Second Header +------------- | ------------- +Content Cell | Content Cell +Content Cell | Content Cell +~~~ + +First Header | Second Header +------------- | ------------- +Content Cell | Content Cell +Content Cell | Content Cell + +Note that the pipes on the very left and very right side are optional, and you can change the text-alignment by adding a colon on the right, or on both sides for center. +~~~ +| Item | Value | Savings | +| --------- | -----:|:-------:| +| Computer | $1600 | 40% | +| Phone | $12 | 30% | +| Pipe | $1 | 0% | +~~~ +| Item | Value | Savings | +| --------- | -----:|:-------:| +| Computer | $1600 | 40% | +| Phone | $12 | 30% | +| Pipe | $1 | 0% | + +# Userguide Specific Syntax + +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 links are "namespaced" to the current module. For example, from anywhere within the Kohana core docs you do not need to include `kohana` at the beginning of a link url. For example: `[Hello World Tutorial](tutorials/hello-world)` rather than `(kohana/tutorials/hello-world)`. + +To link to a modules index page, have an empty url like: `[Kohana]()`. + +To link to page in a different module, prefix your url with `../` and the module name. For example: `[Kohana Routes](../kohana/routing)` + +**Images are also namespaced**, using `![Alt Text](imagename.jpg)` would look for `media/guide//imagename.jpg`. + +## API Links + +You can make links to the api browser by wrapping any class name in brackets. You may also include a function name, or propery name to link to that specifically. All of the following will link to the API browser: + + [Request] + [Request::execute] + [Request::execute()] + [Request::$status] + +[Request] +[Request::execute] +[Request::execute()] +[Request::$status] + +If you want to have parameters and have the function be clickable, 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') + +[Kohana::config]\('foobar','baz') + +## Notes + +If you put `[!!]` in front of a line it will be a "note" and be placed in a box with a lightbulb. + + [!!] This is a note + +will display as: + +[!!] 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 (e.g. more than one "Examples" header), only the first will get be automatically assigned an id, so you should manually assign more descriptive ids. For example: + + ### Examples {#more-descriptive-id} + +## Including Views + +If you need you may include a regular Kohana View file by placing the name of the view in double curly brackets. **If the view is not found, no error or exception will be shown, the curly brackets and view name will simply remain there!** + + {{some/view/file}} diff --git a/includes/kohana/modules/userguide/guide/userguide/menu.md b/includes/kohana/modules/userguide/guide/userguide/menu.md new file mode 100644 index 00000000..e3f53efd --- /dev/null +++ b/includes/kohana/modules/userguide/guide/userguide/menu.md @@ -0,0 +1,7 @@ +## [Userguide]() + - [Using the Userguide](using) + - [How userguide works](works) + - [Contributing](contributing) + - [Markdown Syntax](markdown) + - [Configuration](config) + - [Adding your module](adding) \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/userguide/modules.md b/includes/kohana/modules/userguide/guide/userguide/modules.md new file mode 100644 index 00000000..e69de29b diff --git a/includes/kohana/modules/userguide/guide/userguide/using.md b/includes/kohana/modules/userguide/guide/userguide/using.md new file mode 100644 index 00000000..662351cf --- /dev/null +++ b/includes/kohana/modules/userguide/guide/userguide/using.md @@ -0,0 +1 @@ +Give tips on how to most effectively use the user guide. How to navigate around, how things are organized, etc. \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/userguide/works.md b/includes/kohana/modules/userguide/guide/userguide/works.md new file mode 100644 index 00000000..e78c48a8 --- /dev/null +++ b/includes/kohana/modules/userguide/guide/userguide/works.md @@ -0,0 +1,25 @@ +# How the Userguide works + +The userguide uses [Markdown](markdown) for the documentation. Both the userguide pages, and the in code comments for the API browser are written in markdown. + +## Userguide pages + +Userguide pages are in the module they apply to, in `guide/`. For example, documentation for Kohana is in `system/guide/kohana` and documentation for orm is in `modules/orm/guide/orm`, database is in `modules/database/guide/database`, etc. + +Each module has an index page at `guide//index.md`. + +Each module's menu is at `guide//menu.md`. + +All other pages are are in `guide/` and can be organized in subfolders and named however you want. + +For more info on how to make your module have userguide pages, see [Adding your module](adding). + +### Images + +Any images used in the userguide pages must be in `media/guide//`. For example, if a page has `![Image Title](hello-world.jpg)` the image would be located at `media/guide//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. + +TODO: give more specific details on how to comment your classes, constants, methods, etc. including package and how it relates to the api module. diff --git a/includes/kohana/modules/userguide/guide/using.autoloading.md b/includes/kohana/modules/userguide/guide/using.autoloading.md deleted file mode 100644 index 11c9f517..00000000 --- a/includes/kohana/modules/userguide/guide/using.autoloading.md +++ /dev/null @@ -1,95 +0,0 @@ -# Loading Classes - -Kohana takes advantage of PHP [autoloading](http://php.net/manual/language.oop5.autoload.php). This removes the need to call [include](http://php.net/include) or [require](http://php.net/require) before using a class. For instance, when you want to use the [Cookie::set] method, you just call: - - Cookie::set('mycookie', 'any string value'); - -Or to load an [Encrypt] instance, just call [Encrypt::instance]: - - $encrypt = Encrypt::instance(); - -Classes are loaded via the [Kohana::auto_load] method, which makes a simple conversion from class name to file name: - -1. Classes are placed in the `classes/` directory of the [filesystem](about.filesystem) -2. Any underscore characters are converted to slashes -2. The filename is lowercase - -When calling a class that has not been loaded (eg: `Session_Cookie`), Kohana will search the filesystem using [Kohana::find_file] for a file named `classes/session/cookie.php`. - -## Custom Autoloaders - -The default autoloader is enabled in `application/bootstrap.php` using [spl_autoload_register](http://php.net/spl_autoload_register): - - spl_autoload_register(array('Kohana', 'auto_load')); - -This allows [Kohana::auto_load] to attempt to load any class that does not yet exist when the class is first used. - -# Transparent Class Extension {#class-extension} - -The [cascading filesystem](about.filesystem) allows transparent class extension. For instance, the class [Cookie] is defined in `SYSPATH/classes/cookie.php` as: - - class Cookie extends Kohana_Cookie {} - -The default Kohana classes, and many extensions, use this definition so that almost all classes can be extended. You extend any class transparently, by defining your own class in `APPPATH/classes/cookie.php` to add your own methods. - -[!!] You should **never** modify any of the files that are distributed with Kohana. Always make modifications to classes using extensions to prevent upgrade issues. - -For instance, if you wanted to create method that sets encrypted cookies using the [Encrypt] class: - - encode((string) $value); - - parent::set($name, $value, $expiration); - } - - /** - * Gets an encrypted cookie. - * - * @uses Cookie::get - * @uses Encrypt::decode - */ - public static function decrypt($name, $default = NULL) - { - if ($value = parent::get($name, NULL)) - { - $value = Encrypt::instance(Cookie::$encryption)->decode($value); - } - - return isset($value) ? $value : $default; - } - - } // End Cookie - -Now calling `Cookie::encrypt('secret', $data)` will create an encrypted cookie which we can decrypt with `$data = Cookie::decrypt('secret')`. - -## Multiple Levels of Extension {#multiple-extensions} - -If you are extending a Kohana class in a module, you should maintain transparent extensions. Instead of making the [Cookie] extension extend Kohana, you can create `MODPATH/mymod/encrypted/cookie.php`: - - class Encrypted_Cookie extends Kohana_Cookie { - - // Use the same encrypt() and decrypt() methods as above - - } - -And create `MODPATH/mymod/cookie.php`: - - class Cookie extends Encrypted_Cookie {} - -This will still allow users to add their own extension to [Cookie] with your extensions intact. However, the next extension of [Cookie] will have to extend `Encrypted_Cookie` instead of `Kohana_Cookie`. diff --git a/includes/kohana/modules/userguide/guide/using.configuration.md b/includes/kohana/modules/userguide/guide/using.configuration.md deleted file mode 100644 index 4c29a650..00000000 --- a/includes/kohana/modules/userguide/guide/using.configuration.md +++ /dev/null @@ -1,57 +0,0 @@ -# General Configuration - -Kohana uses both static properties and files for configuration. Static properties are typically used for static classes, such as [Cookie], [Security], and [Upload]. Files are typically used for objects such as [Database], [Encrypt], and [Session]. - -Static properties can be set in `APPPATH/bootstrap.php` or by [class extension](using.autoloading#class-extension). The benefit of static properties is that no additional files need to be loaded. The problem with this method is that it causes the class to be loaded when the property is set, if you do not use an extension. However, using extensions will overload extensions made in modules. It is generally recommended to do static property configuration in the bootstrap. - -[!!] When using opcode caching, such as [APC](http://php.net/apc) or [eAccelerator](http://eaccelerator.net/), class loading time is significantly reduced. It is highly recommended to use opcode caching with *any* production website, no matter the size. - -## Initial Settings - -Every new Kohana installation will require changing [Kohana::init] settings in `APPPATH/bootstrap.php`. Any setting that is not set will use the default setting. These settings can be accessed and modified later by using the static property of the [Kohana] class. For instance, to get the current character set, read the [Kohana::$charset] property. - -## Security Settings - -There are several settings which need to be changed to make Kohana secure. The most important of these is [Cookie::$salt], which is used to create a "signature" on cookies that prevents them from being modified outside of Kohana. - -If you plan to use the [Encrypt] class, you will also need to create an `encrypt` configuration file and set the encryption `key` value. The encryption key should include letters, numbers, and symbols for the best security. - -[!!] **Do not use a hash for the encryption key!** Doing so will make the encryption key much easier to crack. - -# Configuration Files {#config-files} - -Configuration files are slightly different from other files within the [cascading filesystem](about.filesystem) in that they are **merged** rather than overloaded. This means that all configuration files with the same file path are combined to produce the final configuration. The end result is that you can overload *individual* settings rather than duplicating an entire file. - -Configuration files are plain PHP files, stored in the `config/` directory, which return an associative array: - - 'value', - 'options' => array( - 'foo' => 'bar', - ), - ); - -If the above configuration file was called `myconf.php`, you could access 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; - -Please note that you can only access the top level of keys as object properties, all child keys must be accessed using standard array syntax: - - $foo = Kohana::config('myconf')->options['foo']; diff --git a/includes/kohana/modules/userguide/guide/using.messages.md b/includes/kohana/modules/userguide/guide/using.messages.md deleted file mode 100644 index 896daede..00000000 --- a/includes/kohana/modules/userguide/guide/using.messages.md +++ /dev/null @@ -1,26 +0,0 @@ -# Message Basics - -Kohana messages are human friendly strings represented by a shorter word or phrase, called a "key". Messages are accessed using the [Kohana::message] method, which returns either an entire group of messages, or a single message. - -As an example, when a user is not logged in and attempts to access a page that requires authentication, an error such as "You must be logged in to access this page" might be displayed. This message could be stored in the `auth` file with a `must_login` key: - - $message = Kohana::message('auth', 'must_login'); - -Messages are not translated. To translate a message, use the [translation function](using.translation): - - $translated = __(Kohana::message('auth', 'must_login')); - -[!!] In Kohana v2, the message system was used for translation. However, it is highly recommended to use the new translation system instead of messages, as it provides readable text even when a translation is not available. - -## Message Files - -All message files are plain PHP files, stored in the `messages/` directory, that return an associative array: - - 'You must login to access this page', - 'no_access' => 'You do not have privileges to access this page', - ); - -Message files are similar to [config files](using.configuration#config-files) in that they are merged together. This means that all of the messages stored in a file called `auth` will be combined into a single array, so it is not necessary to duplicate all of the messages when you create a new `auth` file. diff --git a/includes/kohana/modules/userguide/guide/zh-cn/about.conventions.md b/includes/kohana/modules/userguide/guide/zh-cn/about.conventions.md deleted file mode 100644 index e0d360c1..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/about.conventions.md +++ /dev/null @@ -1,303 +0,0 @@ -# 约定 - -鼓励大家遵循 Kohana 的编码样式,Kohana 基于 [BSD/Allman style](http://en.wikipedia.org/wiki/Indent_style#BSD.2FAllman_style) 的编码样式(这里还有一些更多[关于 Kohana 编码样式的描述](http://dev.kohanaframework.org/wiki/kohana2/CodingStyle)) - -## 类名和文件位置 {#classes} - -在 Kohana 系统中类名严格遵循命名约定才能够[自动加载](using.autoloading)。类名的首字母必须大写,且使用下划线连接单词,千万要注意下划线的重要性,因为它直接关系到文件在文件系统中所存放的位置。 - -请遵循以下约定: - -1. 类名不允许使用骆驼命名法,除非需要创建新一级的目录文件。 -2. 所有的类文件的文件名和目录名都必须是小写。 -3. 所有的类文件都应该存放在 `classes` 目录下面,它可以是在[级联文件系统](about.filesystem)的任何一级。 - -[!!] 不像 Kohana v2.x,这里不再区分 "controllers","models","libraries" 和 "helpers" 文件夹。所有的类都存放在 "classes/" 目录,既可以是完全静态的 辅助函数("helpers")或对象形式的类库("libraries")。你可以使用任意形式的设计模式的类库:静态,单例,适配器等。 - -## 实例 - -请大家记着一点在类文件中,类名到下划线意味着是一个新的目录,参考下面例子: - -类名 | 文件路径 -----------------------|------------------------------- -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} - -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. - -### 命名约定 - -Kohana 使用下划线连接命名,而不是驼峰命名。 - -#### 类 - - // 库,使用 _Core 作后缀 - class Beer_Core { - - // 库的继承不需要使用后缀 - class Beer extends Beer_Core - - // 控制器类,使用 _Controller 作后缀 - class Apple_Controller extends Controller { - - // 模型类,使用 _Model 作后缀 - class Cheese_Model extends Model { - - // 辅助类 - class peanut { - -当你实例化一个不需要附带参数的类时不需要使用圆括号: - - // 正确: - $db = new Database; - - // 错误: - $db = new Database(); - -#### 函数和方法 - -函数尽量全小写,并使用下划线分割单词: - - function drink_beverage($beverage) - { - -#### 变量 - -所有变量尽量全小写,并使用下划线分割单词而不是驼峰: - - // 正确: - $foo = 'bar'; - $long_example = 'uses underscores'; - - // 错误: - $weDontWantThis = 'understood?'; - -### 缩进 - -代码在逻辑上缩进使用制表符(TAB)代替空格。 - -垂直间距(即多行)使用空格。制表符并不适用于垂直间距主要是因为不同的人可能设置类不同的制表符宽度。 - - $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.'; - -### 字符串连接 - -不要在连接符左右使用空格: - - // 正确: - $str = 'one'.$var.'two'; - - // 错误: - $str = 'one'. $var .'two'; - $str = 'one' . $var . 'two'; - -### 单行表达式 - -单行 IF 表达式仅用于破坏正常执行的情况(比如,return 或 continue): - - // 可接受: - if ($foo == $bar) - return $foo; - - if ($foo == $bar) - continue; - - if ($foo == $bar) - break; - - if ($foo == $bar) - throw new Exception('You screwed up!'); - - // 不可接受: - if ($baz == $bun) - $baz = $bar + 2; - -### 比较操作 - -使用 OR 和 AND 作为比较符: - - // 正确: - if (($foo AND $bar) OR ($b AND $c)) - - // 错误: - if (($foo && $bar) || ($b && $c)) - -if/else Blocks - -使用 elseif 而不是 else if: - - // 正确: - elseif ($bar) - - // 错误: - else if($bar) - -### Switch 结构 - -每个 case,break 和 default 都应该是独立的一行。每个 case 或 default 里面必须使用一个制表符(TAB)。 - - switch ($var) - { - case 'bar': - case 'foo': - echo 'hello'; - break; - case 1: - echo 'one'; - break; - default: - echo 'bye'; - break; - } - -### 括号 - -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. - - // 正确: - if ($foo == $bar) - if ( ! $foo) - - // 错误: - if($foo == $bar) - if(!$foo) - if ((int) $foo) - if ( $foo == $bar ) - if (! $foo) - -### 三元操作 - -所有的三元操作都应该遵循一种标准格式。表达式左右使用括号,而变量则不需要。 - - $foo = ($bar == $foo) ? $foo : $bar; - $foo = $bar ? $foo : $bar; - -所有的比较和操作都必须使用括号括起来作为一个组: - - $foo = ($bar > 5) ? ($bar + $foo) : strlen($bar); - -分离复杂的三元操作(三元的第一部分超过了 80 个字符)为多行形式。spaces should be used to line up operators, which should be at the front of the successive lines: - - $foo = ($bar == $foo) - ? $foo - : $bar; - -### 强制类型转换 - -强制类型转换需要在两边使用空格: - - // 正确: - $foo = (string) $bar; - if ( (string) $bar) - - // 错误: - $foo = (string)$bar; - -如果可能,请使用强制类型转换,而不是三元操作: - - // 正确: - $foo = (bool) $bar; - - // 错误: - $foo = ($bar == TRUE) ? TRUE : FALSE; - -如果强制类型转换整形(int)或布尔型(boolean),请使用短格式: - - // 正确: - $foo = (int) $bar; - $foo = (bool) $bar; - - // 错误: - $foo = (integer) $bar; - $foo = (boolean) $bar; - -### 常量 - -常量尽量使用全大写: - - // 正确: - define('MY_CONSTANT', 'my_value'); - $a = TRUE; - $b = NULL; - - // 错误: - define('MyConstant', 'my_value'); - $a = True; - $b = null; - -请把常量放在比较符号的末端: - - // 正确: - if ($foo !== FALSE) - - // 错误: - if (FALSE !== $foo) - -这是一个略有争议的选择,所以我会解释其理由。如果我们用简单的英语写前面的例子中,正确的例子如下: - - if variable $foo is not exactly FALSE - -但是错误的例子可以理解为: - - if FALSE is not exactly variable $foo - -由于我们是从左向右读,因此把常量放在第一位根本没有意义。 - -### 注解 - -#### 单行注解 - -单行注解使用 //,或许你在使用下面几种注解方式。请在注解符后面保留一个空格在添加注解。坚决不能使用 #。 - - // 正确 - - //错误 - // 错误 - # 错误 - -### 正则表达式 - -如果编码中使用到正则表达式,请尽量使用 PCRE 风格而不是 POSIX 风格。相比较而言 PCRE 风格更为强大,速度更快。 - - // 正确: - if (preg_match('/abc/i'), $str) - - // 错误: - if (eregi('abc', $str)) - -正则表达式使用单引号括起来而不是双引号。单引号的字符串简单而且解析起来更快。 -Unlike double-quoted strings they don't support variable interpolation -nor integrated backslash sequences like \n or \t, etc. - - // 正确: - preg_match('/abc/', $str); - - // 错误: - preg_match("/abc/", $str); - -当需要使用正则搜索活替换时,请使用 $n 符号作反向引用,它的效率优于 \\n。 - - // 正确: - preg_replace('/(\d+) dollar/', '$1 euro', $str); - - // 错误: - preg_replace('/(\d+) dollar/', '\\1 euro', $str); - -最后,请注意如果使用 $ 符号匹配字符串末尾是否允许后换行符的话,如果需要可以附加 D 修饰符解决此问题。[更多详情](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 diff --git a/includes/kohana/modules/userguide/guide/zh-cn/about.filesystem.md b/includes/kohana/modules/userguide/guide/zh-cn/about.filesystem.md deleted file mode 100644 index 72793ecc..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/about.filesystem.md +++ /dev/null @@ -1,75 +0,0 @@ -# 级联文件系统 - -Kohana 文件系统单一的目录结构。 -当使用 [Kohana::find_file] 加载一个文件时,系统会以下顺序搜索: - -Application 路径 -: 在 `index.php` 文件中常量被定义为 `APPPATH`,默认值是 `application`。 - -Module 路径 -: 这是在 `APPPATH/bootstrap.php` 文件中使用 [Kohana::modules] 设置的一组数组。 - 数组的每个值都会按照顺序搜索并添加进来。 - -System 路径 -: 在 `index.php` 文件中常量被定义为 `SYSPATH`。默认值是 `system`。 -所有 “core” 核心文件和类文件都在这里定义。 - -目录中的文件包含了优先顺序建立的从高到低的优先级,这就有可能使得具有"高等级"目录的同名文件的会重载任何可以低于它的文件内容。 - -![级联文件系统示意图](img/cascading_filesystem.png) - -如果在 `APPPATH/views` 目录和 `APPPATH/views` 目录均有一个名为 `welcome.php` 视图文件, -当 `welcome.php` 被加载的时候由于 application 目录在文件系统的最上面所以只有它会被返回。 - -## 文件类型 - -目录的级别从高到低依次是 application,module 和 system 路径,分别都有下面的目录结构: - -classes/ -: 所有你想要 [autoload](using.autoloading) 的类库均保存在这里。 - 本目录包含了控制器,模型和其他类库。所有的库文件都必须遵循[类的命名规则](about.conventions#classes)。 - -config/ -: 配置文件是使用 [Kohana::config] 返回的数组项。 - 详情请查阅[配置的用法](using.configuration)。 - -i18n/ -: 多语言文件返回的包各国语言的字符串数组。多语言是使用 `__()` 方法实现。 - 如果想把 "Hello, world" 多语言化,只需要调用 `__('Hello, world!')` 并设置 - [I18n::$lang] 为 "zh-cn"。 - 详情请查阅[多语言的用法](using.translation)。 - -messages/ -: 消息文件是使用 [Kohana::message] 返回的字符串数组。消息和 i18n 文件唯一不同的就是无法多语言化, - 但是总是携程默认语言并通过单键引用。 - 详情请查阅[消息的用法](using.messages)。 - -views/ -: 视图是标准的 PHP 文件被用于生成 HTML。视图文件被加载到 [View] 对象中并得到变量的设置, - 最后在转换为 HTML 片段或其他输出。多个视图可以相互引用。 - 详情请查阅[视图的用法](using.views)。 - -## 查找文件 - -使用 [Kohana::find_file] 方法可以找到在文件系统中任意路径下的文件: - - // 查询的路径 "classes/cookie.php" - $path = Kohana::find_file('classes', 'cookie'); - - // 查询的路径 "views/user/login.php" - $path = Kohana::find_file('views', 'user/login'); - - -## 第三方扩展 - -调用扩展并非限定在 Kohana 。 -比如,如果你想使用 [DOMPDF](http://code.google.com/p/dompdf), -只需把他复制到 `application/vendor/dompdf` 并加载 DOMPDF 的自动加载类: - - require Kohana::find_file('vendor', 'dompdf/dompdf/dompdf_config.inc'); - -现在无需再加载任何文件就可以使用 DOMPDF: - - $pdf = new DOMPDF; - -[!!] 如果你想使用 DOMPDF 转换试图到 PDFs,可以试试 [PDFView](http://github.com/shadowhand/pdfview) 扩展。 diff --git a/includes/kohana/modules/userguide/guide/zh-cn/about.flow.md b/includes/kohana/modules/userguide/guide/zh-cn/about.flow.md deleted file mode 100644 index 2c5ddc69..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/about.flow.md +++ /dev/null @@ -1,73 +0,0 @@ -# 请求流程 - -每个应用都遵循同样的流程: - -1. 程序从 `index.php` 文件加载 -2. 设置 application,module 和 system 目录到路径 -3. 设置错误报告的级别 -4. 加载 install.php 文件(如果存在的话) -5. 加载 [Kohana] 类 -6. 加载 `APPPATH/bootstrap.php` 引导文件 -7. 调用 [Kohana::init] 方法初始化错误句柄,缓存和日志设置 -8. 设置 [Kohana_Config] 读取器和 [Kohana_Log] 记录器 -9. 调用 [Kohana::modules] 方法加载激活的模块 - * 模块路径附加到[文件级联系统](about.filesystem). - * 加载模块的 `init.php` 文件(如果存在的话) - * `init.php` 文件可以增强系统环境设置,同时也包括路由 -10. [Route::set] 会被多次调用来定义[程序路由](using.routing) -11. 调用 [Request::instance] 方法来处理请求 - 1. 检测每个路由直到发现匹配的 - 2. 加载控制器实例化并传递请求 - 3. 调用 [Controller::before] 方法 - 4. 调用控制器的方法生成请求的响应 - 5. 调用 [Controller::after] 方法 - * 当使用 [HMVC sub-requests](about.mvc) 时以上五步会多次循环调用 -12. 显示 [Request] 响应 - -## index.php - -Kohana 遵循[前端控制器]模式,因此所有的请求都要发送到 `index.php` 文件。这样就可以允许保持一个非常整洁的[文件系统](about.filesystem)设计。在 `index.php` 文件中有一些非常重要而又基础的配置变量。你可以改变 `$application`,`$modules` 和 `$system` 的路径以及设置错误报告级别。 - -`$application` 变量让目录包含着你的程序文件。默认情况下,就是 `application` 目录。`$modules` 变量让目录包含着你的扩展文件。默认情况下。`$system` 变量让目录包含着默认的 Kohana 文件。默认情况下。 - -你可以移动下面三个目录到任意路径。假如你的目录结构是: - - www/ - index.php - application/ - modules/ - system/ - -你想转移这些目录到 web 目录以外: - - application/ - modules/ - system/ - www/ - index.php - -那么你应该在 `index.php` 文件改变下面变量的配置: - - $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. - -### 错误报告 - -默认情况下,Kohana显示所有错误,包括严格的警告。 - - error_reporting(E_ALL | E_STRICT); - -对于已经上线并在运行的程序,一个保守的推荐,可以忽略掉提醒: - - error_reporting(E_ALL & ~E_NOTICE); - -如果在错误被触发后得到的是一个空白的结果,你的服务器可能关闭了错误提示。你可以在 `error_reporting` 调用前使用下面的代码开启错误提醒: - - ini_set('display_errors', TRUE); - -在发送错误提示时,错误应该**实时**显示,甚至是在上线发布之后,因为它允许你使用[异常和错误句柄](debugging.errors) 指引到一个友好的错误页面从而代替空白的页面。 diff --git a/includes/kohana/modules/userguide/guide/zh-cn/about.install.md b/includes/kohana/modules/userguide/guide/zh-cn/about.install.md deleted file mode 100644 index a7c10b30..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/about.install.md +++ /dev/null @@ -1,95 +0,0 @@ -# 系统安装 - -1. 从 [Kohana 官方网站](http://kohanaframework.org/)下载最新**稳定**版本的框架 -2. 创建一个名为 'kohana' 的目录并解压缩到这个目录 -3. 上传到这个目录的所有文件到你的服务器上 -4. 编辑 `application/bootstrap.php` 文件并按实际情况修改下面配置: - - 为你的程序设置默认[时区](http://php.net/timezones) - - 在 [Kohana::init] 方法中设置 `base_url` 的值为 kohana 目录的路径(或域名地址) -6. 确保 `application/cache` 目录和 `application/logs` 目录让服务器可写权限 -7. 在你喜欢的浏览器地址栏中输入 `base_url` 来测试 Kohana 是否安装成功 - -[!!] 根据系统平台的不同,安装的目录可能会随着解压缩而失去原先的权限属性。如果有错误发生请在 Kohana 根目录设定所有文件属性为 755。命令为:`find . -type d -exec chmod 0755 {} \;` - -如果你可以看到安装页面(install.php)则说明已经安装成功(一片绿色),如果它报告有任何的错误(红色显示),你应该在立刻修复。 - -![安装页面](img/install.png "Example of install page") - -一旦安装页面报告你的环境确认无误,并且可以改名或删除在跟目录的 `install.php` 文件,然后你就能看到 Kohana 的欢迎界面: - -![欢迎界面](img/welcome.png "Example of welcome page") - - -## 设置产品(Production)环境 - -在转移到产品环境之前有些事情需要完成: - -1. 查看文档的[配置页面](about.configuration)。 - 它涵盖了大多数的环境全局设置。 - 一般来讲,在产品环境下需要开启缓存并关闭概况分析(profiling)([Kohana::init] 设置)。 - 如果设置了很多路由,路由缓存也是很有必要的。 -2. 在 application/bootstrap.php 捕获所有的异常,已保证敏感信息不会被堆栈跟踪泄漏。 - 下面有一个从 Shadowhand 的 wingsc.com 网站源代码提取出来的样例。 -3. 打开 APC 或某些类型的指令缓存。 - 这是最简单容易的提升 PHP 自身性能的方法。程序越复杂,使用指令缓存带来越大的利益。 - - /** - * Set the environment string by the domain (defaults to '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 == '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; - diff --git a/includes/kohana/modules/userguide/guide/zh-cn/about.kohana.md b/includes/kohana/modules/userguide/guide/zh-cn/about.kohana.md deleted file mode 100644 index dc60b6d5..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/about.kohana.md +++ /dev/null @@ -1,15 +0,0 @@ -# 什么是 Kohana? - -Kohana 是由志愿者团队开发的一个开源形式使用 [PHP5](http://php.net/manual/intro-whatis "PHP Hypertext Preprocessor") 开发的[面对对象](http://wikipedia.org/wiki/Object-Oriented_Programming)模式 [MVC](http://wikipedia.org/wiki/Model–View–Controller "Model View Controller") 架构的 [Web 框架](http://wikipedia.org/wiki/Web_Framework)。它目标旨在快速开发,高安全性,轻量级代码。 - -[!!] Kohana 是基于 [BSD license](http://kohanaframework.org/license) 发布,所以大家可以用它开发任何的开源形式的,公司形式的或者个人形式的应用。 - -## Kohana 的特点是什么? - -使用独有的 [文件系统](about.filesystem) 设计可以任意继承库类而经可能少的(或不需要)[配置](about.configuration),[错误句柄](debugging.errors)能够在开发过程中迅速定位错误源,并有内置的[调试器](debugging.overview)和[分析器](debugging.profiling)作为辅助开发工具。 - -并且提供为您的应用程序提供安全系数相关的工具:[XSS removal](security.xss),[input validation](security.validation),[signed cookies](security.cookies),[form](security.forms) 和 [HTML](security.html)。于此同时,[数据库](security.database)层提供对 [SQL 注入](http://wikipedia.org/wiki/SQL_Injection)的保护。这是因为所有的官方代码经过精心编写和安全审查的。 - -## 这文档太逊了! - -我们正在全力提供完整的文档。如果你想从问题中找到答案,请查阅[非官方 Wiki](http://kerkness.ca/wiki/doku.php)。如果你想要添加或修改文档的内容,请 [fork](http://github.com/kohana/userguide) 本文档保存后发送 pull 请求。如果你不善于使用 git,你同样可以提交[feature request](http://dev.kohanaframework.org/projects/kohana3/issues)(需要注册)。 diff --git a/includes/kohana/modules/userguide/guide/zh-cn/about.mvc.md b/includes/kohana/modules/userguide/guide/zh-cn/about.mvc.md deleted file mode 100644 index 035b6b19..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/about.mvc.md +++ /dev/null @@ -1,7 +0,0 @@ -# (层次结构)模型 视图 控制器 - -模型 视图 控制器,英文全称为 Model View Controller(缩写 MVC)是一个流行的设计模式,它从呈现/模板(视图)和请求流程(控制器)中分离了数据源(模型)。 - -使用此模式设计开发系统级别的应用程序会更加容易和最大限度的重用代码,这就意味着你不必在写那么多不必要的代码了! - -[!!] Stub diff --git a/includes/kohana/modules/userguide/guide/zh-cn/about.upgrading.md b/includes/kohana/modules/userguide/guide/zh-cn/about.upgrading.md deleted file mode 100644 index 30bc5713..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/about.upgrading.md +++ /dev/null @@ -1,288 +0,0 @@ -# 从 2.3.x 升级 - -Kohana v3 大部分功能都不同于 Kohana 2.3 版本,下面列出了一系列的升级建议: - -## 命名约定 - -在 2.x 体系中不同的类的'类型'(比如 controller,model 等)使用后缀来加以区分。文件夹在模型/控制器目录下没有任何类名的关系。 - -在 3.0 版本中废弃了上面的形式转而使用 Zend framework 的文件体系的约定,也就是类名包含类名和其路径,之间是有下划线分割而不是斜杠符(比如 `/some/class/file.php` 变为了 `Some_Class_File`) -详情请参见 [约定文档](start.conventions) - -## Input 库 - -Input 库已经从 3.0 版本中移除,请使用 `$_GET` 和 `$_POST` 获取。 - -### XSS 保护 - -假如你需要使用 XSS 清除用户输入数据,你可以使用 [Security::xss_clean] 处理输入数据,比如: - - $_POST['description'] = security::xss_clean($_POST['description']); - -你也可以把 [Security::xss_clean] 当作 [Validate] 类的过滤器使用: - - $validation = new Validate($_POST); - - $validate->filter('description', 'Security::xss_clean'); - -### POST & GET - -Input 库有一个最大的方便之处在于如果你试图从一个超全域阵列(superglobal arrays)访问它的值,假若其值不存在 Input 库则会返回一个指定的默认值,比如: - - $_GET = array(); - - // $id 获得的值是 1 - $id = Input::instance()->get('id', 1); - - $_GET['id'] = 25; - - // $id 现在获得的值是 25 - $id = Input::instance()->get('id', 1); - -在 3.0 版本你可以使用 [Arr::get] 方法实现同样的效果: - - $_GET = array(); - - // $id 获得的值是 1 - $id = Arr::get($_GET, 'id', 1); - - $_GET['id'] = 42; - - // $id 现在获得的值是 42 - $id = Arr::get($_GET, 'id', 1); - -## ORM 库 - -自 2.3 版本到现在已经有一些主要的改动,下面是常见的通用升级问题: - -### 成员变量 - -现在所有的成员变量都添加了 下划线(_) 作为前缀而且无法再通过 `__get()` 方法获得访问权利。相反的你可以把属性名并去掉下划线当作函数去调用。 - -例如,在 2.3 版本中有一个 `loaded` 属性,现在改名为 `_loaded` 并且如果需要在外边类库中访问此属性只需要 `$model->loaded()`。 - -### 关系 - -在 2.3 版本中如果你想要迭代一个模型相关对象的话,你需要: - - foreach($model->{relation_name} as $relation) - -然而,在新的系统中这已经失效。在 2.3 版本中任何使用 Databate 库生成的查询都是在全局作用域生成,这就意味着你不能同时尝试和构建两个查询语句。这里有个例子: - -# TODO: 需要一个具体的实例!!!! - -第二此查询则会失效而不能查询,内部查询将 '继承' 作为第一条件,从而造成混乱。在 3.0 版本中此问题得到了有效的解决,创建每条查询都是其自身的作用域之中,尽管如此,这也意味着有些东西没法按实际的预期正常工作。这里有个例子: - - foreach(ORM::factory('user', 3)->where('post_date', '>', time() - (3600 * 24))->posts as $post) - { - echo $post->title; - } - -[!!] (相关新的查询语法请查看 [Database 教程](tutorials.databases)) - -在 2.3 版本中你希望它可以返回用户为 3 且 `post_date` 在最近 24 小时内发布的所有 posts 的迭代器,然而相反的,它将适用 where 语句到 user 模型中并返回带有指定加入语句的 'Model_Post' 对象。 - -为了达到 2.3 版本的同样效果,你只需要略微修改结构即可: - - foreach(ORM::factory('user', 3)->posts->where('post_date', '>', time() - (36000 * 24))->find_all() as $post) - { - echo $post->title; - } - -这同样也应用到 `has_one` 关系中: - - // 错误 - $user = ORM::factory('post', 42)->author; - // 正确 - $user = ORM::factory('post', 42)->author->find(); - -### Has and belongs to many relationships - -在 2.3 版本中你可以设置 `has_and_belongs_to_many` 关系。但是在 3.0 版本此功能已经融合到了 `has_many` *through*。 - -在你的模型中定义一个 `has_many` 关系到其他模型中,并且添加一个 `'through' => 'table'` 属性,其中 `'table'` 是连接表的名称。比如(posts<>categories): - - $_has_many = array - ( - 'categories' => array - ( - 'model' => 'category', // 外部模型 - 'through' => 'post_categories' // 连接表 - ), - ); - -如果你的数据库配置设置了表前缀,这也不用担心去添加表前缀。 - -### 外键 - -如果你想在 2.x 版本的 ORM 中覆写一个外键,你必须指定关系属于谁,并且你的新外键在成员变量 `$foreign_keys` 之中。 - -在 3.0 版本中你只需要在关系数组中定义一个 `foreign_key` 键即可,比如: - - Class Model_Post extends ORM - { - $_belongs_to = array - ( - 'author' => array - ( - 'model' => 'user', - 'foreign_key' => 'user_id', - ), - ); - } - -在上面的实例中我们应该在 posts 表中存在一个 `user_id` 字段。 - - - -In has_many relationships the `far_key` is the field in the through table which links it to the foreign table & the foreign key is the field in the through table which links "this" model's table to the through table. - -考虑以下设定,"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', - ), - ); - } - - -显然,这里的别名设定是有点疯狂,但它是如何让 foreign/far 键很好工作的绝佳范例。 - -### ORM 迭代器 - -`ORM_Iterator` 也是值得注意的改动,它已经融合到了 Database_Result 之中。 - -如果你想要获得带有对象主键的 ORM 对象数组,你只需要调用 [Database_Result::as_array],比如: - - $objects = ORM::factory('user')->find_all()->as_array('id'); - -其中的 `id` 就是 user 表的主键。 - -## Router 库 - -在 2.x 版本中有一个 Router 库用于处理主要的请求工作。它允许你在 `config/routes.php` 配置文件中定义基本的路由,而且它还允许支持自定义的正则表达式路由,尽管如此,如果你想做极端的话它就显得相当呆板。 - -## 路由 - -在 3.0 版本中路由系统(现在成为请求系统)有了更多的灵活度。路由现在全部定义在 bootstrap 文件中(`application/bootstrap.php`)以及模块(Module)的 init.php 文件之中(`modules/module/init.php`)。(另外值得一提的是,现在的路由是按照他们定义的顺序评估) - -替换定义的路由数组,你现在为每个路由创建一个新的 [Route] 对象。不像在 2.x 体系一样没有必要映射一个 uri 到另一个。相反的你使用标记段(比如,controller,method,id)的变量来指定 uri 模式。 - -例如,在老系统的正则: - - $config['([a-z]+)/?(\d+)/?([a-z]*)'] = '$1/$3/$1'; - -需要映射 uri 的 `controller/id/method` 为 `controller/method/id`,在 3.0 版本中这样修改: - - Route::set('reversed','((/(/)))') - ->defaults(array('controller' => 'posts', 'action' => 'index')); - -[!!] 每个 uri 都必须指定一个独一无二的名称(这里定义的是 `reversed`),其背后的原因是解释在 [URL 教程](tutorials.urls) 之中。 - -尖括号的内容会当作动态解析部分。圆括号的内容则会当作是可选或不必要的字段。如果你只是想匹配 uris 的开头是 admin,你只需要: - - Rouse::set('admin', 'admin(/(/(/)))'); - -但,如果你想用户必须指定一个控制器: - - Route::set('admin', 'admin/(/(/))'); - -同样,Kohana 不使用任何的 '默认的默认项'。如果你想让 Kohana 去设置默认 action 为 'index',你只需要使用 [Route::defaults] 设置即可!如果你需要为 uri 字段自定义正则表达式,你只需要以 `segment => regex` 传递数组,比如: - - Route::set('reversed', '((/(/)))', array('id' => '[a-z_]+')) - ->defaults(array('controller' => 'posts', 'action' => 'index')) - -这会迫使 id 的值必须全部是小写字母或者是数字,下划线。 - -### Actions - -还有一点我们必须要提到的,如果控制器中的方法可以通过网址访问,现在被称为 "actions",且其前缀为 'action_'。比如,在上面的例中,如果用户访问 `admin/posts/1/edit`,那么 "actions" 就是 'edit' 而且方法在控制器将会是 `action_edit`。详情请参见 [URL 教程](tutorials.urls) - -## Sessions - -以下方法不再存在:Session::set_flash(),Session::keep_flash() 和 Session::expire_flash() 方法,替代这些废弃方法的函数你可以使用 [Session::get_once]。 - -## URL 辅助函数 - -URL 辅助函数仅做了略微的改动 - `url::redirect()` 方法转移到了 `$this->request->redirect()` 之中(包含控制器)/ `Request::instance()->redirect()` - -`url::current` 现在替换为了 `$this->request->uri()` - -## Valid / Validation - -这恋歌类现在已经合并为一个类并命名为 `Validate`. - -对于校验数组的语法也有些改动: - - $validate = new Validate($_POST); - - // 应用一个过滤器到所有数组项中 - $validate->filter(TRUE, 'trim'); - - // 定义规则使用 rule() 方法 - $validate - ->rule('field', 'not_empty') - ->rule('field', 'matches', array('another_field')); - - // 为单字段设置多个规则也使用 rules() 方法,以 rules => params 的数组方式作为第二参数 - $validate->rules('field', array( - 'not_empty' => NULL, - 'matches' => array('another_field') - )); - -为保证定义明确,其中 'required' 规则现已经改名为 'not_empty'。 - -## View 库 - -对于 View 库也有一些值得注意的主要改动。 - -在 2.3 版本中视图在其处理的控制器中调用呈现,并允许你使用 `$this` 作为视图应用引用到控制器中。这一点在 3.0 版本改变了。视图现在呈现在一个空白的作用域,如果你需要在视图中使用 `$this`,你可以使用 [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. 推荐的方法是像下面这样去传递必备的变量到视图中: - - $view = View::factory('my/view'); - - $view->variable = $this->property; - - // 或者如果你想使用连接方式 - - $view - ->set('variable', $this->property) - ->set('another_variable', 42); - - // 不推荐 - $view->bind('this', $this); - -因为视图在一个空的作用域呈现,而 `Controller::_kohana_load_view` 现在是多余的了。如果你想在它呈现之前修改视图(比如,添加一个站点的菜单),你可以使用 [Controller::after] - - Class Controller_Hello extends Controller_Template - { - function after() - { - $this->template->menu = '...'; - - return parent::after(); - } - } diff --git a/includes/kohana/modules/userguide/guide/zh-cn/debugging.code.md b/includes/kohana/modules/userguide/guide/zh-cn/debugging.code.md deleted file mode 100644 index b6105225..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/debugging.code.md +++ /dev/null @@ -1,18 +0,0 @@ -# 调试 - -Kohana 默认加载一些功能强大的功能来辅助调试程序。 - -最常使用也是最基本的 [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 也提供一个方法 [Kohana::debug_source] 来显示特定文件的源代码。 - - // 显示当前行的源代码 - echo Kohana::debug_source(__FILE__, __LINE__); - -如果你希望显示你应用文件的信息而不泄漏安装路径,你可以使用[Kohana::debug_path]: - - // 显示 "APPPATH/cache" 而不是真实路径 - echo Kohana::debug_path(APPPATH.'cache'); diff --git a/includes/kohana/modules/userguide/guide/zh-cn/debugging.errors.md b/includes/kohana/modules/userguide/guide/zh-cn/debugging.errors.md deleted file mode 100644 index 0cf6d963..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/debugging.errors.md +++ /dev/null @@ -1,22 +0,0 @@ -# 错误/异常句柄 - -Kohana 同时提供了异常句柄和错误句柄使用 PHP 的 [ErrorException](http://php.net/errorexception) 类转换错误为异常。关于错误的详情和通过句柄显示应用程序的内部状态: - -1. Exception 类 -2. 错误等级 -3. 错误信息 -4. 带有行高亮的错误源 -5. 执行流程的[调试跟踪](http://php.net/debug_backtrace) -6. 导入(include)文件,加载扩展,全局变量 - -## 实例 - -点击任何一个链接可以切换显示额外的信息: - -
        {{userguide/examples/error}}
        - -## 显示错误/异常句柄 - -如果您不希望使用内部错误句柄,您可以调用 [Kohana::init] 时禁用它: - - Kohana::init(array('errors' => FALSE)); diff --git a/includes/kohana/modules/userguide/guide/zh-cn/debugging.profiling.md b/includes/kohana/modules/userguide/guide/zh-cn/debugging.profiling.md deleted file mode 100644 index 95ebe61a..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/debugging.profiling.md +++ /dev/null @@ -1,20 +0,0 @@ -# 分析器 - -Kohana 提供一种非常简单的方法来显示你的程序的统计信息 - -1. 普通 [Kohana] 方法调用 -2. 请求 -3. [Database] 查询 -4. 程序的平均运行时间 - -## 实例 - -你可以在任何时候显示或收集当前 [profiler] 统计: - -
        - -
        - -## 预览 - -{{profiler/stats}} \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/zh-cn/features.md b/includes/kohana/modules/userguide/guide/zh-cn/features.md deleted file mode 100644 index 4f7e05e5..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/features.md +++ /dev/null @@ -1 +0,0 @@ -本页面将会列举 Kohana v3 的特性。 \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/zh-cn/menu.md b/includes/kohana/modules/userguide/guide/zh-cn/menu.md deleted file mode 100644 index 7de47433..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/menu.md +++ /dev/null @@ -1,31 +0,0 @@ -1. **入门指南** - - [什么是 Kohana?](about.kohana) - - [约定和样式](about.conventions) - - [模型-视图-控制器](about.mvc) - - [级联文件系统](about.filesystem) - - [请求流程](about.flow) - - [安装](about.install) - - [升级](about.upgrading) - - [API 浏览器](api) -3. **基本使用** - - [配置](using.configuration) - - [类的加载](using.autoloading) - - [视图和 HTML](using.views) - - [Sessions 和 Cookies](using.sessions) - - [消息](using.messages) -6. **调试** - - [代码](debugging.code) - - [错误句柄](debugging.errors) - - [分析器](debugging.profiling) -5. **安全** - - [XSS](security.xss) - - [校验](security.validation) - - [Cookies](security.cookies) - - [数据库](security.database) -4. **教程** - - [Hello, World](tutorials.helloworld) - - [路由,URLs 和链接](tutorials.urls) - - [清理 URLs](tutorials.removeindex) - - [数据库](tutorials.databases) - - [ORM](tutorials.orm) - - [使用 Git 开发](tutorials.git) diff --git a/includes/kohana/modules/userguide/guide/zh-cn/security.validation.md b/includes/kohana/modules/userguide/guide/zh-cn/security.validation.md deleted file mode 100644 index 796e956d..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/security.validation.md +++ /dev/null @@ -1,244 +0,0 @@ -# 效验 - -使用 [Validate] 类可以对任意的数组进行校验。标签,过滤器,规则和回调函数都以数组的键(称之为 "字段名")附属于 Validate 对象。 - -标签(labels) -: 标签是人们可读取的字段名。 - -过滤器(filters) -: 过滤器必须在规则和回调函数之前调用执行做预处理。 - -规则(rules) -: 规则是用于检测字段并返回结果 `TRUE` 或 `FALSE`。 - 如果返回 `FALSE`,其对于的错误会添加到字段中。 - -回调函数(callbacks) -: 回调函数是自定义函数,它可以访问整个校验对象。 - 回调函数的返回值会被忽略,因此,当校验错误时回调函数必须手动的使用 [Validate::error] 添加错误到对象中。 - -[!!] 注意 [Validate] 的 callbacks 和 [PHP callbacks](http://php.net/manual/language.pseudo-types.php#language.types.callback) 是完全不同的两个方法。 - -如果想把添加的过滤器,规则或回调函数应用到所有的定义的字段需要设置字段名为 `TRUE` 。 - -**[Validate] 对象会移除所有未设置标签,过滤器,规则或回调函数的字段。以此防止未被验证的字段发生校验错误。** - -使用 [Validate::factory] 方法创建校验对象: - - $post = Validate::factory($_POST); - -[!!] 提示 `$post` 对象将会被用于本教程的其他实例中。 - -### 默认规则 - -校验默认提供的规则: - -规则名称 | 函数 -------------------------- |------------------------------------------------- -[Validate::not_empty] | 值不能为空值 -[Validate::regex] | 值使用正则表达式匹配 -[Validate::min_length] | 值的最小长度 -[Validate::max_length] | 值的最大长度 -[Validate::exact_length] | 值的长度必须是这里指定的长度 -[Validate::email] | 值必须是 Email 地址 -[Validate::email_domain] | 检查 Email 的域是否存在 -[Validate::url] | 值必须是 URL -[Validate::ip] | 值必须是 IP 地址 -[Validate::phone] | 值必须是电话号码 -[Validate::credit_card] | 值必须是信用卡号 -[Validate::date] | 值必须是日期(时间) -[Validate::alpha] | 仅允许英文字母 -[Validate::alpha_dash] | 仅允许英文字母和连词符号(-) -[Validate::alpha_numeric] | 仅允许英文字母和数字 -[Validate::digit] | 仅允许整数 -[Validate::decimal] | 值必须是小数或浮点数 -[Validate::numeric] | 仅允许数字 -[Validate::range] | 值必须是某一范围内的值 -[Validate::color] | 值必须是有效的 HEX 颜色 -[Validate::matches] | 值必须匹配其他字段的值 - -[!!] 任何存在于 [Validate] 类中的方法都可以在不指定完整回调的情况下用于校验规则。 -比如,添加 `'not_empty'` 和 `array('Validate', 'not_empty')` 是等同的。 - -## 添加过滤器 - -所有的校验规则被定义为字段名,方法或函数(使用 [PHP callback](http://php.net/callback) 语法)以及数组形式的参数: - - $object->filter($field, $callback, $parameter); - -过滤器修改字段值之前请仔细检查规则或回调函数。 - -如果要转换 "username" 字段的值为全小写: - - $post->filter('username', 'strtolower'); - -如果要对所有字段移除左右*所有*空格: - - $post->filter(TRUE, 'trim'); - -## 添加规则 - -所有的校验规则被定义为字段名,方法或函数(使用 [PHP callback](http://php.net/callback) 语法)以及数组形式的参数: - - $object->rule($field, $callback, $parameter); - -### 实例 - -任何函数添加到 `Validate` 类都可以通过调用一个规则而不必指定 `Validate` 类: - - $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'); - -任何 PHP 可用的函数也可以当作规则。比如,如果我们要检测用户是否使用 SSL: - - $post->rule('use_ssl', 'in_array', array(array('yes', 'no'))); - -[!!] 注意:所有的参数类数组都必须在一个数组内! - -所有其他自定义的规则也可以作为回调函数添加进来: - - $post->rule('username', array($model, 'unique_username')); - -回调方法 `$model->unique_username()` 的代码如下: - - public function unique_username($username) - { - // 检测用户名是否存在于数据库 - return ! DB::select(array(DB::expr('COUNT(username)'), 'total')) - ->from('users') - ->where('username', '=', $username) - ->execute() - ->get('total'); - } - -[!!] 自定义规则可以设置许多额外的检测以可用于多种用途。这些方法运行存在于一个模型(model)中,或者是定义在任意一个类中。 - -## 添加回调函数 - -所有的校验规则被定义为字段名,方法或函数(使用 [PHP callback](http://php.net/callback) 语法)以及数组形式的参数: - - $object->callback($field, $callback); - -[!!] 不同的过滤器和规则,没有参数也可以传递到回调函数之中。 - -如果用户的密码必须是哈希值,我们可以使用回调函数哈希其值: - - $post->callback('password', array($model, 'hash_password')); - -假设 `$model->hash_password()` 方法是类似这样定义的: - - public function hash_password(Validate $array, $field) - { - if ($array[$field]) - { - // 如果存在此字段进行哈希操作 - $array[$field] = sha1($array[$field]); - } - } - -# 一个完整的例子 - -首先,我们使用 [View] 创建一个 HTML 表单。假设文件存放于 `application/views/user/register.php`: - - - -

        操作发生问题,请仔细检查并保证填写正确。

        -
          - -
        • - - - -
          -
          -
          - -
          -
          -
          密码必须保证至少六位字符
          -
          -
          - -
          -
          '总是使用 SSL', 'no' => '仅当需要的时候'), $post['use_ssl']) ?>
          -
          鉴于安全起见,SSL 一般用于支付时使用
          -
          - - - - -[!!] 本例子我们使用了 [Form] 辅助函数生成表单。使用 [Form] 从而代替手写 HTML 代码的好处在于所有输入项都会严格处理。 -如果你喜欢手写 HTML,那请记得使用 [HTML::chars] 方法来转移用户输入。 - -接下来,我们开始编写控制器的代码来处理注册过程。假设文件存放于 `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()) - { - // 确保数据都通过了校验后执行注册用户 - $user->register($post); - - // 通常在注册成功后会调整到登录前的页面 - URL::redirect('user/profile'); - } - - // 校验失败,获得错误提示 - $errors = $post->errors('user'); - - // 显示用户注册的表单 - $this->request->response = View::factory('user/register') - ->bind('post', $post) - ->bind('errors', $errors); - } - - } - -另外我们还需要有一个 user 模型,假设文件存放于 `application/classes/model/user.php`: - - class Model_User extends Model { - - public function register($array) - { - // 创建一条新纪录 - $id = DB::insert(array_keys($array)) - ->values($array) - ->execute(); - - // 保存新用户的 id 到 cookie - cookie::set('user', $id); - - return $id; - } - - } - -一个简单的用户注册的例子就这么完成了! diff --git a/includes/kohana/modules/userguide/guide/zh-cn/security.xss.md b/includes/kohana/modules/userguide/guide/zh-cn/security.xss.md deleted file mode 100644 index 1d7da562..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/security.xss.md +++ /dev/null @@ -1,15 +0,0 @@ -# 跨站脚本(XSS)安全 - -首先大家先要了解什么是 [XSS](http://wikipedia.org/wiki/Cross-Site_Scripting) 之后才能更好的保护自己。XSS 只能在 HTML 代码中才能触发,可能通过表单的输入或者从数据库结果显示。任何全局变量包括客户信息都可能被感染。这包括 `$_GET`,`$_POST` 和 `$_COOKIE` 中的数据。 - -## 预防措施 - -这里有一些简单的方法可以预防你的程序不受 XSS 的侵害。第一个方法是使用 [Security::xss] 方法处理所有全局变量的输入数据。如果你不想让变量里有 HTML 代码,你可以使用 [strip_tags](http://php.net/strip_tags) 从值中移除所有的 HTML 标签。 - -[!!] 如果用户提交 HTML 到你的程序之中,最好的推荐方法是使用类似 [HTML Purifier](http://htmlpurifier.org/) 或 [HTML Tidy](http://php.net/tidy) 这样的 HTML 代码清理工具。 - -第二个方法是转义输入的 HTML 代码。[HTML] 类提供生成大多数的标签,其中包括脚本(script)和样式表(stylesheet)链接,超级链接,图片,邮箱(emailto)链接。任何不可信的内容都会使用 [HTML::chars] 去转义。 - -## 参考资料 - -* [OWASP XSS Cheat Sheet](http://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet) diff --git a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.databases.md b/includes/kohana/modules/userguide/guide/zh-cn/tutorials.databases.md deleted file mode 100644 index 4f99eaa3..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.databases.md +++ /dev/null @@ -1,248 +0,0 @@ -# 数据库 {#top} - -Kohana 3.0 采用了更加健壮的模块方式开发。默认情况下数据库模块支持 [MySQL](http://php.net/mysql) 和 [PDO](http://php.net/pdo) 两种驱动方式。 - -默认 Kohana 3.0 中包含了数据库模块,但是使用之前必须在 `application/bootstrap.php` 文件中的 [Kohana::modules] 方法中开启它。 - - Kohana::modules(array( - ... - 'database' => MODPATH.'database', - ... - )); - -## 配置 {#configuration} - -开启模块后接着需要配置数据库,这样才能保证数据库的正常连接。比如说配置文件存放在 `modules/database/config/database.php` 文件中。 - -数据库配置组的结构,我们称之为 "instance",就像下面这个样子: - - 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, - ), - -[!!] 配置文件里可以定义多个 instances 配置组。 - -重点了解一下各项设置的含义。 - -INSTANCE_NAME -: 配置组的名称,任意命名,但是最好保留一个名为 "default" 的默认连接。 - -DATABASE_TYPE -: 数据库驱动类型。Kohana 目前支持 "mysql" 和 "pdo" 两种驱动。 - -CONNECTION_ARRAY -: 配置上述驱动的连接项。(驱动连接项在[下面](#connection_settings)有说明) - -TABLE_PREFIX -: 表前缀,用于通过 [查询器](#query_building) 添加到所有的表名。 - -QUERY_PROFILING -: 开始数据库查询的 [profiling](debugging.profiling)。 - -### 范例 - -范例中共给出了两种 MySQL 连接:一个是本地,一个是远程。 - - 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, - ), - ); - -### 连接设置 {#connection_settings} - -每种数据库驱动的连接方式各有不同。 - -#### MySQL - -在 `connection` 数组中 MySQL 数据库可接受下面选项: - -类型 | 选项 | 描述 | 默认值 -----------|------------|----------------------------| ------------------------- -`string` | hostname | Hostname of the database | `localhost` -`integer` | port | Port number | `NULL` -`string` | socket | UNIX socket | `NULL` -`string` | username | Database username | `NULL` -`string` | password | Database password | `NULL` -`boolean` | persistent | Persistent connections | `FALSE` -`string` | database | Database name | `kohana` - -#### PDO - -在 `connection` 数组中 PDO 数据库可接受下面选项: - -类型 | 选项 | 描述 | 默认值 -----------|------------|----------------------------| ------------------------- -`string` | dsn | PDO data source identifier | `localhost` -`string` | username | Database username | `NULL` -`string` | password | Database password | `NULL` -`boolean` | persistent | Persistent connections | `FALSE` - -[!!] 如果你使用的是 PDO 而且并不确定如何去配置 `dsn` 选项,请查阅 [PDO::__construct](http://php.net/pdo.construct) 的相关资料。 - -## 连接并实例化 {#connections} - -每个配置组都可以当作数据库的实例化对象。每个实例化都是通过调用 [Database::instance] 方法来访问: - - $default = Database::instance(); - $remote = Database::instance('remote'); - -关闭数据库连接的最简单的方法(销毁对象): - - unset($default, Database::$instances['default']); - -如果你想关闭所有数据库的实例化只需: - - Database::$instances = array(); - -## 如何查询 {#making_queries} - -这里共有两种不同的方法进行查询。最简单的一次查询方式是通过 [DB::query] 使用 [Database_Query] 来创建查询。这些查询被称之为 "预处理语句",并且允许设置的查询参数自动的转义。而第二种查询方式是通过方法调用来组建查询。它们都是通过[查询器](#query_building) 完成。 - -[!!] 所有的查询都必须调用 `execute` 方法才能进行运行查询,可接受一个 [Database] 对象或者实例化名称。详情请参见 [Database_Query::execute]。 - -### 预处理语句 - -使用预处理语句可以让你手动编写 SQL 语句的同时还能自动转义查询的值以防止 [SQL 注入](http://wikipedia.org/wiki/SQL_Injection)。首先我们先来一个简单的查询: - - $query = DB::query(Database::SELECT, 'SELECT * FROM users WHERE username = :user'); - -[DB::query] factory 方法为我们创建了一个新的 [Database_Query] 类并允许串连(chaining)。查询语句包含一个 `:user` 参数,这个参数我们可以分配给它一个值: - - $query->param(':user', 'john'); - -[!!] 参数名称可以是任意的可以使用 [strtr](http://php.net/strtr) 替换的字符串。强烈建议**不要**使用美元符号当作参数名以免混淆。 - -如果你想显示 SQL 执行的语句,只需要简单的强制转换对象为字符串即可: - - echo Kohana::debug((string) $query); - // 应该显示: - // SELECT * FROM users WHERE username = 'john' - -如果你想更新 `:user` 参数只需要再次调用 [Database_Query::param] 即可: - - $query->param(':user', $_GET['search']); - -[!!] 如果你想一次设置多个参数,你需要使用 [Database_Query::parameters]。 - -当你分配完毕每个参数之后,你只需要执行下面的方法来执行查询语句: - - $query->execute(); - -使用[变量引用]((http://php.net/language.references.whatdo)) 也可以绑定参数到一个变量中。当多次执行同条语句的时候是非常管用的: - - $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(); - } - -在上面的例子中,变量 `$username` 和 `$password` 在每次使用 `foreach` 语句循环的时候都会改变。如果变量改变了,那么语句中的参数 `:user` 和 `:pass` 也会跟着改变。这种方法使用得当的话是非常节省时间的。 - -### 查询器 {#query_building} - -使用对象和方法动态查询使得查询语句可以以一种不可知论的方法迅速的组建起来。查询器也添加了和值引用一样好的标识符(表和列名)引用。 - -[!!] 目前为止,查询器无法有效的和预处理语句组合。 - -#### SELECT - -每种数据库查询类型都是用过不同的类引用,它们每一个都有自己的方法。比如,创建一个 SELECT 查询,我们需要使用 [DB::select]: - - $query = DB::select()->from('users')->where('username', '=', 'john'); - -默认情况下,[DB::select] 会选择所有的列(`SELECT * ...`),但是你也可以指定返回的某些列: - - $query = DB::select('username', 'password')->from('users')->where('username', '=', 'john'); - -现在让我们花一点时间看看方法是如何串连完成的。首先,我们使用 [DB::select] 方法创建了一个选择对象。接着,我们使用 `from` 方法选择表。最后我们使用 `where` 方法查询一个指定的记录。好了,执行之后我们看看执行了怎么样的一条 SQL 语句,还是老方法,强制转换对象为字符串: - - echo Kohana::debug((string) $query); - // 应该显示: - // SELECT `username`, `password` FROM `users` WHERE `username` = 'john' - -注意列名,表名是如何和值很好的转义啊?这就是使用查询器最重要的好处。 - -查询的时候它也支持 `AS` 方式的别名: - - $query = DB::select(array('username', 'u'), array('password', 'p'))->from('users'); - -生成的 SQL 语句: - - SELECT `username` AS `u`, `password` AS `p` FROM `users` - -#### INSERT - -向数据库插入一条记录,我们使用 [DB::insert] 方法创建一条 INSERT 语句: - - $query = DB::insert('users', array('username', 'password'))->values(array('fred', 'p@5sW0Rd')); - -生成的 SQL 语句: - - INSERT INTO `users` (`username`, `password`) VALUES ('fred', 'p@5sW0Rd') - -#### UPDATE - -更新已存在的记录,我们使用 [DB::update] 方法创建一条 UPDATE 语句: - - $query = DB::update('users')->set(array('username' => 'jane'))->where('username', '=', 'john'); - -生成的 SQL 语句: - - UPDATE `users` SET `username` = 'jane' WHERE `username` = 'john' - -#### DELETE - -删除已存在的记录,我们使用 [DB::delete] 方法创建一条 DELETE 语句: - - $query = DB::delete('users')->where('username', 'IN', array('john', 'jane')); - -生成的 SQL 语句: - - DELETE FROM `users` WHERE `username` IN ('john', 'jane') - -#### 数据库函数 {#database_functions} - -有些时候,你可以会碰到这样的一个情况:当你需要在查询时调用 `COUNT` 或者一些其他数据库自身函数。其实查询器可以通过两种方法支持这些函数。第一种是使用别名引用: - - $query = DB::select(array('COUNT("username")', 'total_users'))->from('users'); - -这看起来十分的相似于 `AS` 别名,但是注意列名是通过双引号括起来的。任何时候一个带有双引号的值出现在列名内部的时候,这部分在双引号内部的引用**仅仅**只能被转义。上面的查询方法生成的 SQL 语句: - - SELECT COUNT(`username`) AS `total_users` FROM `users` - -#### 复杂的表达式 - -别名引用可以解决大部分的问题。但是有时你可能因需要复杂的表达式陷入困境。由于这些原因,你可以使用数据库表达式 [DB::expr] 创建。数据库表达式可以作为直接输入而并不会执行转义。 diff --git a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.git.md b/includes/kohana/modules/userguide/guide/zh-cn/tutorials.git.md deleted file mode 100644 index 65b752e3..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.git.md +++ /dev/null @@ -1,143 +0,0 @@ -# 使用 Git 开发 - -Kohana 使用 [git](http://git-scm.com/) 作为版本控制并托管在 [github](http://github.com/kohana) 网站上面。本教程将会讲解如何让你使用 Git 并从 github 上部署一个简单的应用。 - -## 安装配置 Git - -### 安装 Git - -- OSX: [Git-OSX](http://code.google.com/p/git-osx-installer/) -- Windows: [Msygit](http://code.google.com/p/msysgit/) -- 或者从 [Git 官网](http://git-scm.com/) 下载并手动安装(步骤请参考 Git 官网) - -### 设置全局配置 - - git config --global user.name "你的名字" - git config --global user.email "你的邮箱" - -### 附加偏好设置 - -为了让 git 命令和版本库在命令行达到更好的视觉效果,你可以额外设置: - - git config --global color.diff auto - git config --global color.status auto - git config --global color.branch auto - -### 设置自动补全 - -[!!] 以下步骤仅用于 OSX 机器 - -根据下面步骤一步步执行,全部完成之后自动补全就可以在 git 环境下工作了 - - 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 - -### 总是使用 LF 作为换行符 - -此设置主要用于 Kohana。如果你愿意捐赠代码至社区请遵循此约定。 - - git config --global core.autocrlf input - git config --global core.savecrlf true - -[!!] 关于换行符的更多信息请参见 [github](http://help.github.com/dealing-with-lineendings/) - -### 参考资料 - -- [Git Screencasts](http://www.gitcasts.com/) -- [Git Reference](http://gitref.org/) -- [Pro Git book](http://progit.org/book/) - -## 部署系统结构 - -[!!] 开始本教程前务必保证开发环境以及设置完毕,接下来我们要做一个可以通过 访问的新应用。 - -打开你的控制台(译者:Windows 平台为命令提示符,*nux 平台为终端),创建并切换到 `gitorial` 空目录下面(译者:此目录即为新应用的目录),执行 `git init`。这是为当前目录创建一个新的 git 空版本库。 - -下一步,我们为 `system` 目录要创建一个 [submodule](http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html)(子模块)。访问 页面并复制克隆(Clone) URL: - -![Github Clone URL](http://img.skitch.com/20091019-rud5mmqbf776jwua6hx9nm1n.png) - -现在使用复制后的 URL 去创建 `system` 子模块: - - git submodule add git://github.com/kohana/core.git system - -[!!] 上面的链接是 Kohana 为下一个稳定版本准备的当前的开发版本。开发版本几乎是可以拿来做开发的,他拥有当前稳定版本同样的 API 和一些补丁修复。 - -现在,我们准备添加自己开发所需的子模块。比如你可能需要使用 [Database](http://github.com/kohana/database) 模块: - - git submodule add git://github.com/kohana/database.git modules/database - -添加子模块之后,我们必须让其初始化: - - git submodule init - -子模块我们已经添加完毕,接着我们去提交当前版本: - - git commit -m 'Added initial submodules' - -下一步,创建应用文件结构。下面的是最低要求: - - mkdir -p application/classes/{controller,model} - mkdir -p application/{config,views} - mkdir -m 0777 -p application/{cache,logs} - -如果你执行 `find application` 你应该会看到: - - application - application/cache - application/config - application/classes - application/classes/controller - application/classes/model - application/logs - application/views - -如果我们不想让 git 去追踪日志(log)或者缓存(Cache)文件,我们需要为每个目录添加一个 `.gitignore` 文件。它会忽略所有的非隐藏文件: - - echo '[^.]*' > application/{logs,cache}/.gitignore - -[!!] Git 会忽略空目录,所有我们添加 `.gitignore` 文件以保证 git 会追踪其目录,但是不会追踪目录下面的文件。 - -现在我们还缺 `index.php` 和 `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 - -再次提交: - - git add application - git commit -m 'Added initial directory structure' - -所有的工作都完成了!你现在可以使用 Git 作为版本控制开发 Kohana 应用了。 - -## 更新子模块 - -有时候你可能也需要更新你的子模块。更新所有子模块至最新的 `HEAD` 版本: - - git submodule foreach 'git checkout master && git pull origin master' - -更新单个子模块,比如 `system`: - - cd system - git checkout master - git pull origin master - cd .. - git add system - git commit -m 'Updated system to latest version' - -如果你要更新单个子模块到指定的版本库: - - cd modules/database - git pull origin master - git checkout fbfdea919028b951c23c3d99d2bc1f5bbeda0c0b - cd ../.. - git add database - git commit -m 'Updated database module' - -完成! \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.helloworld.md b/includes/kohana/modules/userguide/guide/zh-cn/tutorials.helloworld.md deleted file mode 100644 index 95590144..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.helloworld.md +++ /dev/null @@ -1,106 +0,0 @@ -# Hello, World - -差不多每个框架提供的教程实例都会包括 Hello,World 这样的例子,于是我们也遵循这样的传统! - -下面我们将要创建一个非常非常基础的 Hello,World,然后我们将它慢慢扩展符合 MVC 架构的样例。 - -## 基础框架 - -首先,我们先要创建一个控制器,让 Kohana 可用于处理请求。 - -在 application 目录下创建 `application/classes/controller/hello.php` 文件并敲入下面代码: - - template->message = 'hello, world!'; - } - } - -`extends Controller_Template` -: 现在我们继承了模板控制器(Template Controller),使用它可以更加方便在控制器中使用视图。 - -`public $template = 'site';` -: 模板控制器需要知道你想要使用什么模板文件。它会自动加载这个变量中定义的视图并返回一个视图对象。 - -`$this->template->message = 'hello, world!';` -: `$this->template` 是我们站点模板的视图对象引用。这里我们分配一个名为 "message" 的变量其值为 "hello, world!" 到视图中。 - -现在让我们尝试运行代码... - -
          {{userguide/examples/hello_world_error}}
          - -出于某种原因 Kohana 会抛出一个不稳定的而没有正常显示我们期望的信息。 - -如果我们仔细查看错误信息,我们可以发现 View 库无法找到我们设定的模板文件,这可能是我们还没有创建它 – *doh*!(译注:doh 表达当发现事情朝坏的、不随人意的方向发展或某人说了傻话、做了蠢事时的情绪低落) - -马上开始创建视图文件 `application/views/site.php`: - - - - We've got a message for you! - - - -

          -

          We just wanted to say it! :)

          - - - -再次刷新刚才的错误页面,怎么样看到正确的结果了吧: - -![hello, world! We just wanted to say it!](img/hello_world_2.png "hello, world! We just wanted to say it!") - -## 第三阶段 – 成果! - -在本教程中你已经学会如何创建和使用控制器,以及使用视图分离逻辑来显示视图。 - -这绝对是一个非常基本教程来介绍如何使用 Kohana 工作,且它根本就不会影响你的潜力使用它来开发应用。 diff --git a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.orm.md b/includes/kohana/modules/userguide/guide/zh-cn/tutorials.orm.md deleted file mode 100644 index 2c418dcb..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.orm.md +++ /dev/null @@ -1,299 +0,0 @@ -# ORM {#top} - -Kohana 3.0 包含一个强劲的 ORM 扩展,作用于记录模式,数据库内省来确定模型的列表。 - -ORM 扩展默认包含在 Kohana 3.0 之中,但是如要使用它则需要先开启它。修改 `application/bootstrap.php` 文件中的 [Kohana::modules] 方法并加载 ORM 扩展: - - Kohana::modules(array( - ... - 'orm' => MODPATH.'orm', - ... - )); - -## 配置 {#configuration} - -通过一些配置 ORM 才能工作。通过在模型类继承 ORM: - - class Model_User extends ORM - { - ... - } - -上面的例子中,模型会寻找默认数据库的 `users` 表。 - -### 模型配置属性 - -下面的属性是用于配置每个模型的: - -类型 | 属性 | 描述 | 默认值 -----------|---------------------|----------------------------------| ------------------------- -`string` | _table_name | 表名 | `singular model name` -`string` | _db | 数据库配置名 | `default` -`string` | _primary_key | 主键 | `id` -`string` | _primary_val | 主键值 | `name` -`bool` | _table_names_plural | 表名是否是复数形式 | `TRUE` -`array` | _sorting | 列名 => 排序方向的数组 | `primary key => ASC` -`string` | _foreign_key_suffix | 外键的后缀 | `_id` - -## 使用 ORM - -### 加载一条记录 - -通过调用 [ORM::factory] 或 [ORM::__construct] 方法创建模型的实例化: - - $user = ORM::factory('user'); - // 或者 - $user = new Model_User(); - -构造函数和 factory 方法也接受一个主键值来加载模型数据: - - // 加载 ID 为 5 的用户 - $user = ORM::factory('user', 5); - - // 检查用户是否加载成功 - if ($user->loaded()) { ... } - -你同样可以使用传递键-值型数组的数据对象去加载记录: - - // 加载 email 为 oe@example.com 的用 - $user = ORM::factory('user', array('email' => 'joe@example.com')); - -### 搜索记录 - -ORM 支持大多数的 [Database] 方法来强劲驱动搜索模型中的数据。ORM 类的 `_db_methods` 属性列出了所有支持调用的方法列表。记录的搜索可以通过 [ORM::find] 和 [ORM::find_all] 方法调用获得。 - - // 搜索活跃用户中名为 Bob 的第一条记录 - $user = ORM::factory('user') - ->where('active', '=', TRUE) - ->where('name', '=', 'Bob') - ->find(); - - // 搜索名为 Bob 的所有用户 - $users = ORM::factory('user') - ... - ->find_all(); - -当你使用 [ORM::find_all] 搜索一批记录模型,你可以使用迭代从数据库结果中获取每条记录模型: - - foreach ($users as $user) - { - ... - } - -ORM 一个强大的特性是 [ORM::as_array] 方法,它把返回的记录集转为为一个数组。如果使用了 [ORM::find_all] 所有的记录都会以数组的形式返回。 -对于选择列的时候是非常好用的: - - // 显示选择列的用户名 (使用 id 作为其值) - form::select('user', ORM::factory('user')->find_all()->as_array('id', 'username') ... - -### 记录数 - -使用 [ORM::count_all] 方法返回查询返回记录集的记录数。 - - // 用户的记录数 - $count = ORM::factory('user')->where('active', '=', TRUE)->count_all(); - -如果你想在特定子集的查询语句中统计所有用户的记录数,在调用 `count_all` 方法之前先调用 [ORM::reset] 方法并赋值 `FALSE`: - - $user = ORM::factory('user'); - - // 用户的总数 (reset FALSE prevents the query object from being cleared) - $count = $user->where('active', '=', TRUE)->reset(FALSE)->count_all(); - - // 仅返回前 10 条记录的记录数 - $users = $user->limit(10)->find_all(); - -### 取出模型属性 - -所有的模型属性都可以通过 PHP 的魔法方法 `__get` 和 `__set` 得到读写权。 - - $user = ORM::factory('user', 5); - - // 输出用户名 - echo $user->name; - - // 更改用户名 - $user->name = 'Bob'; - -假如保存的信息/属性并不存在于模型表中,使用 `_ignored_columns` 来忽略数据成员。 - - class Model_User extends ORM - { - ... - protected $_ignored_columns = array('field1', 'field2', ...) - ... - } - -使用 [ORM::values] 方法设置键-值型数组: - - $user->values(array('username' => 'Joe', 'password' => 'bob')); - -### 创建并存储记录 - -[ORM::save] 方法既可以用于创建新记录也可作用于更新现有记录。 - - // 创建新记录 - $user = ORM::factory('user'); - $user->name = 'New user'; - $user->save(); - - // 更新现有记录 - $user = ORM::factory('user', 5); - $user->name = 'User 2'; - $user->save(); - - // 检查记录是否保存成功 - if ($user->saved()) { ... } - -你也可以使用 [ORM::save_all] 方法来更新多条记录: - - $user = ORM::factory('user'); - $user->name = 'Bob'; - - // 更新所有结果记录的名字为 'Bob' - $user->where('active', '=', TRUE)->save_all(); - -#### 使用 `Updated` 和 `Created` 列 - -`_updated_column` 和 `_created_column` 变量是用于当模型更新或插入新纪录的时候自动更新设置的字段值。默认没有使用。如果你想使用: - - // date_created 列用于储存创建的时间,使用 TRUE 保存的是时间戳(timestamp) - protected $_created_column = array('date_created' => TRUE); - - // date_modified 列用于储存最后修改时间。这里的时间设置为使用 date() 格式后的字符串 - protected $_updated_column = array('date_modified' => 'm/d/Y'); - -### 删除记录 - -删除记录可以使用 [ORM::delete] 和 [ORM::delet_all] 方法。这两个方法的使用和上面 存储记录 方法类似,但有一点不同的是 [ORM::delete] 方法带有一个删除记录 'id' 的可选参数。 - -### 关系 - -ORM 提供强大的关系模型。Ruby 有一篇介绍关系模型的文章: [http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html](http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html) - -#### Belongs-To 和 Has-Many - -假设我们在一所学校工作,当然学校有很多学生,而每个学生都只属于一个学校。这样的关系模型可以这样定义: - - // school 模型文件 - protected $_has_many = array('students' => array()); - - // student 模型文件 - protected $_belongs_to = array('school' => array()); - -获取学生的学校: - - $school = $student->school; - -获取学校的学生: - - // 注意在 studends 后必须调用 find_all 方法 - $students = $school->students->find_all(); - - // 缩小范围查询: - $students = $school->students->where('active', '=', TRUE)->find_all(); - -默认情况下,在 student 表定义的模型文件中 ORM 会寻找 `school_id` 当作外键。这个可以通过 `foreign_key` 属性更改: - - protected $_belongs_to = array('school' => array('foreign_key' => 'schoolID')); - -外键应该同时覆写 student 和 school 模型文件。 - -#### Has-One - -Has-One 是 Has-Many 的一个特别情况,唯一不同的这是一对一关系。还以上面的例子说明就是,每个学校有且只有一个学生(当然这是一个很牵强呃例子)。 - - // school 模型文件 - protected $_has_one = array('student' => array()); - -类似于 Belongs-To,当你引用 Has-One 关系对象的时候无需调用 `find` 方法 - 它是自动完成的。 - -#### Has-Many "Through" - -Has-Many "through" 关系(也可以称之为 Has-And-Belongs-To-Many) is used in the case of one object being related to multiple objects of another type, and visa-versa. For instance, a student may have multiple classes and a class may have multiple students. In this case, a third table and model known as a `pivot` is used. In this case, we will call the pivot object/model `enrollment`. - - // student (学生)模型文件 - protected $_has_many = array('classes' => array('through' => 'enrollment')); - - // class (班级)模型文件 - protected $_has_many = array('students' => array('through' => 'enrollment')); - -其中 enrollment 表包含两个外键: `class_id` 和 `student_id`。在定义关系时,使用 `foreign_key` 和 `far_key` 覆写了默认值。例如: - - // student (学生)模型文件() (the foreign key refers to this model [student], while the far key refers to the other model [class]) - protected $_has_many = array('classes' => array('through' => 'enrollment', 'foreign_key' => 'studentID', 'far_key' => 'classID')); - - // class (班级)模型文件 - protected $_has_many = array('students' => array('through' => 'enrollment', 'foreign_key' => 'classID', 'far_key' => 'studentID')); - -enrollment 模型文件应该这样定义: - - // Enrollment 模型同时属于一个 student 和 class - protected $_belongs_to = array('student' => array(), 'class' => array()); - -获取相关对象: - - // 从 student 中获取 classes - $student->classes->find_all(); - - // 从 class 中获取 students - $class->students->find_all(); - -### 校验 - -ORM 和 [Validate] 类是紧密结合使用的。ORM 提供以下几种校验方式: - -* _rules -* _callbacks -* _filters -* _labels - -#### `_rules` - - protected $_rules = array - ( - 'username' => array('not_empty' => array()), - 'email' => array('not_empty' => array(), 'email' => array()), - ); - -检测并确保 `username` 字段不为空。检测 `email` 字段不为空且是有效的 Email 地址格式。那些传递空值数组用于提供可选的额外参数到校验方法中使用。 - -#### `_callbacks` - - protected $_callbacks = array - ( - 'username' => array('username_unique'), - ); - -`username` 字段被传递到了 `username_unique` 回调函数。如果方法存在于当前模型它就会被调用,否则调用全局函数。下面有个小例子: - - public function username_unique(Validate $data, $field) - { - // 确保 username 是唯一的 - ... - } - -#### `_filters` - - protected $_filters = array - ( - TRUE => array('trim' => array()), - 'username' => array('stripslashes' => array()), - ); - -`TRUE` 值代表 `trim` 过滤器应用到所有字段。而 `username` 字段则在校验前使用 `stripslashes` 过滤。那些传递空值数组用于提供可选的额外参数到校验方法中使用。 - -#### 检测对象是否通过校验 - -使用 [ORM::check] 检测当前对象是否通过校验: - - // 设置完对象的值,接下来检测是否通过校验 - if ($user->values($_POST)->check()) - { - $user->save(); - } - -你也可是使用 `validate()` 方法直接访问模型的校验对象: - - // 手动添加额外的过滤器 - $user->validate()->filter('username', 'trim'); \ No newline at end of file diff --git a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.removeindex.md b/includes/kohana/modules/userguide/guide/zh-cn/tutorials.removeindex.md deleted file mode 100644 index b38119f5..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.removeindex.md +++ /dev/null @@ -1,89 +0,0 @@ -# 从 URL 移除 `index.php` - -为了保持 URLs 的干净,你可能希望 URL 在访问的时候不包含 `/index.php/`。下面有两步可以实现: - -1. 编辑 bootstrap 文件 -2. 设置重写规则 - -# 配置 Bootstrap - -首先你需要在 [Kohana::init] 方法中更改 `index_file` 设置: - - Kohana::init(array( - 'base_url' => '/myapp/', - 'index_file' => FALSE, - )); - -现在所有使用 [URL::site],[URL::base] 和 [HTML::anchor] 生成的 URL均不会包含 "index.php" 了。 - -# URL 重写 - -开启重写配置的方法根据服务器的不同而不同,下面仅供参考: - -## Apache - -改名 `example.htaccess` 为 `.htaccess` 后修改下面的参数代码: - - RewriteBase /kohana/ - -这里需要和 [Kohana::init] 方法中的 `base_url` 选项匹配: - - RewriteBase /myapp/ - -完成了,就这点事! - -### 失败了! - -如果提示 "Internal Server Error" 或 "No input file specified" 错误,请尝试下面的修改: - - RewriteRule ^(?:application|modules|system)\b - [F,L] - -相反,我们可以尝试反斜杠: - - RewriteRule ^(application|modules|system)/ - [F,L] - -如果这样还不工作,再试着修改: - - RewriteRule .* index.php/$0 [PT] - -再简单点: - - RewriteRule .* index.php [PT] - -### 仍然失败! - -如果还是提示失败的话,请确保你的服务器支持 URL 的 `mod_rewrite`。 -加入你可以修改 Apache 的配置,你可以复制下面的配置到 `httpd.conf`: - - - Order allow,deny - Allow from all - AllowOverride All - - -## NGINX - -很难给出 nginx 的配置实例,但是修改其实非常简单: - - location / { - index index.php index.html index.htm; - try_files $uri $uri/ index.php$uri?$args; - } - - location ~ ^(.+\.php)(.*)$ { - fastcgi_split_path_info ^(.+\.php)(.*)$; - fastcgi_param SCRIPT_NAME $fastcgi_script_name; - fastcgi_param SCRIPT_FILENAME $document_root/$fastcgi_script_name; - fastcgi_param PATH_INFO $fastcgi_path_info; - - include fastcgi.conf; - - fastcgi_pass 127.0.0.1:9000; - fastcgi_index index.php; - } - -两点需要注意的是使用 [try_files](http://wiki.nginx.org/NginxHttpCoreModule#try_files) 和 [fastcgi_split_path_info](http://wiki.nginx.org/NginxHttpFcgiModule#fastcgi_split_path_info)。 - -[!!] 以上配置假定你的 PHP 是在端口为 9000 的 FastCGI 服务器,同时 nginx 在 v0.731 以上版本。 - -如果在运行中遇到的问题,请在 nginx 中启用 debug 级别的日志记录并检查 access 和 error 日志。 diff --git a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.urls.md b/includes/kohana/modules/userguide/guide/zh-cn/tutorials.urls.md deleted file mode 100644 index f4360c03..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/tutorials.urls.md +++ /dev/null @@ -1,160 +0,0 @@ -# 路由,URLs 和链接 - -本节讲述了关于 Kohana 的请求路由, URL 生成以及链接的基本使用。 - -## 路由(Routing) - -在上面提到的[请求流程](about.flow)一节中,一个请求通过 [Request] 类来寻找匹配 [Route] 并且加载对应的控制器以执行请求。本系统提供了更大的灵活性以及常规默认行为。 - -如果你查看了 `APPPATH/bootstrap.php` 的代码,你会发现会有包含下面的一段代码,它会在请求处理对在 [Request::instance] 关闭前立即执行。 - - Route::set('default', '((/(/)))') - ->defaults(array( - 'controller' => 'welcome', - 'action' => 'index', - )); - -这是按照 `((/(/)))` 的 uri 格式化的 ‘默认’ 路由设置。其中 *key* 使用 '<>' 括起来,而*可选*部分使用 '()' 括起来。既然是这样,上面的路由设置说明,所有的 uri 都是可选的,所以如果对于一个空的 uri 要匹配,它会去匹配默认的控制器和 action,也就是上面代码将会匹配并加载 `Controller_Welcome` 类,调用 `action_index` 方法以执行请求。 - -需要注意的是,任何的字符都是允许使用 `()<>` 括起来,对于 `/` 并没有特殊含义。在默认路由中 `/` 是被用来当作静态分隔符,但是如果正确的正则表达式是不会限制你如果格式化你的路由。 - -### 目录 - -对于某些原因你可能需要把一些控制器放置在子目录当作。比如这里有一个 amdin 子目录: - - Route::set('admin', 'admin(/(/(/)))') - ->defaults(array( - 'directory' => 'admin', - 'controller' => 'home', - 'action' => 'index', - )); - -该路由规定了 uri 中必须以 `admin` 开头去匹配,并且默认的,这个目录是静态被分配到 `admin`。如果现在有一个请求到 `admin/users/create` 那么它会加载 `Controller_Admin_Users` 类并调用 `action_create` 方法。 - -### 模式 - -Kohana 路由系统使用 perl 正则表达式来处理匹配。默认情况下 key(使用 `<>` 括起来的)只能根据 `[a-zA-Z0-9_]++` 来匹配,但是你可以为每个 key 以数组的形式自定义不同的模式分配到 [Route::set]。继续扩充上面的例子,如果你之前定义了一个 amdin 和 addiliate 段。其实可以使用路由分割或者下面的方式指定它们: - - Route::set('sections', '(/(/(/)))', - array( - 'directory' => '(admin|affiliate)' - )) - ->defaults(array( - 'controller' => 'home', - 'action' => 'index', - )); - -上面的设置同时实现了两个段的路由映射,'admin' 和 'affiliate' 会映射到相对于的目录控制器里但是它会覆盖默认的路由设置。 - -### 更多路由样例 - -这里还有一些其他使用技巧,下面是一些样例: - - /* - * 验证的缩写 - */ - Route::set('auth', '', - array( - 'action' => '(login|logout)' - )) - ->defaults(array( - 'controller' => 'auth' - )); - - /* - * 多样式 feeds - * 452346/comments.rss - * 5373.json - */ - Route::set('feeds', '(/).', - array( - 'user_id' => '\d+', - 'format' => '(rss|atom|json)', - )) - ->defaults(array( - 'controller' => 'feeds', - 'action' => 'status', - )); - - /* - * 静态页面 - */ - Route::set('static', '.html', - array( - 'path' => '[a-zA-Z0-9_/]+', - )) - ->defaults(array( - 'controller' => 'static', - 'action' => 'index', - )); - - /* - * 你不喜欢斜线号?那我们使用冒号分隔。 - * EditGallery:bahamas - * Watch:wakeboarding - */ - Route::set('gallery', '():', - array( - 'controller' => '[A-Z][a-z]++', - 'action' => '[A-Z][a-z]++', - )) - ->defaults(array( - 'controller' => 'Slideshow', - )); - - /* - * 快速搜索 - */ - Route::set('search', ':', array('query' => '.*')) - ->defaults(array( - 'controller' => 'search', - 'action' => 'index', - )); - -路由的匹配是按照顺序指定的所以大家需要知道的是,如果你在加载模块之后设置路由,模块也可以指定路由程序相冲突的路由。如果是因为这个为什么默认路由会在最后设置,所以字段能够以路由的时候最好先做测试。 - -### 请求参数 - -目录,控制器和 action 都可以通过 [Request] 实例化后的两种方式访问: - - $this->request->action; - Request::instance()->action; - -所有其他定义在路由中的键值可以从内控制器中访问: - - $this->request->param('key_name'); - -[Request::param] 方法提供一个可选的第二参数,用于返回默认的没有找到路由设置键值的值。如果没有指定第二参数,返回包含所有键值的数组。 - -### 约定 - -约定适用于自定义的扩展的 `MODPATH//init.php` 文件或者 `APPPATH/bootstrap.php` 文件默认设置的路由。当然,你也可以采用外部加载,甚至是动态加载的方式。 - -## URLs - -随着 Kohana 路由功能的不断强大,加入了一些生成路由 URI 的方法。通常你可能在调用 [URL::site] 方法时指定的字符串来创建完整的 URL: - - URL::site('admin/edit/user/'.$user_id); - -同时,Kohana 也提供另外一种从路由定义生成 URI 的方法。假如能够所以改变的路由的参数从而减轻代码的变更带来的烦恼,这是非常好的替代方法。下面提供一个使用 `feeds` 路由动态生成 URL 的例子: - - Route::get('feeds')->uri(array( - 'user_id' => $user_id, - 'action' => 'comments', - 'format' => 'rss' - )); - -比方说,你今后决定改变 `feeds/(/).` 的路由定义作进一步的设计。 -Let's say you decided later to make that route definition more verbose by changing it to `feeds/(/).`. If you wrote your code with the above uri generation method you wouldn't have to change a single line! When a part of the uri is enclosed in parentheses and specifies a key for which there in no value provided for uri generation and no default value specified in the route, then that part will be removed from the uri. An example of this is the `(/)` part of the default route; this will not be included in the generated uri if an id is not provided. - -[Request::uri] 可能会是你经常使用的方法,它除了上面说明的功能外还可以设定当前的路由,目录,控制器和 actions 的值。如果我们当前的默认路由是 `users/list`,我们可以生成这样的格式 `users/view/$id`: - - $this->request->uri(array('action' => 'view', 'id' => $user_id)); - -或者在视图中,可取的方法: - - Request::instance()->uri(array('action' => 'view', 'id' => $user_id)); - -## 链接 - -[!!] links stub diff --git a/includes/kohana/modules/userguide/guide/zh-cn/using.autoloading.md b/includes/kohana/modules/userguide/guide/zh-cn/using.autoloading.md deleted file mode 100644 index df2f83a0..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/using.autoloading.md +++ /dev/null @@ -1,95 +0,0 @@ -# 类的加载 - -Kohana 需要使用 PHP 自身的[自动加载](http://php.net/manual/language.oop5.autoload.php)。这个消除了不用调用 [include](http://php.net/include) 和 [require](http://php.net/require) 之前就可以使用类文件。例如,让你想使用 [Cookie::set] 方法时,你只需要: - - Cookie::set('mycookie', 'any string value'); - -或者要加载一个 [Encrypt] 的实例化,只需要调用 [Encrypt::instance]: - - $encrypt = Encrypt::instance(); - -类也可以通过 [Kohana::auto_load] 方法加载,这使得从简单的类名称转换为文件名: - -1. 类必须放置在[文件系统](start.filesystem)的 `classes/` 目录 -2. 任何下划线字符转换为斜线 -2. 文件名必须是小写的 - -当调用一个尚未加载类(比如,`Session_Cookie`),通过使用 [Kohana::find_file] 方法可以让 Kohana 搜索文件系统查找名为 `classes/session/cookie.php` 的文件。 - -## 自动加载器 - -在 `application/bootstrap.php` 配置文件默认使用 [spl_autoload_register](http://php.net/spl_autoload_register) 开启了自动加载器。 - - spl_autoload_register(array('Kohana', 'auto_load')); - -在此类第一次使用的时候,这让 [Kohana::auto_load] 尝试去加载任意的不存在类。 - -# Transparent Class Extension {#class-extension} - -The [cascading filesystem](about.filesystem) allows transparent class extension. For instance, the class [Cookie] is defined in `SYSPATH/classes/cookie.php` as: - - class Cookie extends Kohana_Cookie {} - -The default Kohana classes, and many extensions, use this definition so that almost all classes can be extended. You extend any class transparently, by defining your own class in `APPPATH/classes/cookie.php` to add your own methods. - -[!!] You should **never** modify any of the files that are distributed with Kohana. Always make modifications to classes using extensions to prevent upgrade issues. - -For instance, if you wanted to create method that sets encrypted cookies using the [Encrypt] class: - - encode((string) $value); - - parent::set($name, $value, $expiration); - } - - /** - * Gets an encrypted cookie. - * - * @uses Cookie::get - * @uses Encrypt::decode - */ - public static function decrypt($name, $default = NULL) - { - if ($value = parent::get($name, NULL)) - { - $value = Encrypt::instance(Cookie::$encryption)->decode($value); - } - - return isset($value) ? $value : $default; - } - - } // End Cookie - -Now calling `Cookie::encrypt('secret', $data)` will create an encrypted cookie which we can decrypt with `$data = Cookie::decrypt('secret')`. - -## Multiple Levels of Extension {#multiple-extensions} - -If you are extending a Kohana class in a module, you should maintain transparent extensions. Instead of making the [Cookie] extension extend Kohana, you can create `MODPATH/mymod/encrypted/cookie.php`: - - class Encrypted_Cookie extends Kohana_Cookie { - - // Use the same encrypt() and decrypt() methods as above - - } - -And create `MODPATH/mymod/cookie.php`: - - class Cookie extends Encrypted_Cookie {} - -This will still allow users to add their own extension to [Cookie] with your extensions intact. However, the next extension of [Cookie] will have to extend `Encrypted_Cookie` instead of `Kohana_Cookie`. diff --git a/includes/kohana/modules/userguide/guide/zh-cn/using.configuration.md b/includes/kohana/modules/userguide/guide/zh-cn/using.configuration.md deleted file mode 100644 index 0a272412..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/using.configuration.md +++ /dev/null @@ -1,57 +0,0 @@ -# 通用配置 - -Kohana uses both static properties and files for configuration. Static properties are typically used for static classes, such as [Cookie], [Security], and [Upload]. Files are typically used for objects such as [Database], [Encrypt], and [Session]. - -Static properties can be set in `APPPATH/bootstrap.php` or by [class extension](using.autoloading#class-extension). The benefit of static properties is that no additional files need to be loaded. The problem with this method is that it causes the class to be loaded when the property is set, if you do not use an extension. However, using extensions will overload extensions made in modules. It is generally recommended to do static property configuration in the bootstrap. - -[!!] When using opcode caching, such as [APC](http://php.net/apc) or [eAccelerator](http://eaccelerator.net/), class loading time is significantly reduced. It is highly recommended to use opcode caching with *any* production website, no matter the size. - -## 加载配置 - -Every new Kohana installation will require changing [Kohana::init] settings in `APPPATH/bootstrap.php`. Any setting that is not set will use the default setting. These settings can be accessed and modified later by using the static property of the [Kohana] class. For instance, to get the current character set, read the [Kohana::$charset] property. - -## 安全配置 - -There are several settings which need to be changed to make Kohana secure. The most important of these is [Cookie::$salt], which is used to create a "signature" on cookies that prevents them from being modified outside of Kohana. - -If you plan to use the [Encrypt] class, you will also need to create an `encrypt` configuration file and set the encryption `key` value. The encryption key should include letters, numbers, and symbols for the best security. - -[!!] **Do not use a hash for the encryption key!** Doing so will make the encryption key much easier to crack. - -# 配置文件 {#config-files} - -Configuration files are slightly different from other files within the [cascading filesystem](about.filesystem) in that they are **merged** rather than overloaded. This means that all configuration files with the same file path are combined to produce the final configuration. The end result is that you can overload *individual* settings rather than duplicating an entire file. - -配置文件存放在 `config/` 目录的 PHP 文件,结构类似于: - - 'value', - 'options' => array( - 'foo' => 'bar', - ), - ); - -如果上面的配置文件名为 `myconf.php`,你可以通过下面代码调用: - - $config = Kohana::config('myconf'); - $options = $config['options']; - -[Kohana::config] 也提供了一钟使用“逗号格式”访问配置数组中的键: - -获得 "options" 数组: - - $options = Kohana::config('myconf.options'); - -从 "options" 数组获得 "foo" 键: - - $foo = Kohana::config('myconf.options.foo'); - -配置数组也可以当作对象访问,如果你喜欢下面的方法: - - $options = Kohana::config('myconf')->options; - -请注意的是你只能使用键值型数组访问首个变量,其余的子键都必须使用标准数组方式访: - - $foo = Kohana::config('myconf')->options['foo']; diff --git a/includes/kohana/modules/userguide/guide/zh-cn/using.messages.md b/includes/kohana/modules/userguide/guide/zh-cn/using.messages.md deleted file mode 100644 index 3d223609..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/using.messages.md +++ /dev/null @@ -1,26 +0,0 @@ -# 消息的基本使用 - -Kohana 消息(messages) 是一种友好化短小的词或短语的字符串,通常被叫做 "key"。消息通过 [Kohana::message] 方法调用访问并返回整个消息组或者单个消息。 - -举个简单的例子,当用户没有登录并试图访问一个需要验证的页面,通常会一个类似"你必须登录后才能访问此页面"的提示,而此消息可以保存在 auth 文件的 'must_login' 的键值中: - - $message = Kohana::message('auth', 'must_login'); - -消息并不能直接翻译,如果想翻译一个消息,你需要配合使用[翻译函数](using.translation): - - $translated = __(Kohana::message('auth', 'must_login')); - -[!!] 在 Kohana v2 版本中,消息系统是可以翻译的,尽管如此,我们还是强烈推荐大家使用新的翻译系统代替消息,因为当翻译不存时它可以提供可读性文本。 - -## 消息文件 - -所有的消息文件都是保存在 `messages/` 目录下的纯 PHP 文件的配对数组: - - '你必须登录后才能访问此页面', - 'no_access' => '你没有访问此页面的权限', - ); - -消息文件有些类似于[配置文件](using.configuration#config-files),它们都可以合并在一起。这意味着所有的消息都可以设置为一个数组并保存在 'auth' 文件之中。因此当你需要一个新的 'auth' 文件而没有必要创建多个重复文件。 diff --git a/includes/kohana/modules/userguide/guide/zh-cn/using.sessions.md b/includes/kohana/modules/userguide/guide/zh-cn/using.sessions.md deleted file mode 100644 index 7b7f4591..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/using.sessions.md +++ /dev/null @@ -1,223 +0,0 @@ -# Using Sessions and Cookies - -Kohana provides a couple of classes that make it easy to work with both cookies and session. At a high level both sessions and cookies provide the same function. They allow the developer to store temporary or persistent information about a specific client for later retrieval. - -Cookies should be used for storing non-private data that is persistent for a long period of time. For example storing a user id or a language preference. Use the [Cookie] class for getting and setting cookies. - -[!!] Kohana uses "signed" cookies. Every cookie that is stored is combined with a secure hash to prevent modification of the cookie. This hash is generated using [Cookie::salt], which uses the [Cookie::$salt] property. You should [change this setting](using.configuration) when your application is live. - -Sessions should be used for storing temporary or private data. Very sensitive data should be stored using the [Session] class with the "database" or "native" adapters. When using the "cookie" adapter, the session should always be encrypted. - -[!!] For more information on best practices with session variables see [the seven deadly sins of sessions](http://lists.nyphp.org/pipermail/talk/2006-December/020358.html). - -# Storing, Retrieving, and Deleting Data - -[Cookie] and [Session] provide a very similar API for storing data. The main difference between them is that sessions are accessed using an object, and cookies are accessed using a static class. - -Accessing the session instance is done using the [Session::instance] method: - - // Get the session instance - $session = Session::instance(); - -When using sessions, you can also get all of the current session data using the [Session::as_array] method: - - // Get all of the session data as an array - $data = $session->as_array(); - -You can also use this to overload the `$_SESSION` global to get and set data in a way more similar to standard PHP: - - // Overload $_SESSION with the session data - $_SESSION =& $session->as_array(); - - // Set session data - $_SESSION[$key] = $value; - -## Storing Data {#setting} - -Storing session or cookie data is done using the `set` method: - - // Set session data - $session->set($key, $value); - - // Set cookie data - Cookie::set($key, $value); - - // Store a user id - $session->set('user_id', 10); - Cookie::set('user_id', 10); - -## Retrieving Data {#getting} - -Getting session or cookie data is done using the `get` method: - - // Get session data - $data = $session->get($key, $default_value); - - // Get cookie data - $data = Cookie::get($key, $default_value); - - // Get the user id - $user = $session->get('user_id'); - $user = Cookie::get('user_id'); - -## Deleting Data {#deleting} - -Deleting session or cookie data is done using the `delete` method: - - // Delete session data - $session->delete($key); - - // Delete cookie data - Cookie::delete($key); - - // Delete the user id - $session->delete('user_id'); - Cookie::delete('user_id'); - -# Configuration {#configuration} - -Both cookies and sessions have several configuration settings which affect how data is stored. Always check these settings before making your application live, as many of them will have a direct affect on the security of your application. - -## Cookie Settings - -All of the cookie settings are changed using static properties. You can either change these settings in `bootstrap.php` or by using a [class extension](using.autoloading#class-extension). - -The most important setting is [Cookie::$salt], which is used for secure signing. This value should be changed and kept secret: - - Cookie::$salt = 'your secret is safe with me'; - -[!!] Changing this value will render all cookies that have been set before invalid. - -By default, cookies are stored until the browser is closed. To use a specific lifetime, change the [Cookie::$expiration] setting: - - // Set cookies to expire after 1 week - Cookie::$expiration = 604800; - - // Alternative to using raw integers, for better clarity - Cookie::$expiration = Date::WEEK; - -The path that the cookie can be accessed from can be restricted using the [Cookie::$path] setting. - - // Allow cookies only when going to /public/* - Cookie::$path = '/public/'; - -The domain that the cookie can be accessed from can also be restricted, using the [Cookie::$domain] setting. - - // Allow cookies only on the domain www.example.com - Cookie::$domain = 'www.example.com'; - -If you want to make the cookie accessible on all subdomains, use a dot at the beginning of the domain. - - // Allow cookies to be accessed on example.com and *.example.com - Cookie::$domain = '.example.com'; - -To only allow the cookie to be accessed over a secure (HTTPS) connection, use the [Cookie::$secure] setting. - - // Allow cookies to be accessed only on a secure connection - Cookie::$secure = TRUE; - - // Allow cookies to be accessed on any connection - Cookie::$secure = FALSE; - -To prevent cookies from being accessed using Javascript, you can change the [Cookie::$httponly] setting. - - // Make cookies inaccessible to Javascript - Cookie::$httponly = TRUE; - -## Session Adapters {#adapters} - -When creating or accessing an instance of the [Session] class you can decide which session adapter you wish to use. The session adapters that are available to you are: - -Native -: Stores session data in the default location for your web server. The storage location is defined by [session.save_path](http://php.net/manual/session.configuration.php#ini.session.save-path) in `php.ini` or defined by [ini_set](http://php.net/ini_set). - -Database -: Stores session data in a database table using the [Session_Database] class. Requires the [Database] module to be enabled. - -Cookie -: Stores session data in a cookie using the [Cookie] class. **Sessions will have a 4KB limit when using this adapter.** - -The default datapter can be set by changing the value of [Session::$default]. The default adapter is "native". - -[!!] As with cookies, a "lifetime" setting of "0" means that the session will expire when the browser is closed. - -### Session Adapter Settings - -You can apply configuration settings to each of the session adapters by creating a session config file at `APPPATH/config/session.php`. The following sample configuration file defines all the settings for each adapater: - - return array( - 'native' => array( - 'name' => 'session_name', - 'lifetime' => 43200, - ), - 'cookie' => array( - 'name' => 'cookie_name', - 'encrypted' => TRUE, - 'lifetime' => 43200, - ), - 'database' => array( - 'name' => 'cookie_name', - 'encrypted' => TRUE, - 'lifetime' => 43200, - 'group' => 'default', - 'table' => 'table_name', - 'columns' => array( - 'session_id' => 'session_id', - 'last_active' => 'last_active', - 'contents' => 'contents' - ), - 'gc' => 500, - ), - ); - -#### Native Adapter {#adapter-native} - -Type | Setting | Description | Default -----------|-----------|---------------------------------------------------|----------- -`string` | name | name of the session | `"session"` -`integer` | lifetime | number of seconds the session should live for | `0` - -#### Cookie Adapter {#adapter-cookie} - -Type | Setting | Description | Default -----------|-----------|---------------------------------------------------|----------- -`string` | name | name of the cookie used to store the session data | `"session"` -`boolean` | encrypted | encrypt the session data using [Encrypt]? | `FALSE` -`integer` | lifetime | number of seconds the session should live for | `0` - -#### Database Adapter {#adapter-database} - -Type | Setting | Description | Default -----------|-----------|---------------------------------------------------|----------- -`string` | group | [Database::instance] group name | `"default"` -`string` | table | table name to store sessions in | `"sessions"` -`array` | columns | associative array of column aliases | `array` -`integer` | gc | 1:x chance that garbage collection will be run | `500` -`string` | name | name of the cookie used to store the session data | `"session"` -`boolean` | encrypted | encrypt the session data using [Encrypt]? | `FALSE` -`integer` | lifetime | number of seconds the session should live for | `0` - -##### Table Schema - -You will need to create the session storage table in the database. This is the default schema: - - CREATE TABLE `sessions` ( - `session_id` VARCHAR(24) NOT NULL, - `last_active` INT UNSIGNED NOT NULL, - `contents` TEXT NOT NULL, - PRIMARY KEY (`session_id`), - INDEX (`last_active`) - ) ENGINE = MYISAM; - -##### Table Columns - -You can change the column names to match an existing database schema when connecting to a legacy session table. The default value is the same as the key value. - -session_id -: the name of the "id" column - -last_active -: UNIX timestamp of the last time the session was updated - -contents -: session data stored as a serialized string, and optionally encrypted diff --git a/includes/kohana/modules/userguide/guide/zh-cn/using.views.md b/includes/kohana/modules/userguide/guide/zh-cn/using.views.md deleted file mode 100644 index 54f9c220..00000000 --- a/includes/kohana/modules/userguide/guide/zh-cn/using.views.md +++ /dev/null @@ -1,118 +0,0 @@ -# 视图的使用 - -视图是包含输出显示信息内容的文件。通常大多数情况下是 HTML,CSS 和 Javascript 或者其他任何内容(包括调用 AJAX 的 XML 或 JSON 的输出)。其主要目的是为了从程序中分离逻辑以获得可复用性和整洁代码。 - -然而事实上,视图本身也能传递变量等代码并输出数据。比如,循环产品信息的数组并输出每个产品的信息。视图仍然是 PHP 文件因此你可以正常的写任何代码。 - -# 创建视图文件 - -视图文件存在[文件系统](about.filesystem)中的 `views` 目录。你也可以在 `views` 目录下面创建子目录组织你的文件。下面所有的例子都是合理的视图文件: - - APPPATH/views/home.php - APPPATH/views/pages/about.php - APPPATH/views/products/details.php - MODPATH/error/views/errors/404.php - MODPATH/common/views/template.php - -## 加载视图 - -[View] 对象通常在 [Controller] 内部通过使用 [View::factory] 方法创建。一般视图被赋值给 [Request::$response] 属性或其他视图。 - - public function action_about() - { - $this->request->response = View::factory('pages/about'); - } - -当视图对象如同上面的例子赋值给 [Request::$response],必要时它会自动输出呈现。如果想获得视图输出的内容,你可以调用 [View::render] 方法或者强制转为字符串类型。当时视图输出呈现时,视图会被加载并生成 HTML 代码。 - - public function action_index() - { - $view = View::factory('pages/about'); - - // Render the view - $about_page = $view->render(); - - // Or just type cast it to a string - $about_page = (string) $view; - - $this->request->response = $about_page; - } - -## 视图变量 - -一旦视图已经被加载,我们可以通过 [View::set] 和 [View::bind] 方法赋值变量。 - - public function action_roadtrip() - { - $view = View::factory('user/roadtrip') - ->set('places', array('Rome', 'Paris', 'London', 'New York', 'Tokyo')); - ->bind('user', $this->user); - - // 视图拥有 $places 和 $user 变量 - $this->request->response = $view; - } - -[!!] `set()` 和 `bind()` 方法的区别在于 `bind()` 是引用赋值。如果你在变量定义之前使用 `bind()` 绑定了它。变量默认会被当作 `NULL` 创建。 - -### 全局变量 - -在程序中可能有多个视图文件而同时调用同样的变量。比如,在两个模板的 header 块中显示一个页面的相同标题而不同的内容。通过 [View::set_global] 和 [View::bind_global] 方法创建全局变量。 - - // 赋值 $page_title 到所有的视图 - View::bind_global('page_title', $page_title); - -假如程序中首页有三个视图需要输出呈现:`template`,`template/sidebar` 和 `pages/home`。首先,创建一个抽象类控制器去初始化视图模板: - - abstract class Controller_Website extends Controller_Template { - - public $page_title; - - public function before() - { - parent::before(); - - // 定义 $page_title 变量到所有视图中使用 - View::bind_global('page_title', $this->page_title); - - // 加载视图为 $sidebar 变量到模板 - $this->template->sidebar = View::factory('template/sidebar'); - } - - } - -下一步,在 home 控制器继承 `Controller_Website`: - - class Controller_Home extends Controller_Website { - - public function action_index() - { - $this->page_title = 'Home'; - - $this->template->content = View::factory('pages/home'); - } - - } - -## 视图嵌套 - -如果你想在视图中加载另外一个视图,这里提供两个方案。通过调用 [View::factory] 你可以实现沙盒加载视图。这意味着你可以使用 [View::set] 或 [View::bind] 赋值: - - // 只有 $user 变量可用在 "views/user/login.php" 视图文件 - bind('user', $user) ?> - -另外一种选择是直接加载视图,这会使得当前所有变量加载并在视图中使用: - - // 所有定义在此视图中的变量都会加载到 "views/message.php" 文件 - - -另外,你也可以在整个 [Request] 中加载一个视图中: - - execute() ?> - -这是一个 [HMVC](about.mvc) 的例子已确保它可以创建并从程序其他的 URL 调用。 - -# 升级 v2.x 版本 - -不同于 Kohana v2.x 版本,视图不在 [Controller] 环境中加载,因此你不能够把 `$this` 当作加载视图的控制器访问。传递控制器到视图必须这样实现: - - $view->bind('controller', $this); diff --git a/includes/kohana/modules/userguide/init.php b/includes/kohana/modules/userguide/init.php index e55f947c..a812316b 100644 --- a/includes/kohana/modules/userguide/init.php +++ b/includes/kohana/modules/userguide/init.php @@ -8,9 +8,9 @@ Route::set('docs/media', 'guide/media(/)', array('file' => '.+')) 'file' => NULL, )); +// API Browser, if enabled if (Kohana::config('userguide.api_browser') === TRUE) { - // API Browser Route::set('docs/api', 'guide/api(/)', array('class' => '[a-zA-Z0-9_]+')) ->defaults(array( 'controller' => 'userguide', @@ -19,12 +19,12 @@ if (Kohana::config('userguide.api_browser') === TRUE) )); } -// Translated user guide -Route::set('docs/guide', 'guide(/)', array( +// User guide pages, in modules +Route::set('docs/guide', 'guide(/(/))', array( 'page' => '.+', )) ->defaults(array( 'controller' => 'userguide', 'action' => 'docs', - )); - + 'module' => '', + )); \ No newline at end of file diff --git a/includes/kohana/modules/userguide/media/css/kodoc.css b/includes/kohana/modules/userguide/media/css/kodoc.css deleted file mode 100644 index 63ac6bf4..00000000 --- a/includes/kohana/modules/userguide/media/css/kodoc.css +++ /dev/null @@ -1,62 +0,0 @@ -html { margin: 0; } -body { margin: 0 } -body.he { direction: rtl } -pre { background: #eee; padding: 0.5em 0.6em 0.4em; overflow: auto; } -table th { color: #444; background: #eee; } -table td { background: #fafafa; } - table tr.alt td { background: #fff; } - -.container .toggle { font-size: 0.7em; float: right; padding: 0 1em; cursor: pointer; color: #777; text-decoration: none; } -.container table { width: 100%; } - -#topbar { padding: 1em 0; margin-bottom: 2em; background: #111; border-bottom: solid 0.2em #eee; color: #ccc; } - #topbar ul.breadcrumb { display: block; margin: 0; padding: 0; overflow: auto; } - #topbar ul.breadcrumb li { display: block; float: left; margin: 0; padding: 0; padding-left: 0.6em; } - #topbar ul.breadcrumb li:before { content: '» '; color: #888; } - #topbar ul.breadcrumb li a { color: #ccc; text-decoration: underline; } - #topbar form { margin: 0 1em; padding: 0; } - #topbar form select { width: 98%; } - -#menu { background: #eee; padding: 1em 0; } - #menu ol, - #menu ul { margin: 0; padding: 0; list-style: none; } - #menu li { margin: 0; padding: 0; } - #menu li { display: block; } - #menu li strong { display: block; margin-bottom: 0.4em; padding: 0.2em 0.4em; font-weight: normal; color: #eee; background: #111; cursor: pointer; } - #menu li li strong { background-color: #ccc; color: #111; } - #menu ol { padding: 0 0.6em; margin: 0; } - #menu ol ul, - #menu ol ol { margin-left: 1em; padding: 0 0 0.6em; } - #menu h3 { font-size: 1em; margin: 1em 0 0; padding: 1em 1em 0.5em; border-top: 5px solid #fff; } - -#footer { margin-top: 1em; padding: 1em 0; color: #666; } - #footer p { font-size: 0.8em; text-transform: uppercase; } -#content h1 { font-size: 3em; letter-spacing: -0.02em; } -#content h2 { margin-top: 1.5em; margin-left: -20px; padding: 0.6em 20px 0.5em 20px; background: #e5e5e5; font-size: 2em; letter-spacing: -0.01em; text-shadow: 0 -1px 0 #fff; } -#content h3 { border-bottom: 2px solid #eee; font-size: 1.6em; } -#content h1 small, -#content h2 small, -#content h3 small, -#content h4 small, -#content h5 small, -#content h6 small { font-size: 0.8em; font-weight: normal; color: #444; } -#content pre { font-size: 1em; line-height: 1.4em; direction: ltr } - -#content div.class-list div.class { width: 50%; } -#content div.class-list div.class.left { float: left; clear: both; } -#content div.class-list div.class.right { float: right; } - #content div.class-list div.class h2 { margin: 0.4em; padding: 0.2em 0.4em; font-size: 1em; } - -#content div.toc { margin-bottom: 1em; padding-bottom: 1em; background: #eee; } - #content div.toc ul { margin: 0.6em 1em; padding: 0; list-style: none; } - #content div.toc li { margin: 0; padding: 0; } - #content div.toc h3 { margin: 0; padding: 0.2em 1em; font-size: 1em; color: #eee; background: #111; } -#content div.method, -#content div.properties, -#content div.constants { margin-bottom: 1em; } - #content div.method h3 .param { font-weight: normal; cursor: help; border-bottom:1px dashed #666;} - #content div.method h3 abbr.param { text-transform: none; font-size: 1em; } -#content p.note { display: block; padding: 0.4em 0.6em; padding-left: 3em; background: url(../img/note.png) 1em 0.6em no-repeat; border: 1px solid #e5e5e5; font-family: Georgia, serif; font-size: 1.05em; font-style: italic; color: #555; } -#content dl.tags { overflow: auto; background: #eee; padding: 1em; border: solid 6px #ddd; } - #content dl.tags dt { margin: 0 0 0.4em; clear: both; float: left; width: 25%; } - #content dl.tags dd { margin: 0; padding: 0; clear: right; float: right; } diff --git a/includes/kohana/modules/userguide/media/css/print.css b/includes/kohana/modules/userguide/media/css/print.css deleted file mode 100644 index 8b5ba48f..00000000 --- a/includes/kohana/modules/userguide/media/css/print.css +++ /dev/null @@ -1,46 +0,0 @@ -/* -------------------------------------------------------------- - - * print.css - BlueTrip CSS Framework - * Thanks to Hartija Print Framework - --------------------------------------------------------------- */ - -body { -width:100% !important; -margin:0 !important; -padding:0 !important; -line-height: 1.4; -word-spacing:1.1pt; -letter-spacing:0.2pt; font-family: Garamond,"Times New Roman", serif; color: #000; background: none; font-size: 12pt; } - -/*Headings */ -h1,h2,h3,h4,h5,h6 { font-family: Helvetica, Arial, sans-serif; } -h1{font-size:19pt;} -h2{font-size:17pt;} -h3{font-size:15pt;} -h4,h5,h6{font-size:12pt;} - -code { font: 10pt Courier, monospace; } -blockquote { margin: 1.3em; padding: 1em; font-size: 10pt; } -hr { background-color: #ccc; } - -/* Images */ -img { float: left; margin: 1em 1.5em 1.5em 0; } -a img { border: none; } - -/* Links */ -a:link, a:visited { background: transparent; font-weight: 700; text-decoration: underline;color:#333; } - -/* Table */ -table { margin: 1px; text-align:left; } -th { border-bottom: 1px solid #333; font-weight: bold; } -td { border-bottom: 1px solid #333; } -th,td { padding: 4px 10px 4px 0; } -tfoot { font-style: italic; } -caption { background: #fff; margin-bottom:2em; text-align:left; } -thead {display: table-header-group;} -tr {page-break-inside: avoid;} - -/*add sections here to hide various parts from the site*/ - -/*#header, #footer, #navigation, #sidebar, button, a.button {display:none;}*/ \ No newline at end of file diff --git a/includes/kohana/modules/userguide/media/css/shCore.css b/includes/kohana/modules/userguide/media/css/shCore.css deleted file mode 100644 index 61572457..00000000 --- a/includes/kohana/modules/userguide/media/css/shCore.css +++ /dev/null @@ -1,330 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/ - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate - * - * @version - * 2.1.364 (October 15 2009) - * - * @copyright - * Copyright (C) 2004-2009 Alex Gorbatchev. - * - * @license - * This file is part of SyntaxHighlighter. - * - * SyntaxHighlighter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * SyntaxHighlighter is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with SyntaxHighlighter. If not, see . - */ -.syntaxhighlighter, -.syntaxhighlighter div, -.syntaxhighlighter code, -.syntaxhighlighter table, -.syntaxhighlighter table td, -.syntaxhighlighter table tr, -.syntaxhighlighter table tbody -{ - margin: 0 !important; - padding: 0 !important; - border: 0 !important; - outline: 0 !important; - background: none !important; - text-align: left !important; - float: none !important; - vertical-align: baseline !important; - position: static !important; - left: auto !important; - top: auto !important; - right: auto !important; - bottom: auto !important; - height: auto !important; - width: auto !important; - line-height: 1.1em !important; - font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; - font-weight: normal !important; - font-style: normal !important; - font-size: 1em !important; - min-height: inherit !important; /* For IE8, FF & WebKit */ - min-height: auto !important; /* For IE7 */ -} - -.syntaxhighlighter -{ - width: 99% !important; /* 99% fixes IE8 horizontal scrollbar */ - margin: 1em 0 1em 0 !important; - padding: 1px !important; /* adds a little border on top and bottom */ - position: relative !important; -} - -.syntaxhighlighter .bold -{ - font-weight: bold !important; -} - -.syntaxhighlighter .italic -{ - font-style: italic !important; -} - -.syntaxhighlighter .line -{ -} - -.syntaxhighlighter .no-wrap .line .content -{ - white-space: pre !important; -} - -.syntaxhighlighter .line table -{ - border-collapse: collapse !important; -} - -.syntaxhighlighter .line td -{ - vertical-align: top !important; -} - -.syntaxhighlighter .line .number -{ - width: 3em !important; -} - -.syntaxhighlighter .line .number code -{ - width: 2.7em !important; - padding-right: .3em !important; - text-align: right !important; - display: block !important; -} - -.syntaxhighlighter .line .content -{ - padding-left: .5em !important; -} - -.syntaxhighlighter .line .spaces -{ -} - -/* Disable border and margin on the lines when no gutter option is set */ -.syntaxhighlighter.nogutter .line .content -{ - border-left: none !important; -} - -.syntaxhighlighter .bar -{ - display: none !important; -} - -.syntaxhighlighter .bar.show -{ - display: block !important; -} - -.syntaxhighlighter.collapsed .bar -{ - display: block !important; -} - -/* Adjust some properties when collapsed */ - -.syntaxhighlighter.collapsed .lines -{ - display: none !important; -} - -.syntaxhighlighter .lines.no-wrap -{ - overflow: auto !important; - overflow-y: hidden !important; -} - -/* Styles for the toolbar */ - -.syntaxhighlighter .toolbar -{ - position: absolute !important; - right: 0px !important; - top: 0px !important; - font-size: 1px !important; - padding: 8px 8px 8px 0 !important; /* in px because images don't scale with ems */ -} - -.syntaxhighlighter.collapsed .toolbar -{ - font-size: 80% !important; - padding: .2em 0 .5em .5em !important; - position: static !important; -} - -.syntaxhighlighter .toolbar a.item, -.syntaxhighlighter .toolbar .item -{ - display: block !important; - float: left !important; - margin-left: 8px !important; - background-repeat: no-repeat !important; - overflow: hidden !important; - text-indent: -5000px !important; -} - -.syntaxhighlighter.collapsed .toolbar .item -{ - display: none !important; -} - -.syntaxhighlighter.collapsed .toolbar .item.expandSource -{ - background-image: url(magnifier.png) !important; - display: inline !important; - text-indent: 0 !important; - width: auto !important; - float: none !important; - height: 16px !important; - padding-left: 20px !important; -} - -.syntaxhighlighter .toolbar .item.viewSource -{ - background-image: url(page_white_code.png) !important; -} - -.syntaxhighlighter .toolbar .item.printSource -{ - background-image: url(printer.png) !important; -} - -.syntaxhighlighter .toolbar .item.copyToClipboard -{ - text-indent: 0 !important; - background: none !important; - overflow: visible !important; -} - -.syntaxhighlighter .toolbar .item.about -{ - background-image: url(help.png) !important; -} - -/** - * Print view. - * Colors are based on the default theme without background. - */ - -.syntaxhighlighter.printing, -.syntaxhighlighter.printing .line.alt1 .content, -.syntaxhighlighter.printing .line.alt2 .content, -.syntaxhighlighter.printing .line.highlighted .number, -.syntaxhighlighter.printing .line.highlighted.alt1 .content, -.syntaxhighlighter.printing .line.highlighted.alt2 .content -{ - background: none !important; -} - -/* Gutter line numbers */ -.syntaxhighlighter.printing .line .number -{ - color: #bbb !important; -} - -/* Add border to the lines */ -.syntaxhighlighter.printing .line .content -{ - color: #000 !important; -} - -/* Toolbar when visible */ -.syntaxhighlighter.printing .toolbar -{ - display: none !important; -} - -.syntaxhighlighter.printing a -{ - text-decoration: none !important; -} - -.syntaxhighlighter.printing .plain, -.syntaxhighlighter.printing .plain a -{ - color: #000 !important; -} - -.syntaxhighlighter.printing .comments, -.syntaxhighlighter.printing .comments a -{ - color: #008200 !important; -} - -.syntaxhighlighter.printing .string, -.syntaxhighlighter.printing .string a -{ - color: blue !important; -} - -.syntaxhighlighter.printing .keyword -{ - color: #069 !important; - font-weight: bold !important; -} - -.syntaxhighlighter.printing .preprocessor -{ - color: gray !important; -} - -.syntaxhighlighter.printing .variable -{ - color: #a70 !important; -} - -.syntaxhighlighter.printing .value -{ - color: #090 !important; -} - -.syntaxhighlighter.printing .functions -{ - color: #ff1493 !important; -} - -.syntaxhighlighter.printing .constants -{ - color: #0066CC !important; -} - -.syntaxhighlighter.printing .script -{ - font-weight: bold !important; -} - -.syntaxhighlighter.printing .color1, -.syntaxhighlighter.printing .color1 a -{ - color: #808080 !important; -} - -.syntaxhighlighter.printing .color2, -.syntaxhighlighter.printing .color2 a -{ - color: #ff1493 !important; -} - -.syntaxhighlighter.printing .color3, -.syntaxhighlighter.printing .color3 a -{ - color: red !important; -} diff --git a/includes/kohana/modules/userguide/media/css/shThemeDefault.css b/includes/kohana/modules/userguide/media/css/shThemeDefault.css deleted file mode 100644 index 3fef10d2..00000000 --- a/includes/kohana/modules/userguide/media/css/shThemeDefault.css +++ /dev/null @@ -1,173 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/ - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate - * - * @version - * 2.1.364 (October 15 2009) - * - * @copyright - * Copyright (C) 2004-2009 Alex Gorbatchev. - * - * @license - * This file is part of SyntaxHighlighter. - * - * SyntaxHighlighter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * SyntaxHighlighter is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with SyntaxHighlighter. If not, see . - */ -/************************************ - * Default Syntax Highlighter theme. - * - * Interface elements. - ************************************/ - -.syntaxhighlighter -{ - background-color: #fff !important; -} - -/* Highlighed line number */ -.syntaxhighlighter .line.highlighted .number -{ - color: black !important; -} - -/* Highlighed line */ -.syntaxhighlighter .line.highlighted.alt1, -.syntaxhighlighter .line.highlighted.alt2 -{ - background-color: #e0e0e0 !important; -} - -/* Gutter line numbers */ -.syntaxhighlighter .line .number -{ - color: #afafaf !important; -} - -/* Add border to the lines */ -.syntaxhighlighter .line .content -{ - border-left: 3px solid #6CE26C !important; - color: #000 !important; -} - -.syntaxhighlighter.printing .line .content -{ - border: 0 !important; -} - -/* First line */ -.syntaxhighlighter .line.alt1 -{ - background-color: #fff !important; -} - -/* Second line */ -.syntaxhighlighter .line.alt2 -{ - background-color: #F8F8F8 !important; -} - -.syntaxhighlighter .toolbar -{ - background-color: #F8F8F8 !important; - border: #E7E5DC solid 1px !important; -} - -.syntaxhighlighter .toolbar a -{ - color: #a0a0a0 !important; -} - -.syntaxhighlighter .toolbar a:hover -{ - color: red !important; -} - -/************************************ - * Actual syntax highlighter colors. - ************************************/ -.syntaxhighlighter .plain, -.syntaxhighlighter .plain a -{ - color: #000 !important; -} - -.syntaxhighlighter .comments, -.syntaxhighlighter .comments a -{ - color: #008200 !important; -} - -.syntaxhighlighter .string, -.syntaxhighlighter .string a -{ - color: blue !important; -} - -.syntaxhighlighter .keyword -{ - color: #069 !important; - font-weight: bold !important; -} - -.syntaxhighlighter .preprocessor -{ - color: gray !important; -} - -.syntaxhighlighter .variable -{ - color: #a70 !important; -} - -.syntaxhighlighter .value -{ - color: #090 !important; -} - -.syntaxhighlighter .functions -{ - color: #ff1493 !important; -} - -.syntaxhighlighter .constants -{ - color: #0066CC !important; -} - -.syntaxhighlighter .script -{ - background-color: yellow !important; -} - -.syntaxhighlighter .color1, -.syntaxhighlighter .color1 a -{ - color: #808080 !important; -} - -.syntaxhighlighter .color2, -.syntaxhighlighter .color2 a -{ - color: #ff1493 !important; -} - -.syntaxhighlighter .color3, -.syntaxhighlighter .color3 a -{ - color: red !important; -} diff --git a/includes/kohana/modules/userguide/media/guide/css/api.css b/includes/kohana/modules/userguide/media/guide/css/api.css new file mode 100644 index 00000000..56361f76 --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/css/api.css @@ -0,0 +1,34 @@ +/* Api browser stuff */ + +/* api index page */ +div.class-list div.class { width: 50%; } +div.class-list div.class.left { float: left; clear: both; } +div.class-list div.class.right { float: right; } + div.class-list div.class h2 { background:none; } + +/* table of contents at the top of each class */ +div.toc { } +div.toc div {float:left; width: 33%;} +div.toc div h3 {margin-top:0; background:none; } + + +/* constants */ +div.constants dl dt {font-weight:bold; margin-bottom:1.5em;} +div.constants dl dd {margin-left:1.5em; margin-bottom:1.5em;} + +/* properties */ +div.properties dl dt { font-weight:bold; margin-top:1.5em; margin-bottom:1.5em;} +div.properties dl dt small, div.properties dl dt code { font-weight:normal; font-size:0.9em; } +div.properties dl dd {margin-left:1.5em; margin-bottom:1.5em;} + +/* functions */ + +div.method { padding:0 1.5em; border:1px solid #c8cfaf; border-radius:5px; margin-bottom:1.5em; } +div.method h3 { background:none; margin-top:0; margin-left:-1em; margin-right:-1em; padding:.75em 0 .75em 1.17em; background:#e8efcf; border-top-left-radius:5px; border-top-right-radius:5px; } +div.method h3 .param { font-weight: normal; cursor: help; border-bottom:1px dashed #666;} +div.method h3 abbr.param { text-transform: none; font-size: 1em; } + +dl.tags { overflow: auto; background: #e8efcf; padding: 1em; border: solid 6px #d8dfbf; margin-bottom:1.5em; } + dl.tags dt { margin: 0; clear: both; float: left; width: 25%; } + dl.tags dd { margin: 0; padding: 0; clear: right; float: right; } + diff --git a/includes/kohana/modules/userguide/media/guide/css/kodoc.css b/includes/kohana/modules/userguide/media/guide/css/kodoc.css new file mode 100644 index 00000000..391c2d7a --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/css/kodoc.css @@ -0,0 +1,142 @@ +@import url('api.css'); + +html { background: #00262f; font-size: 70%; } +body { margin: 0; } +ol ol, ol ul, ul ul, ul ol { margin-bottom: 0; } +a img { border: 0; } + +h1 small, +h2 small, +h3 small, +h4 small { font-weight: normal; font-size: 0.7em; } +h5 small, +h6 small { font-weight: normal; font-size: 0.8em; } + +dl dd { margin-left: 0; } + +code { + color:#6BAA3D; + font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace; +} + +pre { + background:#fff; + border-radius:10px; + padding:1.5em; + font-size:0.9em; + margin-top:1.5em; + margin-bottom:1.5em; + overflow:auto; +} + +.highlighted div.line { + font-size:1em; + line-height:1.3 !important; +} + +table { + background:#eee; + border-left: 1px solid #CCC; + border-top: 1px solid #CCC; + margin-bottom:1.5em; + width: 100%; +} + +table td, table th { + padding:0.4em 0.8em; + line-height:1.4286; + border-right: 1px solid #CCC; + border-bottom: 1px solid #CCC; +} + +table th { + background: #ddd; +} + +table tr:nth-child(even) { + background: #fff; +} + +.caps { text-transform: uppercase; font-size: 0.8em; font-weight: normal; } +.status { text-transform: lowercase; font-variant: small-caps; font-weight: bold; color: #911; } +.container .colborder { border-color: #d3d8bc; } + +.note { + padding: 1.5em; + padding-left: 5em; + background: #e8efcf url('../img/lightbulb_48.png') no-repeat 1em center; + border-radius: 0.6em; + overflow: auto; +} + +h1 a.permalink, +h2 a.permalink, +h3 a.permalink, +h4 a.permalink, +h5 a.permalink, +h6 a.permalink { + font-size: 0.6em; + line-height: 100%; + vertical-align: middle; + margin-left: 1em; + padding: 0; + font-weight: normal; + display: none; + position: inherit; +} + +h1:hover a.permalink, +h2:hover a.permalink, +h3:hover a.permalink, +h4:hover a.permalink, +h5:hover a.permalink, +h6:hover a.permalink { + display: inline; +} + + +#header, +#content, +#footer { float: left; clear: both; width: 100%; } + +#header { padding: 58px 0 2em; background: #77c244 url(../img/header.png) center top repeat-x; } + #logo { display: block; float: left; } + #menu { float: right; margin-top: 12px; background: #113c32; -moz-border-radius: 5px; -webkit-border-radius: 5px; } + #menu ul { float: left; margin: 0; padding: 0 0.5em 0 0; } + #menu li { display: block; float: left; margin: 0; padding: 0; } + #menu li.first { padding-left: 0.5em; } + #menu li a { display: block; height: 32px; line-height: 32px; padding: 0 0.8em; border-right: solid 1px #0f362d; border-left: solid 1px #144539; letter-spacing: 0.05em; text-decoration: none; text-transform: uppercase; color: #efefef; font-size: 90%; } + #menu li.first a { border-left: 0; } + #menu li.last a { border-right: 0; } + #menu li a:hover { background: #164e41; border-left-color: #195a4b; color: #fff; text-shadow: #fff 0 0 1px; } + +#content { background: #f1f8db url(../img/content.png) center top repeat-x; } + #content .wrapper { min-height: 390px; padding: 1em 0; background: transparent url(../img/wrapper.png) center top no-repeat; } + #content div.page-toc { float: right; margin: 1em; margin-top: 0; padding: 1em; background: #fff; border: solid 0.1em #e8efcf; border-radius: 0.6em; } + #content p.intro { padding: 1em 20px; padding-left: 20px; margin: 0 -20px; font-size: 1.2em; } + #content a { color: #004352; } + #content a:hover { color: #00758f; } + #content a:active { text-decoration: none; } + +#breadcrumb { margin: 0 0 1em; padding: 0 0 0.5em; list-style: none; border-bottom: solid 1px #e8efcf; } + #breadcrumb li { display: inline-block; margin: 0; padding: 0 0.4em 0 0; text-transform: uppercase; font-size: 11px; } + #breadcrumb li:before { content: '»'; padding-right: 0.4em; } + #breadcrumb li a { color: #999; text-decoration: none; } + +#topics { } + #topics ul, + #topics ol { list-style-type:none; margin: 0; padding: 0;} + #topics ul li, + #topics ol li { margin:0; padding: 0; margin-left: 1em; } + #topics ul li a.current, + #topics ol li a.current { font-weight: bold; } + #topics span, + #topics a { display: block; padding: 0; margin: 0; } + #topics span { cursor: pointer; } + #topics span.toggle { display: block; float: left; width: 1em; padding-right: 0.4em; margin-left: -1.4em; text-align: center; } + + #topics li span { cursor:pointer; } + +#footer { padding: 1em 0; background: #00262f; color: #405c63; text-shadow: #00262f 0.1em 0.1em 1px; font-size: 0.9em; } + #footer a { color: #809397; } + #footer div.last { text-align: right; } \ No newline at end of file diff --git a/includes/kohana/modules/userguide/media/guide/css/print.css b/includes/kohana/modules/userguide/media/guide/css/print.css new file mode 100644 index 00000000..5feae024 --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/css/print.css @@ -0,0 +1,50 @@ + +/* Smaller font for printing */ +body { + font:14px/1.5 Helvetica,Arial; +} + +/* Show link urls, imitating markdown syntax */ +a:link, a:visited { text-decoration:none; } +a:link:before, a:visited:before { content:"["; } +a:link:after, a:visited:after { content:"](" attr(href) ")"; } + +/* Hide things like navigation, header links, etc. */ +#kodoc-header, +#kodoc-nav, +#kodoc-menu, +#kodoc-page-toc, +.syntaxhighlighter .toolbar, +h1 a.permalink, +h2 a.permalink, +h3 a.permalink, +h4 a.permalink, +h5 a.permalink, +h6 a.permalink +{ display:none; } + +pre { + padding:1em; + border:1px dashed #999; +} + +table { + border-left: 1px solid #999; + border-top: 1px solid #999; +} + +table td, table th { + padding:0.4em 0.8em; + border-right: 1px solid #999; + border-bottom: 1px solid #999; +} + +/* syntax highlighter tables inside pre cause problems */ +pre table, pre table td, pre table th { + padding:0; + border:none; +} + +p.note { padding:1em; border: 1px solid black; } + +p.note:before { content:"Note: "; font-weight:bold; } \ No newline at end of file diff --git a/includes/kohana/modules/userguide/media/css/screen.css b/includes/kohana/modules/userguide/media/guide/css/screen.css similarity index 93% rename from includes/kohana/modules/userguide/media/css/screen.css rename to includes/kohana/modules/userguide/media/guide/css/screen.css index d02df5d2..cff25704 100644 --- a/includes/kohana/modules/userguide/media/css/screen.css +++ b/includes/kohana/modules/userguide/media/guide/css/screen.css @@ -10,7 +10,7 @@ ----------------------------------------------------------------------- */ -/* MEYER RESET v1.0*/ +/* MEYER RESET v1.0 */ html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,font,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border:0;outline:0;font-size:100%;vertical-align:baseline;background:transparent}body{line-height:1}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}:focus{outline:0}ins{text-decoration:none}del{text-decoration:line-through}table{border-collapse:collapse;border-spacing:0} @@ -95,20 +95,19 @@ dt { margin-top: .8em; margin-bottom: .4em; } ul { margin-left: 1.5em; } ol { margin-left: 2.35em; } ol ol, ul ol { margin-left: 2.5em; } -ol ol, ol ul, ul ul, ul ol { margin-bottom: 0; } form div { margin-bottom: .8em; } /* COLORS */ a:link { text-decoration: underline; color: #36c; } -a:visited { text-decoration: underline; color: #36c; } +a:visited { text-decoration: underline; color: #99c; } a:hover { text-decoration: underline; color: #c33; } a:active, a:focus { text-decoration: underline; color: #000; } code, pre { color: #c33; } /* very optional, but still useful. W3C uses about the same colors for codes */ /* 24 COLUMN GRID */ -.container {width:950px;margin:0 auto;} +.container {width:950px;margin:0 auto;overflow:hidden;} .showgrid {background:url(../img/grid.png);} body {margin:1.5em 0;} div.span-1, div.span-2, div.span-3, div.span-4, div.span-5, div.span-6, div.span-7, div.span-8, div.span-9, div.span-10, div.span-11, div.span-12, div.span-13, div.span-14, div.span-15, div.span-16, div.span-17, div.span-18, div.span-19, div.span-20, div.span-21, div.span-22, div.span-23 {float:left;margin-right:10px;} @@ -238,29 +237,14 @@ div.colborder {padding-right:24px;margin-right:25px;border-right:1px solid #eee; .push-1, .push-2, .push-3, .push-4, .push-5, .push-6, .push-7, .push-8, .push-9, .push-10, .push-11, .push-12, .push-13, .push-14, .push-15, .push-16, .push-17, .push-18, .push-19, .push-20, .push-21, .push-22, .push-23, .push-24 {float:right;position:relative;} hr {background:#ddd;color:#ddd;clear:both;float:none;width:100%;height:.1em;margin:0 0 1.45em;border:none;} hr.space {background:#fff;color:#fff;} -.clearfix:after, .container:after {content:".";display:block;height:0;clear:both;visibility:hidden;max-height:0;} +.clearfix:after {content:".";display:block;height:0;clear:both;visibility:hidden;max-height:0;} .clearfix, .container {display:inline-block;} * html .clearfix, * html .container {height:1%;} .clearfix, .container {display:block;} .clear {clear:both;} -/* to create serif italic dramatic text, use this class */ -.fancy { - color: #666; - font-family: "Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua", Georgia, serif; - font-style: italic; - font-weight: normal; -} - -/* creates small caps */ -.caps { - font-variant: small-caps; - letter-spacing: 1px; - text-transform: lowercase; - font-size:1.2em; - font-weight:bold; - padding:0 2px; -} +/* Creates fancy serif style type */ +.fancy { color: #666; font-family: "Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua", Georgia, serif; font-style: italic; font-weight: normal; } /* TEXT CLASSES */ @@ -280,7 +264,4 @@ hr.space {background:#fff;color:#fff;} .error a {color:#8a1f11; background:none; padding:0; margin:0; } .notice a {color:#514721; background:none; padding:0; margin:0; } .success a {color:#264409; background:none; padding:0; margin:0; } -.left { text-align: left;} -.right {text-align: right;} .center {text-align: center;} - diff --git a/includes/kohana/modules/userguide/media/guide/css/shCore.css b/includes/kohana/modules/userguide/media/guide/css/shCore.css new file mode 100644 index 00000000..34f6864a --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/css/shCore.css @@ -0,0 +1,226 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter a, +.syntaxhighlighter div, +.syntaxhighlighter code, +.syntaxhighlighter table, +.syntaxhighlighter table td, +.syntaxhighlighter table tr, +.syntaxhighlighter table tbody, +.syntaxhighlighter table thead, +.syntaxhighlighter table caption, +.syntaxhighlighter textarea { + -moz-border-radius: 0 0 0 0 !important; + -webkit-border-radius: 0 0 0 0 !important; + background: none !important; + border: 0 !important; + bottom: auto !important; + float: none !important; + height: auto !important; + left: auto !important; + line-height: 1.1em !important; + margin: 0 !important; + outline: 0 !important; + overflow: visible !important; + padding: 0 !important; + position: static !important; + right: auto !important; + text-align: left !important; + top: auto !important; + vertical-align: baseline !important; + width: auto !important; + box-sizing: content-box !important; + font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace !important; + font-weight: normal !important; + font-style: normal !important; + font-size: 1em !important; + min-height: inherit !important; + min-height: auto !important; +} + +.syntaxhighlighter { + width: 100% !important; + margin: 1em 0 1em 0 !important; + position: relative !important; + overflow: auto !important; + font-size: 1em !important; +} +.syntaxhighlighter.source { + overflow: hidden !important; +} +.syntaxhighlighter .bold { + font-weight: bold !important; +} +.syntaxhighlighter .italic { + font-style: italic !important; +} +.syntaxhighlighter .line { + white-space: pre !important; +} +.syntaxhighlighter table { + width: 100% !important; +} +.syntaxhighlighter table caption { + text-align: left !important; + padding: .5em 0 0.5em 1em !important; +} +.syntaxhighlighter table td.code { + width: 100% !important; +} +.syntaxhighlighter table td.code .container { + position: relative !important; +} +.syntaxhighlighter table td.code .container textarea { + box-sizing: border-box !important; + position: absolute !important; + left: 0 !important; + top: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + background: white !important; + padding-left: 1em !important; + overflow: hidden !important; + white-space: pre !important; +} +.syntaxhighlighter table td.gutter .line { + text-align: right !important; + padding: 0 0.5em 0 1em !important; +} +.syntaxhighlighter table td.code .line { + padding: 0 1em !important; +} +.syntaxhighlighter.nogutter td.code .container textarea, .syntaxhighlighter.nogutter td.code .line { + padding-left: 0em !important; +} +.syntaxhighlighter.show { + display: block !important; +} +.syntaxhighlighter.collapsed table { + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar { + padding: 0.1em 0.8em 0em 0.8em !important; + font-size: 1em !important; + position: static !important; + width: auto !important; + height: auto !important; +} +.syntaxhighlighter.collapsed .toolbar span { + display: inline !important; + margin-right: 1em !important; +} +.syntaxhighlighter.collapsed .toolbar span a { + padding: 0 !important; + display: none !important; +} +.syntaxhighlighter.collapsed .toolbar span a.expandSource { + display: inline !important; +} +.syntaxhighlighter .toolbar { + position: absolute !important; + right: 1px !important; + top: 1px !important; + width: 11px !important; + height: 11px !important; + font-size: 10px !important; + z-index: 10 !important; +} +.syntaxhighlighter .toolbar span.title { + display: inline !important; +} +.syntaxhighlighter .toolbar a { + display: block !important; + text-align: center !important; + text-decoration: none !important; + padding-top: 1px !important; +} +.syntaxhighlighter .toolbar a.expandSource { + display: none !important; +} +.syntaxhighlighter.ie { + font-size: .9em !important; + padding: 1px 0 1px 0 !important; +} +.syntaxhighlighter.ie .toolbar { + line-height: 8px !important; +} +.syntaxhighlighter.ie .toolbar a { + padding-top: 0px !important; +} +.syntaxhighlighter.printing .line.alt1 .content, +.syntaxhighlighter.printing .line.alt2 .content, +.syntaxhighlighter.printing .line.highlighted .number, +.syntaxhighlighter.printing .line.highlighted.alt1 .content, +.syntaxhighlighter.printing .line.highlighted.alt2 .content { + background: none !important; +} +.syntaxhighlighter.printing .line .number { + color: #bbbbbb !important; +} +.syntaxhighlighter.printing .line .content { + color: black !important; +} +.syntaxhighlighter.printing .toolbar { + display: none !important; +} +.syntaxhighlighter.printing a { + text-decoration: none !important; +} +.syntaxhighlighter.printing .plain, .syntaxhighlighter.printing .plain a { + color: black !important; +} +.syntaxhighlighter.printing .comments, .syntaxhighlighter.printing .comments a { + color: #008200 !important; +} +.syntaxhighlighter.printing .string, .syntaxhighlighter.printing .string a { + color: blue !important; +} +.syntaxhighlighter.printing .keyword { + color: #006699 !important; + font-weight: bold !important; +} +.syntaxhighlighter.printing .preprocessor { + color: gray !important; +} +.syntaxhighlighter.printing .variable { + color: #aa7700 !important; +} +.syntaxhighlighter.printing .value { + color: #009900 !important; +} +.syntaxhighlighter.printing .functions { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .constants { + color: #0066cc !important; +} +.syntaxhighlighter.printing .script { + font-weight: bold !important; +} +.syntaxhighlighter.printing .color1, .syntaxhighlighter.printing .color1 a { + color: gray !important; +} +.syntaxhighlighter.printing .color2, .syntaxhighlighter.printing .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter.printing .color3, .syntaxhighlighter.printing .color3 a { + color: red !important; +} +.syntaxhighlighter.printing .break, .syntaxhighlighter.printing .break a { + color: black !important; +} diff --git a/includes/kohana/modules/userguide/media/guide/css/shThemeDefault.css b/includes/kohana/modules/userguide/media/guide/css/shThemeDefault.css new file mode 100644 index 00000000..13654117 --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/css/shThemeDefault.css @@ -0,0 +1,117 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +.syntaxhighlighter { + background-color: white !important; +} +.syntaxhighlighter .line.alt1 { + background-color: white !important; +} +.syntaxhighlighter .line.alt2 { + background-color: white !important; +} +.syntaxhighlighter .line.highlighted.alt1, .syntaxhighlighter .line.highlighted.alt2 { + background-color: #e0e0e0 !important; +} +.syntaxhighlighter .line.highlighted.number { + color: black !important; +} +.syntaxhighlighter table caption { + color: black !important; +} +.syntaxhighlighter .gutter { + color: #afafaf !important; +} +.syntaxhighlighter .gutter .line { + border-right: 3px solid #6ce26c !important; +} +.syntaxhighlighter .gutter .line.highlighted { + background-color: #6ce26c !important; + color: white !important; +} +.syntaxhighlighter.printing .line .content { + border: none !important; +} +.syntaxhighlighter.collapsed { + overflow: visible !important; +} +.syntaxhighlighter.collapsed .toolbar { + color: blue !important; + background: white !important; + border: 1px solid #6ce26c !important; +} +.syntaxhighlighter.collapsed .toolbar a { + color: blue !important; +} +.syntaxhighlighter.collapsed .toolbar a:hover { + color: red !important; +} +.syntaxhighlighter .toolbar { + color: white !important; + background: #6ce26c !important; + border: none !important; +} +.syntaxhighlighter .toolbar a { + color: white !important; +} +.syntaxhighlighter .toolbar a:hover { + color: black !important; +} +.syntaxhighlighter .plain, .syntaxhighlighter .plain a { + color: black !important; +} +.syntaxhighlighter .comments, .syntaxhighlighter .comments a { + color: #008200 !important; +} +.syntaxhighlighter .string, .syntaxhighlighter .string a { + color: blue !important; +} +.syntaxhighlighter .keyword { + color: #006699 !important; +} +.syntaxhighlighter .preprocessor { + color: gray !important; +} +.syntaxhighlighter .variable { + color: #aa7700 !important; +} +.syntaxhighlighter .value { + color: #009900 !important; +} +.syntaxhighlighter .functions { + color: #ff1493 !important; +} +.syntaxhighlighter .constants { + color: #0066cc !important; +} +.syntaxhighlighter .script { + font-weight: bold !important; + color: #006699 !important; + background-color: none !important; +} +.syntaxhighlighter .color1, .syntaxhighlighter .color1 a { + color: gray !important; +} +.syntaxhighlighter .color2, .syntaxhighlighter .color2 a { + color: #ff1493 !important; +} +.syntaxhighlighter .color3, .syntaxhighlighter .color3 a { + color: red !important; +} + +.syntaxhighlighter .keyword { + font-weight: bold !important; +} diff --git a/includes/kohana/modules/userguide/media/css/shThemeKodoc.css b/includes/kohana/modules/userguide/media/guide/css/shThemeKodoc.css similarity index 100% rename from includes/kohana/modules/userguide/media/css/shThemeKodoc.css rename to includes/kohana/modules/userguide/media/guide/css/shThemeKodoc.css diff --git a/includes/kohana/modules/userguide/media/guide/img/arrows.png b/includes/kohana/modules/userguide/media/guide/img/arrows.png new file mode 100644 index 00000000..e10a3cab Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/arrows.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/breadcrumbs.png b/includes/kohana/modules/userguide/media/guide/img/breadcrumbs.png new file mode 100644 index 00000000..04b9e028 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/breadcrumbs.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/content.png b/includes/kohana/modules/userguide/media/guide/img/content.png new file mode 100644 index 00000000..29be8c6e Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/content.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/ext_link.png b/includes/kohana/modules/userguide/media/guide/img/ext_link.png new file mode 100644 index 00000000..16f9b92d Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/ext_link.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/h2_line.png b/includes/kohana/modules/userguide/media/guide/img/h2_line.png new file mode 100644 index 00000000..1e59ea44 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/h2_line.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/h3_line.png b/includes/kohana/modules/userguide/media/guide/img/h3_line.png new file mode 100644 index 00000000..82459f5b Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/h3_line.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/header.png b/includes/kohana/modules/userguide/media/guide/img/header.png new file mode 100644 index 00000000..07b1dd38 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/header.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/kohana.png b/includes/kohana/modules/userguide/media/guide/img/kohana.png new file mode 100644 index 00000000..f0583ef7 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/kohana.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/lightbulb_48.png b/includes/kohana/modules/userguide/media/guide/img/lightbulb_48.png new file mode 100644 index 00000000..f84346e4 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/lightbulb_48.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/lines.png b/includes/kohana/modules/userguide/media/guide/img/lines.png new file mode 100644 index 00000000..e017fc22 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/lines.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/orange-tab.png b/includes/kohana/modules/userguide/media/guide/img/orange-tab.png new file mode 100644 index 00000000..f8c6fcd3 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/orange-tab.png differ diff --git a/includes/kohana/modules/userguide/media/guide/img/wrapper.png b/includes/kohana/modules/userguide/media/guide/img/wrapper.png new file mode 100644 index 00000000..bcfa8715 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/img/wrapper.png differ diff --git a/includes/kohana/modules/userguide/media/guide/js/jquery.cookie.js b/includes/kohana/modules/userguide/media/guide/js/jquery.cookie.js new file mode 100644 index 00000000..6df1faca --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/js/jquery.cookie.js @@ -0,0 +1,96 @@ +/** + * Cookie plugin + * + * Copyright (c) 2006 Klaus Hartl (stilbuero.de) + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + */ + +/** + * Create a cookie with the given name and value and other optional parameters. + * + * @example $.cookie('the_cookie', 'the_value'); + * @desc Set the value of a cookie. + * @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true }); + * @desc Create a cookie with all available options. + * @example $.cookie('the_cookie', 'the_value'); + * @desc Create a session cookie. + * @example $.cookie('the_cookie', null); + * @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain + * used when the cookie was set. + * + * @param String name The name of the cookie. + * @param String value The value of the cookie. + * @param Object options An object literal containing key/value pairs to provide optional cookie attributes. + * @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object. + * If a negative value is specified (e.g. a date in the past), the cookie will be deleted. + * If set to null or omitted, the cookie will be a session cookie and will not be retained + * when the the browser exits. + * @option String path The value of the path atribute of the cookie (default: path of page that created the cookie). + * @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie). + * @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will + * require a secure protocol (like HTTPS). + * @type undefined + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ + +/** + * Get the value of a cookie with the given name. + * + * @example $.cookie('the_cookie'); + * @desc Get the value of a cookie. + * + * @param String name The name of the cookie. + * @return The value of the cookie. + * @type String + * + * @name $.cookie + * @cat Plugins/Cookie + * @author Klaus Hartl/klaus.hartl@stilbuero.de + */ +jQuery.cookie = function(name, value, options) { + if (typeof value != 'undefined') { // name and value given, set cookie + options = options || {}; + if (value === null) { + value = ''; + options.expires = -1; + } + var expires = ''; + if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) { + var date; + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else { + date = options.expires; + } + expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE + } + // CAUTION: Needed to parenthesize options.path and options.domain + // in the following expressions, otherwise they evaluate to undefined + // in the packed version for some reason... + var path = options.path ? '; path=' + (options.path) : ''; + var domain = options.domain ? '; domain=' + (options.domain) : ''; + var secure = options.secure ? '; secure' : ''; + document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); + } else { // only name given, get cookie + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + // Does this cookie string begin with the name we want? + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } +}; \ No newline at end of file diff --git a/includes/kohana/modules/userguide/media/guide/js/jquery.min.js b/includes/kohana/modules/userguide/media/guide/js/jquery.min.js new file mode 100644 index 00000000..8f3ca2e2 --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/js/jquery.min.js @@ -0,0 +1,167 @@ +/*! + * jQuery JavaScript Library v1.4.4 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Thu Nov 11 19:04:53 2010 -0500 + */ +(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h= +h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;kd)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La, +"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this, +e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a, +"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+ +a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/, +C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j, +s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this, +j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length}, +toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j=== +-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false; +if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload", +b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&& +!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&& +l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H
PECL HTTP EnabledPassKohana can use the http extension for the Request_Client_External class.
cURL Enabled Pass Kohana requires cURL for the Remote class.Kohana can use the cURL extension for the Request_Client_External class.
Kohana requires GD v2 for the Image class.
MySQL EnabledPassKohana can use the MySQL extension to support MySQL databases.
PDO Enabled
a";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"), +k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false, +scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent= +false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom= +1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="
";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="
t
";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display= +"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h= +c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando); +else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one"; +if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true}, +attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&& +b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0}; +c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem, +arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid= +d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+ +c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType=== +8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k=== +"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+ +d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired= +B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type=== +"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]=== +0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}}); +(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3]; +break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr, +q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h= +l;g.sort(w);if(h)for(var i=1;i0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n, +m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled=== +true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"=== +g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return in[3]-0},nth:function(g,i,n){return n[3]- +0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()=== +i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]]; +if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m, +g);else if(typeof g.length==="number")for(var p=g.length;n";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g); +n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&& +function(){var g=k,i=t.createElement("div");i.innerHTML="

";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F|| +p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g= +t.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition? +function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n0)for(var h=d;h0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h= +h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context): +c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a, +2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a, +b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&& +e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/\s]+\/)>/g,P={option:[1, +""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= +c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, +wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, +prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, +this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); +return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null; +else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1>");try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append", +prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument|| +b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]===""&&!x?r.childNodes:[];for(o=k.length- +1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script")))); +d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i, +jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true, +zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b), +h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b); +if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f= +d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left; +e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/)<[^<]*)*<\/script>/gi, +ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b=== +"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("
").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&& +!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})}, +getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html", +script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data|| +!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache= +false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset; +A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type", +b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&& +c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d|| +c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]= +encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess", +[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"), +e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}}); +if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show", +3),a,b,d);else{d=0;for(var e=this.length;d=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b, +d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a* +Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)} +var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true; +this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide|| +this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a= +c.timers,b=0;b-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a, +e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&& +c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase(); +c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+ +b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window); diff --git a/includes/kohana/modules/userguide/media/guide/js/kodoc.js b/includes/kohana/modules/userguide/media/guide/js/kodoc.js new file mode 100644 index 00000000..70d8b488 --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/js/kodoc.js @@ -0,0 +1,97 @@ +$(document).ready(function() +{ + +// Syntax highlighter + + $('pre:not(.debug) code').each(function() + { + $(this).addClass('brush: php, class-name: highlighted'); + }); + + SyntaxHighlighter.config.tagName = 'code'; + // Don't show the toolbar or line-numbers. + SyntaxHighlighter.defaults.gutter = false; + SyntaxHighlighter.all(); + + // Any link that has the current page as its href should be class="current" + $('a[href="'+ window.location.pathname +'"]').addClass('current'); + + // Breadcrumbs magic + $('#breadcrumb li.last').each(function() + { + var $this = $(this); + var $topics = $('#topics li').has('a.current').slice(0, -1); + + $topics.each(function() + { + // Create a copy of the menu link + var $crumb = $(this).children('a:first, span:not(.toggle):first').clone(); + + // Insert the menu link into the breadcrumbs + $('
  • ').html($crumb).insertBefore($this); + }); + }); + + // Collapsing menus + $('#topics li:has(li)').each(function() + { + var $this = $(this); + var toggle = $(''); + var menu = $this.find('>ul,>ol'); + + toggle.click(function() + { + if (menu.is(':visible')) + { + menu.stop(true, true).slideUp('fast'); + toggle.html('+'); + } + else + { + menu.stop(true, true).slideDown('fast'); + toggle.html('–'); + } + }); + + $this.find('>span').click(function() + { + // Menu without a link + toggle.click(); + }); + + if ( ! $this.is(':has(a.current)')) + { + menu.hide(); + } + + toggle.html(menu.is(':visible') ? '–' : '+').prependTo($this); + }); + +// Show source links + + $('#kodoc-main .method-source').each(function() + { + var self = $(this); + var togg = $(' [show]').appendTo($('h4', self)); + var code = self.find('pre').hide(); + + togg.toggle(function() + { + togg.html('[hide]'); + code.stop(true, true).slideDown(); + }, + function() + { + togg.html('[show]'); + code.stop(true, true).slideUp(); + }); + }); + + // "Link to this" link that appears when you hover over a header + $('#body') + .find('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]') + .append(function(){ + var $this = $(this); + return ''; + }); +}); diff --git a/includes/kohana/modules/userguide/media/guide/js/shBrushPhp.js b/includes/kohana/modules/userguide/media/guide/js/shBrushPhp.js new file mode 100644 index 00000000..95e6e432 --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/js/shBrushPhp.js @@ -0,0 +1,88 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +;(function() +{ + // CommonJS + typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null; + + function Brush() + { + var funcs = 'abs acos acosh addcslashes addslashes ' + + 'array_change_key_case array_chunk array_combine array_count_values array_diff '+ + 'array_diff_assoc array_diff_key array_diff_uassoc array_diff_ukey array_fill '+ + 'array_filter array_flip array_intersect array_intersect_assoc array_intersect_key '+ + 'array_intersect_uassoc array_intersect_ukey array_key_exists array_keys array_map '+ + 'array_merge array_merge_recursive array_multisort array_pad array_pop array_product '+ + 'array_push array_rand array_reduce array_reverse array_search array_shift '+ + 'array_slice array_splice array_sum array_udiff array_udiff_assoc '+ + 'array_udiff_uassoc array_uintersect array_uintersect_assoc '+ + 'array_uintersect_uassoc array_unique array_unshift array_values array_walk '+ + 'array_walk_recursive atan atan2 atanh base64_decode base64_encode base_convert '+ + 'basename bcadd bccomp bcdiv bcmod bcmul bindec bindtextdomain bzclose bzcompress '+ + 'bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite ceil chdir '+ + 'checkdate checkdnsrr chgrp chmod chop chown chr chroot chunk_split class_exists '+ + 'closedir closelog copy cos cosh count count_chars date decbin dechex decoct '+ + 'deg2rad delete ebcdic2ascii echo empty end ereg ereg_replace eregi eregi_replace error_log '+ + 'error_reporting escapeshellarg escapeshellcmd eval exec exit exp explode extension_loaded '+ + 'feof fflush fgetc fgetcsv fgets fgetss file_exists file_get_contents file_put_contents '+ + 'fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype '+ + 'floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv fputs fread fscanf '+ + 'fseek fsockopen fstat ftell ftok getallheaders getcwd getdate getenv gethostbyaddr gethostbyname '+ + 'gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid getmyuid getopt '+ + 'getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext '+ + 'gettimeofday gettype glob gmdate gmmktime ini_alter ini_get ini_get_all ini_restore ini_set '+ + 'interface_exists intval ip2long is_a is_array is_bool is_callable is_dir is_double '+ + 'is_executable is_file is_finite is_float is_infinite is_int is_integer is_link is_long '+ + 'is_nan is_null is_numeric is_object is_readable is_real is_resource is_scalar is_soap_fault '+ + 'is_string is_subclass_of is_uploaded_file is_writable is_writeable mkdir mktime nl2br '+ + 'parse_ini_file parse_str parse_url passthru pathinfo print readlink realpath rewind rewinddir rmdir '+ + 'round str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split '+ + 'str_word_count strcasecmp strchr strcmp strcoll strcspn strftime strip_tags stripcslashes '+ + 'stripos stripslashes stristr strlen strnatcasecmp strnatcmp strncasecmp strncmp strpbrk '+ + 'strpos strptime strrchr strrev strripos strrpos strspn strstr strtok strtolower strtotime '+ + 'strtoupper strtr strval substr substr_compare'; + + var keywords = 'abstract and array as break case catch cfunction class clone const continue declare default die do ' + + 'else elseif enddeclare endfor endforeach endif endswitch endwhile extends final for foreach ' + + 'function include include_once global goto if implements interface instanceof namespace new ' + + 'old_function or private protected public return require require_once static switch ' + + 'throw try use var while xor '; + + var constants = '__FILE__ __LINE__ __METHOD__ __FUNCTION__ __CLASS__'; + + this.regexList = [ + { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments + { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments + { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings + { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings + { regex: /\$\w+/g, css: 'variable' }, // variables + { regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'functions' }, // common functions + { regex: new RegExp(this.getKeywords(constants), 'gmi'), css: 'constants' }, // constants + { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keyword + ]; + + this.forHtmlScript(SyntaxHighlighter.regexLib.phpScriptTags); + }; + + Brush.prototype = new SyntaxHighlighter.Highlighter(); + Brush.aliases = ['php']; + + SyntaxHighlighter.brushes.Php = Brush; + + // CommonJS + typeof(exports) != 'undefined' ? exports.Brush = Brush : null; +})(); diff --git a/includes/kohana/modules/userguide/media/guide/js/shCore.js b/includes/kohana/modules/userguide/media/guide/js/shCore.js new file mode 100644 index 00000000..b47b6454 --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/js/shCore.js @@ -0,0 +1,17 @@ +/** + * SyntaxHighlighter + * http://alexgorbatchev.com/SyntaxHighlighter + * + * SyntaxHighlighter is donationware. If you are using it, please donate. + * http://alexgorbatchev.com/SyntaxHighlighter/donate.html + * + * @version + * 3.0.83 (July 02 2010) + * + * @copyright + * Copyright (C) 2004-2010 Alex Gorbatchev. + * + * @license + * Dual licensed under the MIT and GPL licenses. + */ +eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('K M;I(M)1S 2U("2a\'t 4k M 4K 2g 3l 4G 4H");(6(){6 r(f,e){I(!M.1R(f))1S 3m("3s 15 4R");K a=f.1w;f=M(f.1m,t(f)+(e||""));I(a)f.1w={1m:a.1m,19:a.19?a.19.1a(0):N};H f}6 t(f){H(f.1J?"g":"")+(f.4s?"i":"")+(f.4p?"m":"")+(f.4v?"x":"")+(f.3n?"y":"")}6 B(f,e,a,b){K c=u.L,d,h,g;v=R;5K{O(;c--;){g=u[c];I(a&g.3r&&(!g.2p||g.2p.W(b))){g.2q.12=e;I((h=g.2q.X(f))&&h.P===e){d={3k:g.2b.W(b,h,a),1C:h};1N}}}}5v(i){1S i}5q{v=11}H d}6 p(f,e,a){I(3b.Z.1i)H f.1i(e,a);O(a=a||0;a-1},3d:6(g){e+=g}};c1&&p(e,"")>-1){a=15(J.1m,n.Q.W(t(J),"g",""));n.Q.W(f.1a(e.P),a,6(){O(K c=1;c<14.L-2;c++)I(14[c]===1d)e[c]=1d})}I(J.1w&&J.1w.19)O(K b=1;be.P&&J.12--}H e};I(!D)15.Z.1A=6(f){(f=n.X.W(J,f))&&J.1J&&!f[0].L&&J.12>f.P&&J.12--;H!!f};1r.Z.1C=6(f){M.1R(f)||(f=15(f));I(f.1J){K e=n.1C.1p(J,14);f.12=0;H e}H f.X(J)};1r.Z.Q=6(f,e){K a=M.1R(f),b,c;I(a&&1j e.58()==="3f"&&e.1i("${")===-1&&y)H n.Q.1p(J,14);I(a){I(f.1w)b=f.1w.19}Y f+="";I(1j e==="6")c=n.Q.W(J,f,6(){I(b){14[0]=1f 1r(14[0]);O(K d=0;dd.L-3;){i=1r.Z.1a.W(g,-1)+i;g=1Q.3i(g/10)}H(g?d[g]||"":"$")+i}Y{g=+i;I(g<=d.L-3)H d[g];g=b?p(b,i):-1;H g>-1?d[g+1]:h}})})}I(a&&f.1J)f.12=0;H c};1r.Z.1e=6(f,e){I(!M.1R(f))H n.1e.1p(J,14);K a=J+"",b=[],c=0,d,h;I(e===1d||+e<0)e=5D;Y{e=1Q.3i(+e);I(!e)H[]}O(f=M.3c(f);d=f.X(a);){I(f.12>c){b.U(a.1a(c,d.P));d.L>1&&d.P=e)1N}f.12===d.P&&f.12++}I(c===a.L){I(!n.1A.W(f,"")||h)b.U("")}Y b.U(a.1a(c));H b.L>e?b.1a(0,e):b};M.1h(/\\(\\?#[^)]*\\)/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"});M.1h(/\\((?!\\?)/,6(){J.19.U(N);H"("});M.1h(/\\(\\?<([$\\w]+)>/,6(f){J.19.U(f[1]);J.2N=R;H"("});M.1h(/\\\\k<([\\w$]+)>/,6(f){K e=p(J.19,f[1]);H e>-1?"\\\\"+(e+1)+(3R(f.2S.3a(f.P+f[0].L))?"":"(?:)"):f[0]});M.1h(/\\[\\^?]/,6(f){H f[0]==="[]"?"\\\\b\\\\B":"[\\\\s\\\\S]"});M.1h(/^\\(\\?([5A]+)\\)/,6(f){J.3d(f[1]);H""});M.1h(/(?:\\s+|#.*)+/,6(f){H n.1A.W(A,f.2S.1a(f.P+f[0].L))?"":"(?:)"},M.1B,6(){H J.2K("x")});M.1h(/\\./,6(){H"[\\\\s\\\\S]"},M.1B,6(){H J.2K("s")})})();1j 2e!="1d"&&(2e.M=M);K 1v=6(){6 r(a,b){a.1l.1i(b)!=-1||(a.1l+=" "+b)}6 t(a){H a.1i("3e")==0?a:"3e"+a}6 B(a){H e.1Y.2A[t(a)]}6 p(a,b,c){I(a==N)H N;K d=c!=R?a.3G:[a.2G],h={"#":"1c",".":"1l"}[b.1o(0,1)]||"3h",g,i;g=h!="3h"?b.1o(1):b.5u();I((a[h]||"").1i(g)!=-1)H a;O(a=0;d&&a\'+c+""});H a}6 n(a,b){a.1e("\\n");O(K c="",d=0;d<50;d++)c+=" ";H a=v(a,6(h){I(h.1i("\\t")==-1)H h;O(K g=0;(g=h.1i("\\t"))!=-1;)h=h.1o(0,g)+c.1o(0,b-g%b)+h.1o(g+1,h.L);H h})}6 x(a){H a.Q(/^\\s+|\\s+$/g,"")}6 D(a,b){I(a.Pb.P)H 1;Y I(a.Lb.L)H 1;H 0}6 y(a,b){6 c(k){H k[0]}O(K d=N,h=[],g=b.2D?b.2D:c;(d=b.1I.X(a))!=N;){K i=g(d,b);I(1j i=="3f")i=[1f e.2L(i,d.P,b.23)];h=h.1O(i)}H h}6 E(a){K b=/(.*)((&1G;|&1y;).*)/;H a.Q(e.3A.3M,6(c){K d="",h=N;I(h=b.X(c)){c=h[1];d=h[2]}H\'\'+c+""+d})}6 z(){O(K a=1E.36("1k"),b=[],c=0;c<1z 4I="1Z://2y.3L.3K/4L/5L"><3J><4N 1Z-4M="5G-5M" 6K="2O/1z; 6J=6I-8" /><1t>6L 1v<3B 1L="25-6M:6Q,6P,6O,6N-6F;6y-2f:#6x;2f:#6w;25-22:6v;2O-3D:3C;">1v3v 3.0.76 (72 73 3x)1Z://3u.2w/1v70 17 6U 71.6T 6X-3x 6Y 6D.6t 61 60 J 1k, 5Z 5R 5V <2R/>5U 5T 5S!\'}},1Y:{2j:N,2A:{}},1U:{},3A:{6n:/\\/\\*[\\s\\S]*?\\*\\//2c,6m:/\\/\\/.*$/2c,6l:/#.*$/2c,6k:/"([^\\\\"\\n]|\\\\.)*"/g,6o:/\'([^\\\\\'\\n]|\\\\.)*\'/g,6p:1f M(\'"([^\\\\\\\\"]|\\\\\\\\.)*"\',"3z"),6s:1f M("\'([^\\\\\\\\\']|\\\\\\\\.)*\'","3z"),6q:/(&1y;|<)!--[\\s\\S]*?--(&1G;|>)/2c,3M:/\\w+:\\/\\/[\\w-.\\/?%&=:@;]*/g,6a:{18:/(&1y;|<)\\?=?/g,1b:/\\?(&1G;|>)/g},69:{18:/(&1y;|<)%=?/g,1b:/%(&1G;|>)/g},6d:{18:/(&1y;|<)\\s*1k.*?(&1G;|>)/2T,1b:/(&1y;|<)\\/\\s*1k\\s*(&1G;|>)/2T}},16:{1H:6(a){6 b(i,k){H e.16.2o(i,k,e.13.1x[k])}O(K c=\'\',d=e.16.2x,h=d.2X,g=0;g";H c},2o:6(a,b,c){H\'<2W>\'+c+""},2b:6(a){K b=a.1F,c=b.1l||"";b=B(p(b,".20",R).1c);K d=6(h){H(h=15(h+"6f(\\\\w+)").X(c))?h[1]:N}("6g");b&&d&&e.16.2x[d].2B(b);a.3N()},2x:{2X:["21","2P"],21:{1H:6(a){I(a.V("2l")!=R)H"";K b=a.V("1t");H e.16.2o(a,"21",b?b:e.13.1x.21)},2B:6(a){a=1E.6j(t(a.1c));a.1l=a.1l.Q("47","")}},2P:{2B:6(){K a="68=0";a+=", 18="+(31.30-33)/2+", 32="+(31.2Z-2Y)/2+", 30=33, 2Z=2Y";a=a.Q(/^,/,"");a=1P.6Z("","38",a);a.2C();K b=a.1E;b.6W(e.13.1x.37);b.6V();a.2C()}}}},35:6(a,b){K c;I(b)c=[b];Y{c=1E.36(e.13.34);O(K d=[],h=0;h(.*?))\\\\]$"),s=1f M("(?<27>[\\\\w-]+)\\\\s*:\\\\s*(?<1T>[\\\\w-%#]+|\\\\[.*?\\\\]|\\".*?\\"|\'.*?\')\\\\s*;?","g");(j=s.X(k))!=N;){K o=j.1T.Q(/^[\'"]|[\'"]$/g,"");I(o!=N&&m.1A(o)){o=m.X(o);o=o.2V.L>0?o.2V.1e(/\\s*,\\s*/):[]}l[j.27]=o}g={1F:g,1n:C(i,l)};g.1n.1D!=N&&d.U(g)}H d},1M:6(a,b){K c=J.35(a,b),d=N,h=e.13;I(c.L!==0)O(K g=0;g")==o-3){m=m.4h(0,o-3);s=R}l=s?m:l}I((i.1t||"")!="")k.1t=i.1t;k.1D=j;d.2Q(k);b=d.2F(l);I((i.1c||"")!="")b.1c=i.1c;i.2G.74(b,i)}}},2E:6(a){w(1P,"4k",6(){e.1M(a)})}};e.2E=e.2E;e.1M=e.1M;e.2L=6(a,b,c){J.1T=a;J.P=b;J.L=a.L;J.23=c;J.1V=N};e.2L.Z.1q=6(){H J.1T};e.4l=6(a){6 b(j,l){O(K m=0;md)1N;Y I(g.P==c.P&&g.L>c.L)a[b]=N;Y I(g.P>=c.P&&g.P\'+c+""},3Q:6(a,b){K c="",d=a.1e("\\n").L,h=2u(J.V("2i-1s")),g=J.V("2z-1s-2t");I(g==R)g=(h+d-1).1q().L;Y I(3R(g)==R)g=0;O(K i=0;i\'+j+"":"")+i)}H a},4f:6(a){H a?"<4a>"+a+"":""},4b:6(a,b){6 c(l){H(l=l?l.1V||g:g)?l+" ":""}O(K d=0,h="",g=J.V("1D",""),i=0;i|&1y;2R\\s*\\/?&1G;/2T;I(e.13.46==R)b=b.Q(h,"\\n");I(e.13.44==R)b=b.Q(h,"");b=b.1e("\\n");h=/^\\s*/;g=4Q;O(K i=0;i0;i++){K k=b[i];I(x(k).L!=0){k=h.X(k);I(k==N){a=a;1N a}g=1Q.4q(k[0].L,g)}}I(g>0)O(i=0;i\'+(J.V("16")?e.16.1H(J):"")+\'<3Z 5z="0" 5H="0" 5J="0">\'+J.4f(J.V("1t"))+"<3T><3P>"+(1u?\'<2d 1g="1u">\'+J.3Q(a)+"":"")+\'<2d 1g="17">\'+b+""},2F:6(a){I(a===N)a="";J.17=a;K b=J.3Y("T");b.3X=J.1H(a);J.V("16")&&w(p(b,".16"),"5c",e.16.2b);J.V("3V-17")&&w(p(b,".17"),"56",f);H b},2Q:6(a){J.1c=""+1Q.5d(1Q.5n()*5k).1q();e.1Y.2A[t(J.1c)]=J;J.1n=C(e.2v,a||{});I(J.V("2k")==R)J.1n.16=J.1n.1u=11},5j:6(a){a=a.Q(/^\\s+|\\s+$/g,"").Q(/\\s+/g,"|");H"\\\\b(?:"+a+")\\\\b"},5f:6(a){J.28={18:{1I:a.18,23:"1k"},1b:{1I:a.1b,23:"1k"},17:1f M("(?<18>"+a.18.1m+")(?<17>.*?)(?<1b>"+a.1b.1m+")","5o")}}};H e}();1j 2e!="1d"&&(2e.1v=1v);',62,441,'||||||function|||||||||||||||||||||||||||||||||||||return|if|this|var|length|XRegExp|null|for|index|replace|true||div|push|getParam|call|exec|else|prototype||false|lastIndex|config|arguments|RegExp|toolbar|code|left|captureNames|slice|right|id|undefined|split|new|class|addToken|indexOf|typeof|script|className|source|params|substr|apply|toString|String|line|title|gutter|SyntaxHighlighter|_xregexp|strings|lt|html|test|OUTSIDE_CLASS|match|brush|document|target|gt|getHtml|regex|global|join|style|highlight|break|concat|window|Math|isRegExp|throw|value|brushes|brushName|space|alert|vars|http|syntaxhighlighter|expandSource|size|css|case|font|Fa|name|htmlScript|dA|can|handler|gm|td|exports|color|in|href|first|discoveredBrushes|light|collapse|object|cache|getButtonHtml|trigger|pattern|getLineHtml|nbsp|numbers|parseInt|defaults|com|items|www|pad|highlighters|execute|focus|func|all|getDiv|parentNode|navigator|INSIDE_CLASS|regexList|hasFlag|Match|useScriptTags|hasNamedCapture|text|help|init|br|input|gi|Error|values|span|list|250|height|width|screen|top|500|tagName|findElements|getElementsByTagName|aboutDialog|_blank|appendChild|charAt|Array|copyAsGlobal|setFlag|highlighter_|string|attachEvent|nodeName|floor|backref|output|the|TypeError|sticky|Za|iterate|freezeTokens|scope|type|textarea|alexgorbatchev|version|margin|2010|005896|gs|regexLib|body|center|align|noBrush|require|childNodes|DTD|xhtml1|head|org|w3|url|preventDefault|container|tr|getLineNumbersHtml|isNaN|userAgent|tbody|isLineHighlighted|quick|void|innerHTML|create|table|links|auto|smart|tab|stripBrs|tabs|bloggerMode|collapsed|plain|getCodeLinesHtml|caption|getMatchesHtml|findMatches|figureOutLineNumbers|removeNestedMatches|getTitleHtml|brushNotHtmlScript|substring|createElement|Highlighter|load|HtmlScript|Brush|pre|expand|multiline|min|Can|ignoreCase|find|blur|extended|toLowerCase|aliases|addEventListener|innerText|textContent|wasn|select|createTextNode|removeChild|option|same|frame|xmlns|dtd|twice|1999|equiv|meta|htmlscript|transitional|1E3|expected|PUBLIC|DOCTYPE|on|W3C|XHTML|TR|EN|Transitional||configured|srcElement|Object|after|run|dblclick|matchChain|valueOf|constructor|default|switch|click|round|execAt|forHtmlScript|token|gimy|functions|getKeywords|1E6|escape|within|random|sgi|another|finally|supply|MSIE|ie|toUpperCase|catch|returnValue|definition|event|border|imsx|constructing|one|Infinity|from|when|Content|cellpadding|flags|cellspacing|try|xhtml|Type|spaces|2930402|hosted_button_id|lastIndexOf|donate|active|development|keep|to|xclick|_s|Xml|please|like|you|paypal|cgi|cmd|webscr|bin|highlighted|scrollbars|aspScriptTags|phpScriptTags|sort|max|scriptScriptTags|toolbar_item|_|command|command_|number|getElementById|doubleQuotedString|singleLinePerlComments|singleLineCComments|multiLineCComments|singleQuotedString|multiLineDoubleQuotedString|xmlComments|alt|multiLineSingleQuotedString|If|https|1em|000|fff|background|5em|xx|bottom|75em|Gorbatchev|large|serif|CDATA|continue|utf|charset|content|About|family|sans|Helvetica|Arial|Geneva|3em|nogutter|Copyright|syntax|close|write|2004|Alex|open|JavaScript|highlighter|July|02|replaceChild|offset|83'.split('|'),0,{})) diff --git a/includes/kohana/modules/userguide/media/guide/js/sizzle.js b/includes/kohana/modules/userguide/media/guide/js/sizzle.js new file mode 100644 index 00000000..c52b77d1 --- /dev/null +++ b/includes/kohana/modules/userguide/media/guide/js/sizzle.js @@ -0,0 +1,1068 @@ +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + context = context || document; + + var origContext = context; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, extra, prune = true, contextXML = Sizzle.isXML(context), + soFar = selector, ret, cur, pop, i; + + // Reset the position of the chunker regexp (start from head) + do { + chunker.exec(""); + m = chunker.exec(soFar); + + if ( m ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + } while ( m ); + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + cur = parts.pop(); + pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && Sizzle.isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var filter = Expr.filter[ type ], found, item, left = match[1]; + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part){ + var isPartStr = typeof part === "string", + elem, i = 0, l = checkSet.length; + + if ( isPartStr && !/\W/.test(part) ) { + part = part.toLowerCase(); + + for ( ; i < l; i++ ) { + elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + } else { + for ( ; i < l; i++ ) { + elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck, nodeCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck, nodeCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + part = part.toLowerCase(); + nodeCheck = part; + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + return match[1].toLowerCase(); + }, + CHILD: function(match){ + if ( match[1] === "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return (/h\d/i).test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + input: function(elem){ + return (/input|select|textarea|button/i).test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 === i; + }, + eq: function(elem, i, match){ + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var j = 0, l = not.length; j < l; j++ ) { + if ( not[j] === elem ) { + return false; + } + } + + return true; + } else { + Sizzle.error( "Syntax error, unrecognized expression: " + name ); + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + if ( type === "first" ) { + return true; + } + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first === 0 ) { + return diff === 0; + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS, + fescape = function(all, num){ + return "\\" + (num - 0 + 1); + }; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) ); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || [], i = 0; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( ; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.compareDocumentPosition ? -1 : 1; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.sourceIndex ? -1 : 1; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.ownerDocument ? -1 : 1; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +Sizzle.getText = function( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += Sizzle.getText( elem.childNodes ); + } + } + + return ret; +}; + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date()).getTime(); + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

    "; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !Sizzle.isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE + })(); +} + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
    "; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +Sizzle.contains = document.compareDocumentPosition ? function(a, b){ + return !!(a.compareDocumentPosition(b) & 16); +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +Sizzle.isXML = function(elem){ + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE + +window.Sizzle = Sizzle; + +})(); diff --git a/includes/kohana/modules/userguide/media/guide/userguide/contrib-github-edit.png b/includes/kohana/modules/userguide/media/guide/userguide/contrib-github-edit.png new file mode 100644 index 00000000..b90eb91a Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/userguide/contrib-github-edit.png differ diff --git a/includes/kohana/modules/userguide/media/guide/userguide/contrib-github-fork.png b/includes/kohana/modules/userguide/media/guide/userguide/contrib-github-fork.png new file mode 100644 index 00000000..a557b834 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/userguide/contrib-github-fork.png differ diff --git a/includes/kohana/modules/userguide/media/guide/userguide/contrib-github-pull.png b/includes/kohana/modules/userguide/media/guide/userguide/contrib-github-pull.png new file mode 100644 index 00000000..e2bc6021 Binary files /dev/null and b/includes/kohana/modules/userguide/media/guide/userguide/contrib-github-pull.png differ diff --git a/includes/kohana/modules/userguide/media/img/cascading_filesystem.png b/includes/kohana/modules/userguide/media/img/cascading_filesystem.png deleted file mode 100644 index d450f7b9..00000000 Binary files a/includes/kohana/modules/userguide/media/img/cascading_filesystem.png and /dev/null differ diff --git a/includes/kohana/modules/userguide/media/img/hello_world_2_error.png b/includes/kohana/modules/userguide/media/img/hello_world_2_error.png deleted file mode 100644 index 78f65d5f..00000000 Binary files a/includes/kohana/modules/userguide/media/img/hello_world_2_error.png and /dev/null differ diff --git a/includes/kohana/modules/userguide/media/img/install.png b/includes/kohana/modules/userguide/media/img/install.png deleted file mode 100644 index 00b926ea..00000000 Binary files a/includes/kohana/modules/userguide/media/img/install.png and /dev/null differ diff --git a/includes/kohana/modules/userguide/media/img/note.png b/includes/kohana/modules/userguide/media/img/note.png deleted file mode 100644 index 0814a531..00000000 Binary files a/includes/kohana/modules/userguide/media/img/note.png and /dev/null differ diff --git a/includes/kohana/modules/userguide/media/img/welcome.png b/includes/kohana/modules/userguide/media/img/welcome.png deleted file mode 100644 index 8cad7a84..00000000 Binary files a/includes/kohana/modules/userguide/media/img/welcome.png and /dev/null differ diff --git a/includes/kohana/modules/userguide/media/js/jquery.min.js b/includes/kohana/modules/userguide/media/js/jquery.min.js deleted file mode 100644 index 48a88b8f..00000000 --- a/includes/kohana/modules/userguide/media/js/jquery.min.js +++ /dev/null @@ -1,154 +0,0 @@ -/*! - * jQuery JavaScript Library v1.4.2 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Sat Feb 13 22:33:48 2010 -0500 - */ -(function(A,w){function ma(){if(!c.isReady){try{s.documentElement.doScroll("left")}catch(a){setTimeout(ma,1);return}c.ready()}}function Qa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,j){var i=a.length;if(typeof b==="object"){for(var o in b)X(a,o,b[o],f,e,d);return a}if(d!==w){f=!j&&f&&c.isFunction(d);for(o=0;o)[^>]*$|^#([\w-]+)$/,Ua=/^.[^:#\[\.,]*$/,Va=/\S/, -Wa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Xa=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,P=navigator.userAgent,xa=false,Q=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,R=Array.prototype.slice,ya=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(a==="body"&&!b){this.context=s;this[0]=s.body;this.selector="body";this.length=1;return this}if(typeof a==="string")if((d=Ta.exec(a))&& -(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:s;if(a=Xa.exec(a))if(c.isPlainObject(b)){a=[s.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=sa([d[1]],[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}return c.merge(this,a)}else{if(b=s.getElementById(d[2])){if(b.id!==d[2])return T.find(a);this.length=1;this[0]=b}this.context=s;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=s;a=s.getElementsByTagName(a);return c.merge(this, -a)}else return!b||b.jquery?(b||T).find(a):c(b).find(a);else if(c.isFunction(a))return T.ready(a);if(a.selector!==w){this.selector=a.selector;this.context=a.context}return c.makeArray(a,this)},selector:"",jquery:"1.4.2",length:0,size:function(){return this.length},toArray:function(){return R.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){var f=c();c.isArray(a)?ba.apply(f,a):c.merge(f,a);f.prevObject=this;f.context=this.context;if(b=== -"find")f.selector=this.selector+(this.selector?" ":"")+d;else if(b)f.selector=this.selector+"."+b+"("+d+")";return f},each:function(a,b){return c.each(this,a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(s,c);else Q&&Q.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(R.apply(this,arguments),"slice",R.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this, -function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,j,i,o;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
    a"; -var e=d.getElementsByTagName("*"),j=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!j)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(j.getAttribute("style")),hrefNormalized:j.getAttribute("href")==="/a",opacity:/^0.55$/.test(j.style.opacity),cssFloat:!!j.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:s.createElement("select").appendChild(s.createElement("option")).selected, -parentNode:d.removeChild(d.appendChild(s.createElement("div"))).parentNode===null,deleteExpando:true,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null};b.type="text/javascript";try{b.appendChild(s.createTextNode("window."+f+"=1;"))}catch(i){}a.insertBefore(b,a.firstChild);if(A[f]){c.support.scriptEval=true;delete A[f]}try{delete b.test}catch(o){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function k(){c.support.noCloneEvent= -false;d.detachEvent("onclick",k)});d.cloneNode(true).fireEvent("onclick")}d=s.createElement("div");d.innerHTML="";a=s.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var k=s.createElement("div");k.style.width=k.style.paddingLeft="1px";s.body.appendChild(k);c.boxModel=c.support.boxModel=k.offsetWidth===2;s.body.removeChild(k).style.display="none"});a=function(k){var n= -s.createElement("div");k="on"+k;var r=k in n;if(!r){n.setAttribute(k,"return;");r=typeof n[k]==="function"}return r};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=j=null}})();c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ya=0,za={};c.extend({cache:{},expando:G,noData:{embed:true,object:true, -applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var f=a[G],e=c.cache;if(!f&&typeof b==="string"&&d===w)return null;f||(f=++Ya);if(typeof b==="object"){a[G]=f;e[f]=c.extend(true,{},b)}else if(!e[f]){a[G]=f;e[f]={}}a=e[f];if(d!==w)a[b]=d;return typeof b==="string"?a[b]:a}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==A?za:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{if(c.support.deleteExpando)delete a[c.expando]; -else a.removeAttribute&&a.removeAttribute(c.expando);delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this,a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===w){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===w&&this.length)f=c.data(this[0],a);return f===w&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this, -a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d);return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b=== -w)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var Aa=/[\n\t]/g,ca=/\s+/,Za=/\r/g,$a=/href|src|style/,ab=/(button|input)/i,bb=/(button|input|object|select|textarea)/i, -cb=/^(a|area)$/i,Ba=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(n){var r=c(this);r.addClass(a.call(this,n,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===w){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value||{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var j=b?d:0;for(d=b?d+1:e.length;j=0;else if(c.nodeName(this,"select")){var u=c.makeArray(r);c("option",this).each(function(){this.selected= -c.inArray(c(this).val(),u)>=0});if(!u.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return w;if(f&&b in c.attrFn)return c(a)[b](d);f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==w;b=f&&c.props[b]||b;if(a.nodeType===1){var j=$a.test(b);if(b in a&&f&&!j){if(e){b==="type"&&ab.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed"); -a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:bb.test(a.nodeName)||cb.test(a.nodeName)&&a.href?0:w;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText=""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&j?a.getAttribute(b,2):a.getAttribute(b);return a===null?w:a}return c.style(a,b,d)}});var O=/\.(.*)$/,db=function(a){return a.replace(/[^\w\s\.\|`]/g, -function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==A&&!a.frameElement)a=A;var e,j;if(d.handler){e=d;d=e.handler}if(!d.guid)d.guid=c.guid++;if(j=c.data(a)){var i=j.events=j.events||{},o=j.handle;if(!o)j.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,arguments):w};o.elem=a;b=b.split(" ");for(var k,n=0,r;k=b[n++];){j=e?c.extend({},e):{handler:d,data:f};if(k.indexOf(".")>-1){r=k.split("."); -k=r.shift();j.namespace=r.slice(0).sort().join(".")}else{r=[];j.namespace=""}j.type=k;j.guid=d.guid;var u=i[k],z=c.event.special[k]||{};if(!u){u=i[k]=[];if(!z.setup||z.setup.call(a,f,r,o)===false)if(a.addEventListener)a.addEventListener(k,o,false);else a.attachEvent&&a.attachEvent("on"+k,o)}if(z.add){z.add.call(a,j);if(!j.handler.guid)j.handler.guid=d.guid}u.push(j);c.event.global[k]=true}a=null}}},global:{},remove:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){var e,j=0,i,o,k,n,r,u,z=c.data(a), -C=z&&z.events;if(z&&C){if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(e in C)c.event.remove(a,e+b)}else{for(b=b.split(" ");e=b[j++];){n=e;i=e.indexOf(".")<0;o=[];if(!i){o=e.split(".");e=o.shift();k=new RegExp("(^|\\.)"+c.map(o.slice(0).sort(),db).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(r=C[e])if(d){n=c.event.special[e]||{};for(B=f||0;B=0){a.type= -e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return w;a.result=w;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d,b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(j){}if(!a.isPropagationStopped()&& -f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){f=a.target;var i,o=c.nodeName(f,"a")&&e==="click",k=c.event.special[e]||{};if((!k._default||k._default.call(d,a)===false)&&!o&&!(f&&f.nodeName&&c.noData[f.nodeName.toLowerCase()])){try{if(f[e]){if(i=f["on"+e])f["on"+e]=null;c.event.triggered=true;f[e]()}}catch(n){}if(i)f["on"+e]=i;c.event.triggered=false}}},handle:function(a){var b,d,f,e;a=arguments[0]=c.event.fix(a||A.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive; -if(!b){d=a.type.split(".");a.type=d.shift();f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)")}e=c.data(this,"events");d=e[a.type];if(e&&d){d=d.slice(0);e=0;for(var j=d.length;e-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},fa=function(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Fa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data", -e);if(!(f===w||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:fa,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return fa.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return fa.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a, -"_change_data",Fa(a))}},setup:function(){if(this.type==="file")return false;for(var a in ea)c.event.add(this,a+".specialChange",ea[a]);return da.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return da.test(this.nodeName)}};ea=c.event.special.change.filters}s.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this,f)}c.event.special[b]={setup:function(){this.addEventListener(a, -d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var j in d)this[b](j,f,d[j],e);return this}if(c.isFunction(f)){e=f;f=w}var i=b==="one"?c.proxy(e,function(k){c(this).unbind(k,i);return e.apply(this,arguments)}):e;if(d==="unload"&&b!=="one")this.one(d,f,e);else{j=0;for(var o=this.length;j0){y=t;break}}t=t[g]}m[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, -e=0,j=Object.prototype.toString,i=false,o=true;[0,0].sort(function(){o=false;return 0});var k=function(g,h,l,m){l=l||[];var q=h=h||s;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g||typeof g!=="string")return l;for(var p=[],v,t,y,S,H=true,M=x(h),I=g;(f.exec(""),v=f.exec(I))!==null;){I=v[3];p.push(v[1]);if(v[2]){S=v[3];break}}if(p.length>1&&r.exec(g))if(p.length===2&&n.relative[p[0]])t=ga(p[0]+p[1],h);else for(t=n.relative[p[0]]?[h]:k(p.shift(),h);p.length;){g=p.shift();if(n.relative[g])g+=p.shift(); -t=ga(g,t)}else{if(!m&&p.length>1&&h.nodeType===9&&!M&&n.match.ID.test(p[0])&&!n.match.ID.test(p[p.length-1])){v=k.find(p.shift(),h,M);h=v.expr?k.filter(v.expr,v.set)[0]:v.set[0]}if(h){v=m?{expr:p.pop(),set:z(m)}:k.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=v.expr?k.filter(v.expr,v.set):v.set;if(p.length>0)y=z(t);else H=false;for(;p.length;){var D=p.pop();v=D;if(n.relative[D])v=p.pop();else D="";if(v==null)v=h;n.relative[D](y,v,M)}}else y=[]}y||(y=t);y||k.error(D|| -g);if(j.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))l.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&l.push(t[g]);else l.push.apply(l,y);else z(y,l);if(S){k(S,q,l,m);k.uniqueSort(l)}return l};k.uniqueSort=function(g){if(B){i=o;g.sort(B);if(i)for(var h=1;h":function(g,h){var l=typeof h==="string";if(l&&!/\W/.test(h)){h=h.toLowerCase();for(var m=0,q=g.length;m=0))l||m.push(v);else if(l)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()}, -CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,l,m,q,p){h=g[1].replace(/\\/g,"");if(!p&&n.attrMap[h])g[1]=n.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,l,m,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,h);else{g=k.filter(g[3],h,l,true^q);l||m.push.apply(m, -g);return false}else if(n.match.POS.test(g[0])||n.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,l){return!!k(l[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)}, -text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}}, -setFilters:{first:function(g,h){return h===0},last:function(g,h,l,m){return h===m.length-1},even:function(g,h){return h%2===0},odd:function(g,h){return h%2===1},lt:function(g,h,l){return hl[3]-0},nth:function(g,h,l){return l[3]-0===h},eq:function(g,h,l){return l[3]-0===h}},filter:{PSEUDO:function(g,h,l,m){var q=h[1],p=n.filters[q];if(p)return p(g,l,h,m);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h= -h[3];l=0;for(m=h.length;l=0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var l=h[1];g=n.attrHandle[l]?n.attrHandle[l](g):g[l]!=null?g[l]:g.getAttribute(l);l=g+"";var m=h[2];h=h[4];return g==null?m==="!=":m=== -"="?l===h:m==="*="?l.indexOf(h)>=0:m==="~="?(" "+l+" ").indexOf(h)>=0:!h?l&&g!==false:m==="!="?l!==h:m==="^="?l.indexOf(h)===0:m==="$="?l.substr(l.length-h.length)===h:m==="|="?l===h||l.substr(0,h.length+1)===h+"-":false},POS:function(g,h,l,m){var q=n.setFilters[h[2]];if(q)return q(g,l,h,m)}}},r=n.match.POS;for(var u in n.match){n.match[u]=new RegExp(n.match[u].source+/(?![^\[]*\])(?![^\(]*\))/.source);n.leftMatch[u]=new RegExp(/(^(?:.|\r|\n)*?)/.source+n.match[u].source.replace(/\\(\d+)/g,function(g, -h){return"\\"+(h-0+1)}))}var z=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g};try{Array.prototype.slice.call(s.documentElement.childNodes,0)}catch(C){z=function(g,h){h=h||[];if(j.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var l=0,m=g.length;l";var l=s.documentElement;l.insertBefore(g,l.firstChild);if(s.getElementById(h)){n.find.ID=function(m,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(m[1]))?q.id===m[1]||typeof q.getAttributeNode!=="undefined"&& -q.getAttributeNode("id").nodeValue===m[1]?[q]:w:[]};n.filter.ID=function(m,q){var p=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&p&&p.nodeValue===q}}l.removeChild(g);l=g=null})();(function(){var g=s.createElement("div");g.appendChild(s.createComment(""));if(g.getElementsByTagName("*").length>0)n.find.TAG=function(h,l){l=l.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var m=0;l[m];m++)l[m].nodeType===1&&h.push(l[m]);l=h}return l};g.innerHTML=""; -if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")n.attrHandle.href=function(h){return h.getAttribute("href",2)};g=null})();s.querySelectorAll&&function(){var g=k,h=s.createElement("div");h.innerHTML="

    ";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){k=function(m,q,p,v){q=q||s;if(!v&&q.nodeType===9&&!x(q))try{return z(q.querySelectorAll(m),p)}catch(t){}return g(m,q,p,v)};for(var l in g)k[l]=g[l];h=null}}(); -(function(){var g=s.createElement("div");g.innerHTML="
    ";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){n.order.splice(1,0,"CLASS");n.find.CLASS=function(h,l,m){if(typeof l.getElementsByClassName!=="undefined"&&!m)return l.getElementsByClassName(h[1])};g=null}}})();var E=s.compareDocumentPosition?function(g,h){return!!(g.compareDocumentPosition(h)&16)}: -function(g,h){return g!==h&&(g.contains?g.contains(h):true)},x=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},ga=function(g,h){var l=[],m="",q;for(h=h.nodeType?[h]:h;q=n.match.PSEUDO.exec(g);){m+=q[0];g=g.replace(n.match.PSEUDO,"")}g=n.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var j=d;j0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,j= -{},i;if(f&&a.length){e=0;for(var o=a.length;e-1:c(f).is(e)){d.push({selector:i,elem:f});delete j[i]}}f=f.parentNode}}return d}var k=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(n,r){for(;r&&r.ownerDocument&&r!==b;){if(k?k.index(r)>-1:c(r).is(a))return r;r=r.parentNode}return null})},index:function(a){if(!a||typeof a=== -"string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(),a);return this.pushStack(qa(a[0])||qa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode", -d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")? -a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);eb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e):e;if((this.length>1||gb.test(f))&&fb.test(a))e=e.reverse();return this.pushStack(e,a,R.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===w||a.nodeType!==1||!c(a).is(d));){a.nodeType=== -1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var Ja=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ka=/(<([\w:]+)[^>]*?)\/>/g,hb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,La=/<([\w:]+)/,ib=/"},F={option:[1,""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
    ","
    "];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= -c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==w)return this.empty().append((this[0]&&this[0].ownerDocument||s).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, -wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, -prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, -this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,f;(f=this[d])!=null;d++)if(!a||c.filter(a,[f]).length){if(!b&&f.nodeType===1){c.cleanData(f.getElementsByTagName("*"));c.cleanData([f])}f.parentNode&&f.parentNode.removeChild(f)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); -return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Ja,"").replace(/=([^="'>\s]+\/)>/g,'="$1">').replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){ra(this,b);ra(this.find("*"),b.find("*"))}return b},html:function(a){if(a===w)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Ja, -""):null;else if(typeof a==="string"&&!ta.test(a)&&(c.support.leadingWhitespace||!V.test(a))&&!F[(La.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Ka,Ma);try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?k.cloneNode(true):k)}o.length&&c.each(o,Qa)}return this}});c.fragments={};c.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var f=[];d=c(d);var e=this.length===1&&this[0].parentNode;if(e&&e.nodeType===11&&e.childNodes.length===1&&d.length===1){d[b](this[0]); -return this}else{e=0;for(var j=d.length;e0?this.clone(true):this).get();c.fn[b].apply(c(d[e]),i);f=f.concat(i)}return this.pushStack(f,a,d.selector)}}});c.extend({clean:function(a,b,d,f){b=b||s;if(typeof b.createElement==="undefined")b=b.ownerDocument||b[0]&&b[0].ownerDocument||s;for(var e=[],j=0,i;(i=a[j])!=null;j++){if(typeof i==="number")i+="";if(i){if(typeof i==="string"&&!jb.test(i))i=b.createTextNode(i);else if(typeof i==="string"){i=i.replace(Ka,Ma);var o=(La.exec(i)||["", -""])[1].toLowerCase(),k=F[o]||F._default,n=k[0],r=b.createElement("div");for(r.innerHTML=k[1]+i+k[2];n--;)r=r.lastChild;if(!c.support.tbody){n=ib.test(i);o=o==="table"&&!n?r.firstChild&&r.firstChild.childNodes:k[1]===""&&!n?r.childNodes:[];for(k=o.length-1;k>=0;--k)c.nodeName(o[k],"tbody")&&!o[k].childNodes.length&&o[k].parentNode.removeChild(o[k])}!c.support.leadingWhitespace&&V.test(i)&&r.insertBefore(b.createTextNode(V.exec(i)[0]),r.firstChild);i=r.childNodes}if(i.nodeType)e.push(i);else e= -c.merge(e,i)}}if(d)for(j=0;e[j];j++)if(f&&c.nodeName(e[j],"script")&&(!e[j].type||e[j].type.toLowerCase()==="text/javascript"))f.push(e[j].parentNode?e[j].parentNode.removeChild(e[j]):e[j]);else{e[j].nodeType===1&&e.splice.apply(e,[j+1,0].concat(c.makeArray(e[j].getElementsByTagName("script"))));d.appendChild(e[j])}return e},cleanData:function(a){for(var b,d,f=c.cache,e=c.event.special,j=c.support.deleteExpando,i=0,o;(o=a[i])!=null;i++)if(d=o[c.expando]){b=f[d];if(b.events)for(var k in b.events)e[k]? -c.event.remove(o,k):Ca(o,k,b.handle);if(j)delete o[c.expando];else o.removeAttribute&&o.removeAttribute(c.expando);delete f[d]}}});var kb=/z-?index|font-?weight|opacity|zoom|line-?height/i,Na=/alpha\([^)]*\)/,Oa=/opacity=([^)]*)/,ha=/float/i,ia=/-([a-z])/ig,lb=/([A-Z])/g,mb=/^-?\d+(?:px)?$/i,nb=/^-?\d/,ob={position:"absolute",visibility:"hidden",display:"block"},pb=["Left","Right"],qb=["Top","Bottom"],rb=s.defaultView&&s.defaultView.getComputedStyle,Pa=c.support.cssFloat?"cssFloat":"styleFloat",ja= -function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){return X(this,a,b,true,function(d,f,e){if(e===w)return c.curCSS(d,f);if(typeof e==="number"&&!kb.test(f))e+="px";c.style(d,f,e)})};c.extend({style:function(a,b,d){if(!a||a.nodeType===3||a.nodeType===8)return w;if((b==="width"||b==="height")&&parseFloat(d)<0)d=w;var f=a.style||a,e=d!==w;if(!c.support.opacity&&b==="opacity"){if(e){f.zoom=1;b=parseInt(d,10)+""==="NaN"?"":"alpha(opacity="+d*100+")";a=f.filter||c.curCSS(a,"filter")||"";f.filter= -Na.test(a)?a.replace(Na,b):b}return f.filter&&f.filter.indexOf("opacity=")>=0?parseFloat(Oa.exec(f.filter)[1])/100+"":""}if(ha.test(b))b=Pa;b=b.replace(ia,ja);if(e)f[b]=d;return f[b]},css:function(a,b,d,f){if(b==="width"||b==="height"){var e,j=b==="width"?pb:qb;function i(){e=b==="width"?a.offsetWidth:a.offsetHeight;f!=="border"&&c.each(j,function(){f||(e-=parseFloat(c.curCSS(a,"padding"+this,true))||0);if(f==="margin")e+=parseFloat(c.curCSS(a,"margin"+this,true))||0;else e-=parseFloat(c.curCSS(a, -"border"+this+"Width",true))||0})}a.offsetWidth!==0?i():c.swap(a,ob,i);return Math.max(0,Math.round(e))}return c.curCSS(a,b,d)},curCSS:function(a,b,d){var f,e=a.style;if(!c.support.opacity&&b==="opacity"&&a.currentStyle){f=Oa.test(a.currentStyle.filter||"")?parseFloat(RegExp.$1)/100+"":"";return f===""?"1":f}if(ha.test(b))b=Pa;if(!d&&e&&e[b])f=e[b];else if(rb){if(ha.test(b))b="float";b=b.replace(lb,"-$1").toLowerCase();e=a.ownerDocument.defaultView;if(!e)return null;if(a=e.getComputedStyle(a,null))f= -a.getPropertyValue(b);if(b==="opacity"&&f==="")f="1"}else if(a.currentStyle){d=b.replace(ia,ja);f=a.currentStyle[b]||a.currentStyle[d];if(!mb.test(f)&&nb.test(f)){b=e.left;var j=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;e.left=d==="fontSize"?"1em":f||0;f=e.pixelLeft+"px";e.left=b;a.runtimeStyle.left=j}}return f},swap:function(a,b,d){var f={};for(var e in b){f[e]=a.style[e];a.style[e]=b[e]}d.call(a);for(e in b)a.style[e]=f[e]}});if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b= -a.offsetWidth,d=a.offsetHeight,f=a.nodeName.toLowerCase()==="tr";return b===0&&d===0&&!f?true:b>0&&d>0&&!f?false:c.curCSS(a,"display")==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var sb=J(),tb=//gi,ub=/select|textarea/i,vb=/color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week/i,N=/=\?(&|$)/,ka=/\?/,wb=/(\?|&)_=.*?(&|$)/,xb=/^(\w+:)?\/\/([^\/?#]+)/,yb=/%20/g,zb=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!== -"string")return zb.call(this,a);else if(!this.length)return this;var f=a.indexOf(" ");if(f>=0){var e=a.slice(f,a.length);a=a.slice(0,f)}f="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b==="object"){b=c.param(b,c.ajaxSettings.traditional);f="POST"}var j=this;c.ajax({url:a,type:f,dataType:"html",data:b,complete:function(i,o){if(o==="success"||o==="notmodified")j.html(e?c("
    ").append(i.responseText.replace(tb,"")).find(e):i.responseText);d&&j.each(d,[i.responseText,o,i])}});return this}, -serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||ub.test(this.nodeName)||vb.test(this.type))}).map(function(a,b){a=c(this).val();return a==null?null:c.isArray(a)?c.map(a,function(d){return{name:b.name,value:d}}):{name:b.name,value:a}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "), -function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:f})},getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,f){if(c.isFunction(b)){f=f||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:f})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href, -global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:A.XMLHttpRequest&&(A.location.protocol!=="file:"||!A.ActiveXObject)?function(){return new A.XMLHttpRequest}:function(){try{return new A.ActiveXObject("Microsoft.XMLHTTP")}catch(a){}},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},etag:{},ajax:function(a){function b(){e.success&& -e.success.call(k,o,i,x);e.global&&f("ajaxSuccess",[x,e])}function d(){e.complete&&e.complete.call(k,x,i);e.global&&f("ajaxComplete",[x,e]);e.global&&!--c.active&&c.event.trigger("ajaxStop")}function f(q,p){(e.context?c(e.context):c.event).trigger(q,p)}var e=c.extend(true,{},c.ajaxSettings,a),j,i,o,k=a&&a.context||e,n=e.type.toUpperCase();if(e.data&&e.processData&&typeof e.data!=="string")e.data=c.param(e.data,e.traditional);if(e.dataType==="jsonp"){if(n==="GET")N.test(e.url)||(e.url+=(ka.test(e.url)? -"&":"?")+(e.jsonp||"callback")+"=?");else if(!e.data||!N.test(e.data))e.data=(e.data?e.data+"&":"")+(e.jsonp||"callback")+"=?";e.dataType="json"}if(e.dataType==="json"&&(e.data&&N.test(e.data)||N.test(e.url))){j=e.jsonpCallback||"jsonp"+sb++;if(e.data)e.data=(e.data+"").replace(N,"="+j+"$1");e.url=e.url.replace(N,"="+j+"$1");e.dataType="script";A[j]=A[j]||function(q){o=q;b();d();A[j]=w;try{delete A[j]}catch(p){}z&&z.removeChild(C)}}if(e.dataType==="script"&&e.cache===null)e.cache=false;if(e.cache=== -false&&n==="GET"){var r=J(),u=e.url.replace(wb,"$1_="+r+"$2");e.url=u+(u===e.url?(ka.test(e.url)?"&":"?")+"_="+r:"")}if(e.data&&n==="GET")e.url+=(ka.test(e.url)?"&":"?")+e.data;e.global&&!c.active++&&c.event.trigger("ajaxStart");r=(r=xb.exec(e.url))&&(r[1]&&r[1]!==location.protocol||r[2]!==location.host);if(e.dataType==="script"&&n==="GET"&&r){var z=s.getElementsByTagName("head")[0]||s.documentElement,C=s.createElement("script");C.src=e.url;if(e.scriptCharset)C.charset=e.scriptCharset;if(!j){var B= -false;C.onload=C.onreadystatechange=function(){if(!B&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){B=true;b();d();C.onload=C.onreadystatechange=null;z&&C.parentNode&&z.removeChild(C)}}}z.insertBefore(C,z.firstChild);return w}var E=false,x=e.xhr();if(x){e.username?x.open(n,e.url,e.async,e.username,e.password):x.open(n,e.url,e.async);try{if(e.data||a&&a.contentType)x.setRequestHeader("Content-Type",e.contentType);if(e.ifModified){c.lastModified[e.url]&&x.setRequestHeader("If-Modified-Since", -c.lastModified[e.url]);c.etag[e.url]&&x.setRequestHeader("If-None-Match",c.etag[e.url])}r||x.setRequestHeader("X-Requested-With","XMLHttpRequest");x.setRequestHeader("Accept",e.dataType&&e.accepts[e.dataType]?e.accepts[e.dataType]+", */*":e.accepts._default)}catch(ga){}if(e.beforeSend&&e.beforeSend.call(k,x,e)===false){e.global&&!--c.active&&c.event.trigger("ajaxStop");x.abort();return false}e.global&&f("ajaxSend",[x,e]);var g=x.onreadystatechange=function(q){if(!x||x.readyState===0||q==="abort"){E|| -d();E=true;if(x)x.onreadystatechange=c.noop}else if(!E&&x&&(x.readyState===4||q==="timeout")){E=true;x.onreadystatechange=c.noop;i=q==="timeout"?"timeout":!c.httpSuccess(x)?"error":e.ifModified&&c.httpNotModified(x,e.url)?"notmodified":"success";var p;if(i==="success")try{o=c.httpData(x,e.dataType,e)}catch(v){i="parsererror";p=v}if(i==="success"||i==="notmodified")j||b();else c.handleError(e,x,i,p);d();q==="timeout"&&x.abort();if(e.async)x=null}};try{var h=x.abort;x.abort=function(){x&&h.call(x); -g("abort")}}catch(l){}e.async&&e.timeout>0&&setTimeout(function(){x&&!E&&g("timeout")},e.timeout);try{x.send(n==="POST"||n==="PUT"||n==="DELETE"?e.data:null)}catch(m){c.handleError(e,x,null,m);d()}e.async||g();return x}},handleError:function(a,b,d,f){if(a.error)a.error.call(a.context||a,b,d,f);if(a.global)(a.context?c(a.context):c.event).trigger("ajaxError",[b,a,f])},active:0,httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status=== -1223||a.status===0}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),f=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(f)c.etag[b]=f;return a.status===304||a.status===0},httpData:function(a,b,d){var f=a.getResponseHeader("content-type")||"",e=b==="xml"||!b&&f.indexOf("xml")>=0;a=e?a.responseXML:a.responseText;e&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b=== -"json"||!b&&f.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&f.indexOf("javascript")>=0)c.globalEval(a);return a},param:function(a,b){function d(i,o){if(c.isArray(o))c.each(o,function(k,n){b||/\[\]$/.test(i)?f(i,n):d(i+"["+(typeof n==="object"||c.isArray(n)?k:"")+"]",n)});else!b&&o!=null&&typeof o==="object"?c.each(o,function(k,n){d(i+"["+k+"]",n)}):f(i,o)}function f(i,o){o=c.isFunction(o)?o():o;e[e.length]=encodeURIComponent(i)+"="+encodeURIComponent(o)}var e=[];if(b===w)b=c.ajaxSettings.traditional; -if(c.isArray(a)||a.jquery)c.each(a,function(){f(this.name,this.value)});else for(var j in a)d(j,a[j]);return e.join("&").replace(yb,"+")}});var la={},Ab=/toggle|show|hide/,Bb=/^([+-]=)?([\d+-.]+)(.*)$/,W,va=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b){if(a||a===0)return this.animate(K("show",3),a,b);else{a=0;for(b=this.length;a").appendTo("body");f=e.css("display");if(f==="none")f="block";e.remove();la[d]=f}c.data(this[a],"olddisplay",f)}}a=0;for(b=this.length;a=0;f--)if(d[f].elem===this){b&&d[f](true);d.splice(f,1)}});b||this.dequeue();return this}});c.each({slideDown:K("show",1),slideUp:K("hide",1),slideToggle:K("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(a,b){c.fn[a]=function(d,f){return this.animate(b,d,f)}});c.extend({speed:function(a,b,d){var f=a&&typeof a==="object"?a:{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};f.duration=c.fx.off?0:typeof f.duration=== -"number"?f.duration:c.fx.speeds[f.duration]||c.fx.speeds._default;f.old=f.complete;f.complete=function(){f.queue!==false&&c(this).dequeue();c.isFunction(f.old)&&f.old.call(this)};return f},easing:{linear:function(a,b,d,f){return d+f*a},swing:function(a,b,d,f){return(-Math.cos(a*Math.PI)/2+0.5)*f+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]|| -c.fx.step._default)(this);if((this.prop==="height"||this.prop==="width")&&this.elem.style)this.elem.style.display="block"},cur:function(a){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];return(a=parseFloat(c.css(this.elem,this.prop,a)))&&a>-10000?a:parseFloat(c.curCSS(this.elem,this.prop))||0},custom:function(a,b,d){function f(j){return e.step(j)}this.startTime=J();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start; -this.pos=this.state=0;var e=this;f.elem=this.elem;if(f()&&c.timers.push(f)&&!W)W=setInterval(c.fx.tick,13)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(a){var b=J(),d=true;if(a||b>=this.options.duration+this.startTime){this.now= -this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var f in this.options.curAnim)if(this.options.curAnim[f]!==true)d=false;if(d){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;a=c.data(this.elem,"olddisplay");this.elem.style.display=a?a:this.options.display;if(c.css(this.elem,"display")==="none")this.elem.style.display="block"}this.options.hide&&c(this.elem).hide();if(this.options.hide||this.options.show)for(var e in this.options.curAnim)c.style(this.elem, -e,this.options.orig[e]);this.options.complete.call(this.elem)}return false}else{e=b-this.startTime;this.state=e/this.options.duration;a=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||a](this.state,e,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=c.timers,b=0;b
    "; -a.insertBefore(b,a.firstChild);d=b.firstChild;f=d.firstChild;e=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=f.offsetTop!==5;this.doesAddBorderForTableAndCells=e.offsetTop===5;f.style.position="fixed";f.style.top="20px";this.supportsFixedPosition=f.offsetTop===20||f.offsetTop===15;f.style.position=f.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=f.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==j;a.removeChild(b); -c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.curCSS(a,"marginTop",true))||0;d+=parseFloat(c.curCSS(a,"marginLeft",true))||0}return{top:b,left:d}},setOffset:function(a,b,d){if(/static/.test(c.curCSS(a,"position")))a.style.position="relative";var f=c(a),e=f.offset(),j=parseInt(c.curCSS(a,"top",true),10)||0,i=parseInt(c.curCSS(a,"left",true),10)||0;if(c.isFunction(b))b=b.call(a, -d,e);d={top:b.top-e.top+j,left:b.left-e.left+i};"using"in b?b.using.call(a,d):f.css(d)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),f=/^body|html$/i.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.curCSS(a,"marginTop",true))||0;d.left-=parseFloat(c.curCSS(a,"marginLeft",true))||0;f.top+=parseFloat(c.curCSS(b[0],"borderTopWidth",true))||0;f.left+=parseFloat(c.curCSS(b[0],"borderLeftWidth",true))||0;return{top:d.top- -f.top,left:d.left-f.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||s.body;a&&!/^body|html$/i.test(a.nodeName)&&c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(f){var e=this[0],j;if(!e)return null;if(f!==w)return this.each(function(){if(j=wa(this))j.scrollTo(!a?f:c(j).scrollLeft(),a?f:c(j).scrollTop());else this[d]=f});else return(j=wa(e))?"pageXOffset"in j?j[a?"pageYOffset": -"pageXOffset"]:c.support.boxModel&&j.document.documentElement[d]||j.document.body[d]:e[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();c.fn["inner"+b]=function(){return this[0]?c.css(this[0],d,false,"padding"):null};c.fn["outer"+b]=function(f){return this[0]?c.css(this[0],d,false,f?"margin":"border"):null};c.fn[d]=function(f){var e=this[0];if(!e)return f==null?null:this;if(c.isFunction(f))return this.each(function(j){var i=c(this);i[d](f.call(this,j,i[d]()))});return"scrollTo"in -e&&e.document?e.document.compatMode==="CSS1Compat"&&e.document.documentElement["client"+b]||e.document.body["client"+b]:e.nodeType===9?Math.max(e.documentElement["client"+b],e.body["scroll"+b],e.documentElement["scroll"+b],e.body["offset"+b],e.documentElement["offset"+b]):f===w?c.css(e,d):this.css(d,typeof f==="string"?f:f+"px")}});A.jQuery=A.$=c})(window); \ No newline at end of file diff --git a/includes/kohana/modules/userguide/media/js/kodoc.js b/includes/kohana/modules/userguide/media/js/kodoc.js deleted file mode 100644 index b914d937..00000000 --- a/includes/kohana/modules/userguide/media/js/kodoc.js +++ /dev/null @@ -1,94 +0,0 @@ -$(document).ready(function() -{ - // Translation selector - $('#topbar form select').change(function() - { - $(this).parents('form').submit(); - }); - - // Syntax highlighter - $('pre:not(.debug) code').each(function() - { - $(this).addClass('brush: php'); - }); - - SyntaxHighlighter.config.tagName = 'code'; - // Don't show the toolbar or line-numbers. - SyntaxHighlighter.defaults.toolbar = false; - SyntaxHighlighter.defaults.gutter = false; - SyntaxHighlighter.all(); - - // Striped tables - $('#content tbody tr:even').addClass('alt'); - - // Toggle menus - $('#menu ol li strong').each(function() - { - var link = $(this); - var menu = link.parent().find('ol:first, ul:first'); - var togg = $('+').appendTo(link); - - link.click(function() - { - if (menu.is(':visible')) - { - // Hide visible menus - togg.html('+'); - menu.stop(true, true).slideUp('fast'); - } - else - { - // Show hidden menus - togg.html('–'); - menu.stop(true, true).slideDown('fast'); - } - }); - - // Hide all menus that do not contain the active link - menu.not(':has(a[href="'+ window.location.pathname +'"])').hide(); - - if (menu.is(':visible')) - { - // Display the toggle as being open - togg.html('–'); - } - }); - - // Collapsable class contents - $('#content #toc').each(function() - { - var header = $(this); - var content = $('#content div.toc').hide(); - - $('[ + ]').toggle(function() - { - $(this).html('[ – ]'); - content.stop(true, true).slideDown(); - }, - function() - { - $(this).html('[ + ]'); - content.stop(true, true).slideUp(); - }) - .appendTo(header); - }); - - // Show source links - $('#content .method-source').each(function() - { - var self = $(this); - var togg = $('+').appendTo($('h5', self)); - var code = self.find('pre').hide(); - - self.toggle(function() - { - togg.html('–'); - code.stop(true, true).slideDown(); - }, - function() - { - togg.html('+'); - code.stop(true, true).slideUp(); - }); - }); -}); diff --git a/includes/kohana/modules/userguide/media/js/shBrushPhp.js b/includes/kohana/modules/userguide/media/js/shBrushPhp.js deleted file mode 100644 index 4e92a19b..00000000 --- a/includes/kohana/modules/userguide/media/js/shBrushPhp.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/ - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate - * - * @version - * 2.1.364 (October 15 2009) - * - * @copyright - * Copyright (C) 2004-2009 Alex Gorbatchev. - * - * @license - * This file is part of SyntaxHighlighter. - * - * SyntaxHighlighter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * SyntaxHighlighter is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with SyntaxHighlighter. If not, see . - */ -SyntaxHighlighter.brushes.Php = function() -{ - var funcs = 'abs acos acosh addcslashes addslashes ' + - 'array_change_key_case array_chunk array_combine array_count_values array_diff '+ - 'array_diff_assoc array_diff_key array_diff_uassoc array_diff_ukey array_fill '+ - 'array_filter array_flip array_intersect array_intersect_assoc array_intersect_key '+ - 'array_intersect_uassoc array_intersect_ukey array_key_exists array_keys array_map '+ - 'array_merge array_merge_recursive array_multisort array_pad array_pop array_product '+ - 'array_push array_rand array_reduce array_reverse array_search array_shift '+ - 'array_slice array_splice array_sum array_udiff array_udiff_assoc '+ - 'array_udiff_uassoc array_uintersect array_uintersect_assoc '+ - 'array_uintersect_uassoc array_unique array_unshift array_values array_walk '+ - 'array_walk_recursive atan atan2 atanh base64_decode base64_encode base_convert '+ - 'basename bcadd bccomp bcdiv bcmod bcmul bindec bindtextdomain bzclose bzcompress '+ - 'bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite ceil chdir '+ - 'checkdate checkdnsrr chgrp chmod chop chown chr chroot chunk_split class_exists '+ - 'closedir closelog copy cos cosh count count_chars date decbin dechex decoct '+ - 'deg2rad delete ebcdic2ascii echo empty end ereg ereg_replace eregi eregi_replace error_log '+ - 'error_reporting escapeshellarg escapeshellcmd eval exec exit exp explode extension_loaded '+ - 'feof fflush fgetc fgetcsv fgets fgetss file_exists file_get_contents file_put_contents '+ - 'fileatime filectime filegroup fileinode filemtime fileowner fileperms filesize filetype '+ - 'floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv fputs fread fscanf '+ - 'fseek fsockopen fstat ftell ftok getallheaders getcwd getdate getenv gethostbyaddr gethostbyname '+ - 'gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid getmyuid getopt '+ - 'getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext '+ - 'gettimeofday gettype glob gmdate gmmktime ini_alter ini_get ini_get_all ini_restore ini_set '+ - 'interface_exists intval ip2long is_a is_array is_bool is_callable is_dir is_double '+ - 'is_executable is_file is_finite is_float is_infinite is_int is_integer is_link is_long '+ - 'is_nan is_null is_numeric is_object is_readable is_real is_resource is_scalar is_soap_fault '+ - 'is_string is_subclass_of is_uploaded_file is_writable is_writeable mkdir mktime nl2br '+ - 'parse_ini_file parse_str parse_url passthru pathinfo readlink realpath rewind rewinddir rmdir '+ - 'round str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split '+ - 'str_word_count strcasecmp strchr strcmp strcoll strcspn strftime strip_tags stripcslashes '+ - 'stripos stripslashes stristr strlen strnatcasecmp strnatcmp strncasecmp strncmp strpbrk '+ - 'strpos strptime strrchr strrev strripos strrpos strspn strstr strtok strtolower strtotime '+ - 'strtoupper strtr strval substr substr_compare'; - - var keywords = 'and or xor array as break case ' + - 'cfunction class const continue declare default die do else ' + - 'elseif enddeclare endfor endforeach endif endswitch endwhile ' + - 'extends for foreach function include include_once global if ' + - 'new old_function return static switch use require require_once ' + - 'var while abstract interface public implements extends private protected throw'; - - var constants = '__FILE__ __LINE__ __METHOD__ __FUNCTION__ __CLASS__'; - - this.regexList = [ - { regex: SyntaxHighlighter.regexLib.singleLineCComments, css: 'comments' }, // one line comments - { regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments - { regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings - { regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings - { regex: /\$\w+/g, css: 'variable' }, // variables - { regex: new RegExp(this.getKeywords(funcs), 'gmi'), css: 'functions' }, // common functions - { regex: new RegExp(this.getKeywords(constants), 'gmi'), css: 'constants' }, // constants - { regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keyword - ]; - - this.forHtmlScript(SyntaxHighlighter.regexLib.phpScriptTags); -}; - -SyntaxHighlighter.brushes.Php.prototype = new SyntaxHighlighter.Highlighter(); -SyntaxHighlighter.brushes.Php.aliases = ['php']; diff --git a/includes/kohana/modules/userguide/media/js/shCore.js b/includes/kohana/modules/userguide/media/js/shCore.js deleted file mode 100644 index 5fed4860..00000000 --- a/includes/kohana/modules/userguide/media/js/shCore.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * SyntaxHighlighter - * http://alexgorbatchev.com/ - * - * SyntaxHighlighter is donationware. If you are using it, please donate. - * http://alexgorbatchev.com/wiki/SyntaxHighlighter:Donate - * - * @version - * 2.1.364 (October 15 2009) - * - * @copyright - * Copyright (C) 2004-2009 Alex Gorbatchev. - * - * @license - * This file is part of SyntaxHighlighter. - * - * SyntaxHighlighter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * SyntaxHighlighter is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with SyntaxHighlighter. If not, see . - */ -eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('c(!1q.2X){h 2X=l(){h p={6b:{"1s-R":"","84-2y":1,"83-2y-7W":I,"1I":v,"8d-89":I,"1H-2Q":4,"3g":I,"1w":I,"66":N,"8k-8l":I,"88":N,"5h-1p":I,"1L-1l":N},M:{4T:I,69:v,5l:16,5k:16,8B:N,8f:N,8s:"54",1f:{5q:"53 1g",5d:"9N 1g",5i:"9O 6q 6p",78:"9M C 9L 1V 9I 6p 9J",3t:"3t",6C:"?",1A:"2X\\n\\n",6T:"9K\'t 9P 2O D: ",7x:"9Q 9W\'t 9X D 1L-1l 9V: ",77:"<1L 9t=\\"2s://5x.6x.6B/9s/9x\\"><6z><9y 2s-9E=\\"9F-9D\\" 63=\\"1X/1L; 9C=9z-8\\" /><3i>9A 2X<33 1m=\\"39-9Y:9Z,an,ao,am-al;ai-3f:#aj;3f:#ak;39-2Q:ap;1X-6G:6u;\\">2X6O 2.1.ag (a5 15 6h)2s://6I.3ka3 a0 a1 f 1l, a2 8R 6q 8Q 8O 8W!8V C 8U 8X.8K 8N-6h 8M 8S."},8u:N},1r:{4Z:v,9o:v,3m:v,6f:{}},2d:{},8h:{9g:/\\/\\*[\\s\\S]*?\\*\\//3b,9d:/\\/\\/.*$/3b,9e:/#.*$/3b,9j:/"([^\\\\"\\n]|\\\\.)*"/g,9n:/\'([^\\\\\'\\n]|\\\\.)*\'/g,9m:/"([^\\\\"]|\\\\.)*"/g,8Y:/\'([^\\\\\']|\\\\.)*\'/g,9k:/(&X;|<)!--[\\s\\S]*?--(&Z;|>)/3b,43:/&X;\\w+:\\/\\/[\\w-.\\/?%&=@:;]*&Z;|\\w+:\\/\\/[\\w-.\\/?%&=@:;]*/g,9c:{G:/(&X;|<)\\?=?/g,1d:/\\?(&Z;|>)/g},93:{G:/(&X;|<)%=?/g,1d:/%(&Z;|>)/g},92:{G:/(&X;|<)\\s*1l.*?(&Z;|>)/4e,1d:/(&X;|<)\\/\\s*1l\\s*(&Z;|>)/4e}},1w:{1c:l(3O){h 3T=Q.22("3Y"),5s=p.1w.7d;3T.L="1w";D(h 30 1V 5s){h 6i=5s[30],5t=W 6i(3O),1Y=5t.1c();3O.6g[30]=5t;c(1Y==v){1J}c(7X(1Y)=="91"){1Y=p.1w.6m(1Y,3O.1k,30)}1Y.L+="5v "+30;3T.2p(1Y)}q 3T},6m:l(5L,7j,5K){h a=Q.22("a"),5N=a.1m,5D=p.M,5M=5D.5l,5J=5D.5k;a.27="#"+5K;a.3i=5L;a.5j=7j;a.76=5K;a.1Q=5L;c(40(5M)==N){5N.26=5M+"75"}c(40(5J)==N){5N.2e=5J+"75"}a.9l=l(e){97{p.1w.6M(f,e||1q.6Y,f.5j,f.76)}98(e){p.B.1A(e.6n)}q N};q a},6M:l(7i,7g,7b,7h,7f){h 5G=p.1r.6f[7b],5H;c(5G==v||(5H=5G.6g[7h])==v){q v}q 5H.2z(7i,7g,7f)},7d:{5q:l(5b){f.1c=l(){c(5b.V("66")!=I){q}q p.M.1f.5q};f.2z=l(5c,8T,8P){h A=5b.A;5c.7y.4p(5c);A.L=A.L.E("5O","")}},5d:l(6R){f.1c=l(){q p.M.1f.5d};f.2z=l(b1,bU,bV){h 3J=p.B.3d(6R.5g).E(/"+3J+"");2A.Q.4o()}},5i:l(64){h 3C,c2,6a=64.1k;f.1c=l(){h 2V=p.M;c(2V.69==v){q v}l 1E(56){h 5m="";D(h 5f 1V 56){5m+=""}q 5m};l 2i(5n){h 5p="";D(h 5o 1V 5n){5p+=" "+5o+"=\'"+5n[5o]+"\'"}q 5p};h 67={26:2V.5l,2e:2V.5k,1k:6a+"bY",4r:"bZ/x-71-6V",3i:p.M.1f.5i},5V={bE:"ay",bD:"bC",bA:"5j="+6a,c4:"N"},5U=2V.69,3x;c(/bG/i.1R(6K.7k)){3x="<4h"+2i({bH:"bM:bN-bL-bK-bI-bJ",c3:"2s://ck.cj.3k/cm/71/c9/6V/c8.c7#6O=9,0,0,0"})+2i(67)+">"+1E(5V)+1E({c6:5U})+""}F{3x=""}3C=Q.22("A");3C.1Q=3x;q 3C};f.2z=l(cf,ce,62){h 7c=62.cd;6U(7c){2K"7q":h 61=p.B.2T(p.B.3d(64.5g).E(/&X;/g,"<").E(/&Z;/g,">").E(/&aT;/g,"&"));c(1q.74){1q.74.aU("1X",61)}F{q p.B.2T(61)}2K"aR":p.B.1A(p.M.1f.78);2h;2K"aP":p.B.1A(62.6n);2h}}},aV:l(65){f.1c=l(){q p.M.1f.3t};f.2z=l(aW,bz,b0){h 1Z=Q.22("aZ"),1N=v;c(p.1r.3m!=v){Q.33.4p(p.1r.3m)}p.1r.3m=1Z;1Z.1m.aX="aY:aO;26:6r;2e:6r;G:-6j;4w:-6j;";Q.33.2p(1Z);1N=1Z.5Q.Q;6J(1N,1q.Q);1N.3D(""+65.A.1Q+"");1N.4o();1Z.5Q.4F();1Z.5Q.3t();l 6J(6N,6E){h 2I=6E.4O("4n");D(h i=0;i<2I.u;i++){c(2I[i].6y.6P()=="6A"&&/aE\\.1a$/.1R(2I[i].27)){6N.3D("<4n 4r=\\"1X/1a\\" 6y=\\"6A\\" 27=\\""+2I[i].27+"\\">")}}}}},az:l(aA){f.1c=l(){q p.M.1f.6C};f.2z=l(aF,aG){h 2A=p.B.4z("","4k",aM,aK,"7a=0"),1N=2A.Q;1N.3D(p.M.1f.77);1N.4o();2A.4F()}}}},B:{Y:l(49,73,3y){3y=3e.aH(3y||0,0);D(h i=3y;i<49.u;i++){c(49[i]==73){q i}}q-1},6d:l(72){q 72+3e.aI(3e.b2()*b3).2u()},6c:l(51,4L){h 3h={},1W;D(1W 1V 51){3h[1W]=51[1W]}D(1W 1V 4L){3h[1W]=4L[1W]}q 3h},80:l(4J){6U(4J){2K"I":q I;2K"N":q N}q 4J},4z:l(43,6W,4B,4H,2N){h x=(6X.26-4B)/2,y=(6X.2e-4H)/2;2N+=", G="+x+", 4w="+y+", 26="+4B+", 2e="+4H;2N=2N.E(/^,/,"");h 4E=1q.bk(43,6W,2N);4E.4F();q 4E},7C:l(1G,1T,1U){c(1G.6Z){1G["e"+1T+1U]=1U;1G[1T+1U]=l(){1G["e"+1T+1U](1q.6Y)};1G.6Z("bw"+1T,1G[1T+1U])}F{1G.bv(1T,1U,N)}},1A:l(z){1A(p.M.1f.1A+z)},4u:l(4N,6Q){h 2r=p.1r.4Z,3V=v;c(2r==v){2r={};D(h 2L 1V p.2d){h 42=p.2d[2L].bu;c(42==v){1J}p.2d[2L].R=2L.6P();D(h i=0;i<42.u;i++){2r[42[i]]=2L}}p.1r.4Z=2r}3V=p.2d[2r[4N]];c(3V==v&&6Q!=N){p.B.1A(p.M.1f.6T+4N)}q 3V},46:l(z,6S){h 2E=z.1P("\\n");D(h i=0;i<2E.u;i++){2E[i]=6S(2E[i])}q 2E.5A("\\n")},8C:l(z){q z.E(/^[ ]*[\\n]+|[\\n]*[ ]*$/g,"")},8H:l(z){h 3X,45={},4P=W U("^\\\\[(?<4c>(.*?))\\\\]$"),7e=W U("(?[\\\\w-]+)"+"\\\\s*:\\\\s*"+"(?<24>"+"[\\\\w-%#]+|"+"\\\\[.*?\\\\]|"+"\\".*?\\"|"+"\'.*?\'"+")\\\\s*;?","g");2j((3X=7e.T(z))!=v){h 2f=3X.24.E(/^[\'"]|[\'"]$/g,"");c(2f!=v&&4P.1R(2f)){h m=4P.T(2f);2f=m.4c.u>0?m.4c.1P(/\\s*,\\s*/):[]}45[3X.R]=2f}q 45},7K:l(z,1a){c(z==v||z.u==0||z=="\\n"){q z}z=z.E(/"+2l+""})}q z},7V:l(6l,6o){h 32=6l.2u();2j(32.u<6o){32="0"+32}q 32},6k:l(){h 3w=Q.22("A"),3B,3o=0,44=Q.33,1k=p.B.6d("6k"),36="",4U="";3w.1Q=36+"6e\\">"+36+"1p\\">"+36+"2y\\">"+36+"63"+"\\"><4G 1s=\\"b5\\"><4G 1k=\\""+1k+"\\">&2B;"+4U+4U+2Y+2Y+2Y+2Y;44.2p(3w);3B=Q.bb(1k);c(/bg/i.1R(6K.7k)){h 6v=1q.be(3B,v);3o=85(6v.bc("26"))}F{3o=3B.bd}44.4p(3w);q 3o},8b:l(79,6s){h 1H="";D(h i=0;i<6s;i++){1H+=" "}q 79.E(/\\t/g,1H)},8a:l(2Z,4f){h bF=2Z.1P("\\n"),1H="\\t",4d="";D(h i=0;i<50;i++){4d+=" "}l 8x(3s,18,8A){q 3s.29(0,18)+4d.29(0,8A)+3s.29(18+1,3s.u)};2Z=p.B.46(2Z,l(20){c(20.Y(1H)==-1){q 20}h 18=0;2j((18=20.Y(1H))!=-1){h 8w=4f-18%4f;20=8x(20,18,8w)}q 20});q 2Z},3d:l(z){h br=/|&X;br\\s*\\/?&Z;/4e;c(p.M.8B==I){z=z.E(br,"\\n")}c(p.M.8f==I){z=z.E(br,"")}q z},2G:l(z){q z.E(/^\\s+|\\s+$/g,"")},2T:l(z){h 21=p.B.3d(z).1P("\\n"),bf=W bh(),8D=/^\\s*/,2a=ba;D(h i=0;i<21.u&&2a>0;i++){h 4x=21[i];c(p.B.2G(4x).u==0){1J}h 4I=8D.T(4x);c(4I==v){q z}2a=3e.2a(4I[0].u,2a)}c(2a>0){D(h i=0;i<21.u;i++){21[i]=21[i].29(2a)}}q 21.5A("\\n")},82:l(35,31){c(35.H<31.H){q-1}F{c(35.H>31.H){q 1}F{c(35.u<31.u){q-1}F{c(35.u>31.u){q 1}}}}q 0},2D:l(8q,34){l 8n(4D,8r){q[W p.4v(4D[0],4D.H,8r.1a)]};h b4=0,4s=v,3L=[],8p=34.4X?34.4X:8n;2j((4s=34.3K.T(8q))!=v){3L=3L.2t(8p(4s,34))}q 3L},8m:l(8o){h X="&X;",Z="&Z;";q 8o.E(p.8h.43,l(m){h 4j="",47="";c(m.Y(X)==0){47=X;m=m.3U(X.u)}c(m.Y(Z)==m.u-Z.u){m=m.3U(0,m.u-Z.u);4j=Z}q 47+""+m+""+4j})},8v:l(){h 3N=Q.4O("1l"),4i=[];D(h i=0;i<3N.u;i++){c(3N[i].4r=="6e"){4i.K(3N[i])}}q 4i},8I:l(4b){h 4q="",1v=p.B.2G(4b),3R=N;c(1v.Y(4q)==0){1v=1v.3U(4q.u);3R=I}c(1v.Y(3S)==1v.u-3S.u){1v=1v.3U(0,1v.u-3S.u);3R=I}q 3R?1v:4b}},1I:l(8E,4R){l 8e(4g){h 4Q=[];D(h i=0;i<4g.u;i++){4Q.K(4g[i])}q 4Q};h 2q=4R?[4R]:8e(Q.4O(p.M.8s)),8J="1Q",2k=v,4S=p.M;c(4S.4T){2q=2q.2t(p.B.8v())}c(2q.u===0){q}D(h i=0;i<2q.u;i++){h 2M=2q[i],28=p.B.8H(2M.L),1D,2W,25;28=p.B.6c(8E,28);1D=28["2O"];c(1D==v){1J}c(28["1L-1l"]=="I"||p.6b["1L-1l"]==I){2k=W p.4a(1D);1D="b9"}F{h 3P=p.B.4u(1D);c(3P){1D=3P.R;2k=W 3P()}F{1J}}2W=2M[8J];c(4S.4T){2W=p.B.8I(2W)}28["2O-R"]=1D;2k.1I(2W,28);25=2k.A;c(p.M.8u){25=Q.22("bj");25.24=2k.A.1Q;25.1m.26="bt";25.1m.2e="bx"}2M.7y.bs(25,2M)}},bq:l(7H){p.B.7C(1q,"bl",l(){p.1I(7H)})}};p.4v=l(4A,7G,1a){f.24=4A;f.H=7G;f.u=4A.u;f.1a=1a;f.5Y=v};p.4v.14.2u=l(){q f.24};p.4a=l(4K){h 3z=p.B.4u(4K),2g,4W=W p.2d.bm(),bn=v;c(3z==v){q}2g=W 3z();f.4m=4W;c(2g.3I==v){p.B.1A(p.M.1f.7x+4K);q}4W.59.K({3K:2g.3I.C,4X:7p});l 3A(4Y,7w){D(h j=0;j<4Y.u;j++){4Y[j].H+=7w}};l 7p(19,bp){h 7n=19.C,1o=[],4M=2g.59,7l=19.H+19.G.u,2U=2g.3I,1n;D(h i=0;i<4M.u;i++){1n=p.B.2D(7n,4M[i]);3A(1n,7l);1o=1o.2t(1n)}c(2U.G!=v&&19.G!=v){1n=p.B.2D(19.G,2U.G);3A(1n,19.H);1o=1o.2t(1n)}c(2U.1d!=v&&19.1d!=v){1n=p.B.2D(19.1d,2U.1d);3A(1n,19.H+19[0].bo(19.1d));1o=1o.2t(1n)}D(h j=0;j<1o.u;j++){1o[j].5Y=3z.R}q 1o}};p.4a.14.1I=l(7t,7s){f.4m.1I(7t,7s);f.A=f.4m.A};p.7I=l(){};p.7I.14={V:l(7J,7Z){h 4l=f.1E[7J];q p.B.80(4l==v?7Z:4l)},1c:l(7Y){q Q.22(7Y)},8i:l(2F,81){h 3u=[];c(2F!=v){D(h i=0;i<2F.u;i++){c(7X(2F[i])=="4h"){3u=3u.2t(p.B.2D(81,2F[i]))}}}q 3u.aB(p.B.82)},86:l(){h 23=f.2C;D(h i=0;i<23.u;i++){c(23[i]===v){1J}h 2x=23[i],4V=2x.H+2x.u;D(h j=i+1;j<23.u&&23[i]!==v;j++){h 1S=23[j];c(1S===v){1J}F{c(1S.H>4V){2h}F{c(1S.H==2x.H&&1S.u>2x.u){f.2C[i]=v}F{c(1S.H>=2x.H&&1S.H<4V){f.2C[j]=v}}}}}}},8t:l(2H){h 3r=2H.1P(/\\n/g),3n=85(f.V("84-2y")),2v=f.V("83-2y-7W"),7N=f.V("1I",[]),7U=f.V("3g");2H="";c(2v==I){2v=(3n+3r.u-1).2u().u}F{c(40(2v)==I){2v=0}}D(h i=0;i<3r.u;i++){h 1x=3r[i],60=/^(&2B;|\\s)+/.T(1x),52="aN"+(i%2==0?1:2),7F=p.B.7V(3n+i,2v),7P=p.B.Y(7N,(3n+i).2u())!=-1,2S=v;c(60!=v){2S=60[0].2u();1x=1x.29(2S.u)}1x=p.B.2G(1x);c(1x.u==0){1x="&2B;"}c(7P){52+=" aQ"}2H+=""+"<7L>"+"<7T>"+(7U?"<3F 1s=\\"aS\\">"+7F+"":"")+"<3F 1s=\\"63\\">"+(2S!=v?""+2S.E(" ","&2B;")+"":"")+1x+""+""+""+""}q 2H},8y:l(5X,5T){h 18=0,3c="",3a=p.B.7K,5S=f.V("2O-R","");l 5W(5Z){h 5R=5Z?(5Z.5Y||5S):5S;q 5R?5R+" ":""};D(h i=0;i<5T.u;i++){h 1y=5T[i],3G;c(1y===v||1y.u===0){1J}3G=5W(1y);3c+=3a(5X.29(18,1y.H-18),3G+"7O")+3a(1y.24,3G+1y.1a);18=1y.H+1y.u}3c+=3a(5X.29(18),5W()+"7O");q 3c},1I:l(C,7E){h cb=p.M,1r=p.1r,A,ci,3Z,ch="cn";f.1E={};f.A=v;f.1p=v;f.C=v;f.1i=v;f.6g={};f.1k=p.B.6d("cl");1r.6f[f.1k]=f;c(C===v){C=""}f.1E=p.B.6c(p.6b,7E||{});c(f.V("88")==I){f.1E.1w=f.1E.3g=N}f.A=A=f.1c("3Y");f.1p=f.1c("3Y");f.1p.L="1p";L="6e";A.1k=f.1k;c(f.V("66")){L+=" 5O"}c(f.V("3g")==N){L+=" bB"}c(f.V("5h-1p")==N){f.1p.L+=" bO-5h"}L+=" "+f.V("1s-R");L+=" "+f.V("2O-R");A.L=L;f.5g=C;f.C=p.B.8C(C).E(/\\r/g," ");3Z=f.V("1H-2Q");f.C=f.V("8d-89")==I?p.B.8a(f.C,3Z):p.B.8b(f.C,3Z);f.C=p.B.2T(f.C);c(f.V("1w")){f.1i=f.1c("3Y");f.1i.L="1i";f.1i.2p(p.1w.1c(f));A.2p(f.1i);h 1i=f.1i;l 58(){1i.L=1i.L.E("53","")};A.c0=l(){58();1i.L+=" 53"};A.bX=l(){58()}}A.2p(f.1p);f.2C=f.8i(f.59,f.C);f.86();C=f.8y(f.C,f.2C);C=f.8t(p.B.2G(C));c(f.V("8k-8l")){C=p.B.8m(C)}f.1p.1Q=C},9f:l(z){z=z.E(/^\\s+|\\s+$/g,"").E(/\\s+/g,"|");q"\\\\b(?:"+z+")\\\\b"},9i:l(2J){f.3I={G:{3K:2J.G,1a:"1l"},1d:{3K:2J.1d,1a:"1l"},C:W U("(?"+2J.G.1g+")"+"(?.*?)"+"(?<1d>"+2J.1d.1g+")","96")}}};q p}()}c(!1q.U){(l(){h 2w={T:10.14.T,87:5I.14.87,E:5I.14.E,1P:5I.14.1P},1F={13:/(?:[^\\\\([#\\s.]+|\\\\(?!k<[\\w$]+>|[7z]{[^}]+})[\\S\\s]?|\\((?=\\?(?!#|<[\\w$]+>)))+|(\\()(?:\\?(?:(#)[^)]*\\)|<([$\\w]+)>))?|\\\\(?:k<([\\w$]+)>|[7z]{([^}]+)})|(\\[\\^?)|([\\S\\s])/g,99:/(?:[^$]+|\\$(?![1-9$&`\']|{[$\\w]+}))+|\\$(?:([1-9]\\d*|[$&`\'])|{([$\\w]+)})/g,37:/^(?:\\s+|#.*)+/,5B:/^(?:[?*+]|{\\d+(?:,\\d*)?})/,7Q:/&&\\[\\^?/g,7S:/]/g},7o=l(5C,5v,5u){D(h i=5u||0;i<5C.u;i++){c(5C[i]===5v){q i}}q-1},8G=/()??/.T("")[1]!==3j,3q={};U=l(1e,1O){c(1e 68 10){c(1O!==3j){3H 7r("4y\'t 4C 9a 8z 95 7u 10 5u 94")}q 1e.3E()}h 1O=1O||"",7R=1O.Y("s")>-1,7M=1O.Y("x")>-1,5z=N,3v=[],1b=[],13=1F.13,J,cc,38,3M,3p;13.O=0;2j(J=2w.T.2n(13,1e)){c(J[2]){c(!1F.5B.1R(1e.17(13.O))){1b.K("(?:)")}}F{c(J[1]){3v.K(J[3]||v);c(J[3]){5z=I}1b.K("(")}F{c(J[4]){3M=7o(3v,J[4]);1b.K(3M>-1?"\\\\"+(3M+1)+(40(1e.5w(13.O))?"":"(?:)"):J[0])}F{c(J[5]){1b.K(3q.7m?3q.7m.7q(J[5],J[0].5w(1)==="P"):J[0])}F{c(J[6]){c(1e.5w(13.O)==="]"){1b.K(J[6]==="["?"(?!)":"[\\\\S\\\\s]");13.O++}F{cc=U.8g("&&"+1e.17(J.H),1F.7Q,1F.7S,"",{7D:"\\\\"})[0];1b.K(J[6]+cc+"]");13.O+=cc.u+1}}F{c(J[7]){c(7R&&J[7]==="."){1b.K("[\\\\S\\\\s]")}F{c(7M&&1F.37.1R(J[7])){38=2w.T.2n(1F.37,1e.17(13.O-1))[0].u;c(!1F.5B.1R(1e.17(13.O-1+38))){1b.K("(?:)")}13.O+=38-1}F{1b.K(J[7])}}}F{1b.K(J[0])}}}}}}}3p=10(1b.5A(""),2w.E.2n(1O,/[9B]+/g,""));3p.1C={1g:1e,2m:5z?3v:v};q 3p};U.9q=l(R,o){3q[R]=o};10.14.T=l(z){h 1h=2w.T.2n(f,z),R,i,5y;c(1h){c(8G&&1h.u>1){5y=W 10("^"+f.1g+"$(?!\\\\s)",f.5E());2w.E.2n(1h[0],5y,l(){D(i=1;i<8j.u-2;i++){c(8j[i]===3j){1h[i]=3j}}})}c(f.1C&&f.1C.2m){D(i=1;i<1h.u;i++){R=f.1C.2m[i-1];c(R){1h[R]=1h[i]}}}c(f.3l&&f.O>(1h.H+1h[0].u)){f.O--}}q 1h}})()}10.14.5E=l(){q(f.3l?"g":"")+(f.av?"i":"")+(f.8F?"m":"")+(f.37?"x":"")+(f.a4?"y":"")};10.14.3E=l(7A){h 5F=W U(f.1g,(7A||"")+f.5E());c(f.1C){5F.1C={1g:f.1C.1g,2m:f.1C.2m?f.1C.2m.17(0):v}}q 5F};10.14.2n=l(90,z){q f.T(z)};10.14.9b=l(9h,8c){q f.T(8c[0])};U.5P=l(57,5e){h 55="/"+57+"/"+(5e||"");q U.5P[55]||(U.5P[55]=W U(57,5e))};U.41=l(z){q z.E(/[-[\\]{}()*+?.\\\\^$|,#\\s]/g,"\\\\$&")};U.8g=l(z,G,11,1j,2R){h 2R=2R||{},2P=2R.7D,12=2R.c5,1j=1j||"",5r=1j.Y("g")>-1,70=1j.Y("i")>-1,7v=1j.Y("m")>-1,5a=1j.Y("y")>-1,1j=1j.E(/y/g,""),G=G 68 10?(G.3l?G:G.3E("g")):W U(G,"g"+1j),11=11 68 10?(11.3l?11:11.3E("g")):W U(11,"g"+1j),1M=[],2o=0,1u=0,1t=0,1z=0,2b,2c,1B,1K,3Q,48;c(2P){c(2P.u>1){3H aC("4y\'t 4C aL aJ 7u 41 7B")}c(7v){3H 7r("4y\'t 4C 41 7B 8z bi b8 8F b7")}3Q=U.41(2P);48=W 10("^(?:"+3Q+"[\\\\S\\\\s]|(?:(?!"+G.1g+"|"+11.1g+")[^"+3Q+"])+)+",70?"i":"")}2j(I){G.O=11.O=1t+(2P?(48.T(z.17(1t))||[""])[0].u:0);1B=G.T(z);1K=11.T(z);c(1B&&1K){c(1B.H<=1K.H){1K=v}F{1B=v}}c(1B||1K){1u=(1B||1K).H;1t=(1B?G:11).O}F{c(!2o){2h}}c(5a&&!2o&&1u>1z){2h}c(1B){c(!2o++){2b=1u;2c=1t}}F{c(1K&&2o){c(!--2o){c(12){c(12[0]&&2b>1z){1M.K([12[0],z.17(1z,2b),1z,2b])}c(12[1]){1M.K([12[1],z.17(2b,2c),2b,2c])}c(12[2]){1M.K([12[2],z.17(2c,1u),2c,1u])}c(12[3]){1M.K([12[3],z.17(1u,1t),1u,1t])}}F{1M.K(z.17(2c,1u))}1z=1t;c(!5r){2h}}}F{G.O=11.O=0;3H bP("8L aq 9r ar 8Z")}}c(1u===1t){1t++}}c(5r&&!5a&&12&&12[0]&&z.u>1z){1M.K([12[0],z.17(1z),1z,z.u])}G.O=11.O=0;q 1M};',62,768,'||||||||||||if|||this||var||||function||||sh|return||||length|null||||str|div|utils|code|for|replace|else|left|index|true|_121|push|className|config|false|lastIndex||document|name||exec|XRegExp|getParam|new|lt|indexOf|gt|RegExp|_139|vN|part|prototype|||slice|pos|_d3|css|_11f|create|right|_119|strings|source|_129|bar|_13a|id|script|style|_da|_d6|lines|window|vars|class|_145|_144|_b5|toolbar|_f4|_103|_146|alert|_149|_x|_c3|params|lib|obj|tab|highlight|continue|_14a|html|_142|doc|_11a|split|innerHTML|test|_ec|_5a|_5b|in|_4f|text|_8|_3c|_91|_98|createElement|_e7|value|_c5|width|href|_c2|substr|min|_147|_148|brushes|height|_6e|_cd|break|attributes|while|_be|_75|captureNames|call|_143|appendChild|_bc|_5f|http|concat|toString|_f0|real|_e9|line|execute|wnd|nbsp|matches|getMatches|_66|_e3|trim|_ed|_40|_10f|case|_61|_c1|_55|brush|_13c|size|_13b|_f9|unindent|_d9|_28|_c4|SyntaxHighlighter|_81|_88|_5|m2|_7a|body|_a2|m1|_80|extended|len|font|_fe|gm|_fd|fixInputString|Math|color|gutter|_4e|title|undefined|com|global|printFrame|_ef|_7d|_125|_118|_ee|_8e|print|_e5|_11e|_7b|_32|_49|_cc|offsetMatches|_7c|_25|write|addFlags|td|_104|throw|htmlScript|_22|regex|_a7|_124|_af|_2|_c6|_14b|_b6|_b4|_3|substring|_60|_76|_6a|DIV|_10b|isNaN|escape|_62|url|_7e|_6b|eachLine|_ae|esc|_47|HtmlScript|_b2|values|_8c|gi|_89|_b9|object|_b0|_ad|_blank|_e1|xmlBrush|link|close|removeChild|_b3|type|_a6|_73|findBrush|Match|top|_9d|can|popup|_c8|_53|supply|_a3|win|focus|span|_54|_9e|_50|_cb|_4d|_d7|_5d|getElementsByTagName|_6c|_ba|_b8|_bf|useScriptTags|_82|_ea|_ce|func|_d0|discoveredBrushes||_4c|_f6|show|pre|key|_29|_133|hide|regexList|_141|_19|_1a|viewSource|_134|_2b|originalCode|wrap|copyToClipboard|highlighterId|toolbarItemHeight|toolbarItemWidth|_2a|_2c|_2e|_2d|expandSource|_13e|_4|_7|from|item|charAt|www|r2|_11d|join|quantifier|_113|_e|getNativeFlags|_12e|_17|_18|String|_10|_b|_9|_f|_d|collapsed|cache|contentWindow|_101|_ff|_fb|swf|_30|getBrushNameCss|_fa|brushName|_100|_f5|_37|_35|content|_24|_38|collapse|_2f|instanceof|clipboardSwf|_27|defaults|merge|guid|syntaxhighlighter|highlighters|toolbarCommands|2009|_6|500px|measureSpace|_78|createButton|message|_79|clipboard|to|0px|_85|decoration|center|_83|margin|w3|rel|head|stylesheet|org|help|xhtml1|_3f|0099FF|align|DTD|alexgorbatchev|copyStyles|navigator|none|executeCommand|_3e|version|toLowerCase|_5e|_1e|_65|noBrush|switch|flash|_52|screen|event|attachEvent|_13f|shockwave|_4b|_48|clipboardData|px|commandName|aboutDialog|copyToClipboardConfirmation|_84|scrollbars|_14|_36|items|_6d|_16|_13|_15|_12|_a|userAgent|_d8|unicode|_d5|_112|process|get|TypeError|_de|_dd|one|_140|_d1|brushNotHtmlScript|parentNode|pP|_12d|character|addEvent|escapeChar|_106|_f7|_c9|_c7|Highlighter|_df|decorate|table|_11c|_f1|plain|_f8|classLeft|_11b|classRight|tr|_f2|padNumber|numbers|typeof|_e2|_e0|toBoolean|_e4|matchesSortCallback|pad|first|parseInt|removeNestedMatches|match|light|tabs|processSmartTabs|processTabs|args|smart|toArray|stripBrs|matchRecursive|regexLib|findMatches|arguments|auto|links|processUrls|defaultAdd|_a9|_a8|_a1|_a4|tagName|createDisplayLines|debug|getSyntaxHighlighterScriptTags|_93|insertSpaces|processMatches|when|_90|bloggerMode|trimFirstAndLastLines|_9a|_b7|multiline|_117|parseParams|stripCData|_bd|Copyright|subject|Alex|2004|development|_1c|keep|donate|Gorbatchev|_1b|syntax|JavaScript|active|highlighter|multiLineSingleQuotedString|delimiters|_12f|string|scriptScriptTags|aspScriptTags|another|constructing|sgi|try|catch|replaceVar|flags|apply|phpScriptTags|singleLineCComments|singleLinePerlComments|getKeywords|multiLineCComments|_131|forHtmlScript|doubleQuotedString|xmlComments|onclick|multiLineDoubleQuotedString|singleQuotedString|spaceWidth|bottom|addPlugin|contains|1999|xmlns|dtd|TR|transitional|xhtml|meta|utf|About|sx|charset|Type|equiv|Content|EN|Transitional|your|now|Can|is|The|view|copy|find|Brush|PUBLIC|W3C|XHTML|DOCTYPE|option|wasn|configured|family|Geneva|you|like|please|If|sticky|October|target|https|paypal|_s|xclick|hosted_button_id|cmd|webscr|cgi|bin|364|4em|background|fff|000|serif|sans|Arial|Helvetica|1em|data|unbalanced|75em|large|xx|ignoreCase|3em|2930402|always|about|_42|sort|SyntaxError|printing|shCore|_43|_44|max|round|than|250|more|500|alt|absolute|error|highlighted|ok|number|amp|setData|printSource|_39|cssText|position|IFRAME|_3b|_1f|random|1000000|_a5|block|CDATA|flag|the|htmlscript|1000|getElementById|getPropertyValue|offsetWidth|getComputedStyle|_99|opera|Array|using|textarea|open|load|Xml|_cf|lastIndexOf|_d4|all||replaceChild|70em|aliases|addEventListener|on|30em|spaces|_3a|flashVars|nogutter|transparent|wmode|allowScriptAccess|_8a|msie|classid|96b8|444553540000|11cf|ae6d|clsid|d27cdb6e|no|Error|location|resizable|400|750|_20|_21|menubar|onmouseout|_clipboard|application|onmouseover|param|_26|codebase|menu|valueNames|movie|cab|swflash|cabs|embed|conf||command|_34|_33|src|_10c|_10a|macromedia|download|highlighter_|pub|important'.split('|'),0,{})) diff --git a/includes/kohana/modules/userguide/vendor/markdown/License.text b/includes/kohana/modules/userguide/vendor/markdown/License.text old mode 100755 new mode 100644 diff --git a/includes/kohana/modules/userguide/vendor/markdown/markdown.php b/includes/kohana/modules/userguide/vendor/markdown/markdown.php old mode 100755 new mode 100644 diff --git a/includes/kohana/modules/userguide/views/userguide/api/class.php b/includes/kohana/modules/userguide/views/userguide/api/class.php index 78bf73de..0b54712a 100644 --- a/includes/kohana/modules/userguide/views/userguide/api/class.php +++ b/includes/kohana/modules/userguide/views/userguide/api/class.php @@ -2,13 +2,33 @@ modifiers, $doc->class->name ?> class; ?> getParentClass()): ?> -
    uri(array('class' => $parent->name)), $parent->name) ?> +
    extends uri(array('class' => $parent->name)), $parent->name, NULL, NULL, TRUE) ?> -

    -
    -
    +description ?> + +tags): ?> +
    +tags as $name => $set): ?> +
    + +
    + + +
    + + +

    +class->getFilename()): ?> +Class declared in on line class->getStartLine() ?>. + +Class is not declared in a file, it is probably an internal class->name).'.php', 'PHP class') ?>. + +

    + +
    +

      constants): ?> @@ -20,7 +40,7 @@
    -
    +

      properties()): ?> @@ -32,7 +52,7 @@
    -
    +

    -description ?> - -tags) echo View::factory('userguide/api/tags')->set('tags', $doc->tags) ?> - -

    -class->getFilename()): ?> -Class declared in on line class->getStartLine() ?>. - -Class is not declared in a file, it is probably an internal class->name).'.php', 'PHP class') ?>. - -

    +
    constants): ?>
    -

    +

    constants as $name => $value): ?> -
    +

    @@ -71,11 +81,11 @@ Class is not declared in a file, it is probably an internal properties()): ?> -

    +

    -
    modifiers ?> type ?> $property->name ?>
    +

    modifiers ?> type ?> $property->name ?>

    description ?>
    value ?>
    @@ -84,7 +94,7 @@ Class is not declared in a file, it is probably an internal methods()): ?> -

    +

    set('doc', $method)->set('route', $route) ?> diff --git a/includes/kohana/modules/userguide/views/userguide/api/menu.php b/includes/kohana/modules/userguide/views/userguide/api/menu.php index 7d9bbe83..4f4f22f7 100644 --- a/includes/kohana/modules/userguide/views/userguide/api/menu.php +++ b/includes/kohana/modules/userguide/views/userguide/api/menu.php @@ -1,14 +1,16 @@ + +

    Modules