80aj_coder Blog

80AJ Blog


如何写自己的文档

如何写自己的文档

[阅读]

Working_with_assets

Working_with_assets

Working with Assets Bonfire considers any CSS files, javascript files, and many image files to be Assets. While we understand that projects will often contain Flash files or other types of files that would be considered ‘assets’, Bonfire only accounts for these three types of files but does provide some helper methods to assist with other types of files. Assets files can be stored in an application-wide repository, in your theme, or with each module. Because of the possibility of some of these files not being web-accessible, module-related assets are always combined and cached in a web-accessible folder. Assets can be located in one of several locations: /bonfire/modules/my_module/assets /public/themes/active_theme/assets /public/themes/default_theme/assets /public/assets Whenever you use one of the asset rendering methods, like css(), js(), and image(), it will search in each of those folders (as well as a folder named by the asset type under those folders, ie. ‘css’) in the order listed above. Note that it only looks within the module if it was added via add_module_css() or add_module_js(). ### Customizing Asset Base Folder If you need to, you can customize the folders that your assets are located in via settings in the /application/config/application.php configuration file. To change the primary folder that all of your assets are located in, you can set the 'base' key in the assets.directories setting. Note that this is not recommended as it may cause instability in the application. Testing has not been done to ensure that this is a viable option at the moment. $config['assets.directories'] = array( 'base' => 'assets', 'cache' => 'cache', 'css' => 'css', 'image' => 'images', 'js' => 'js', 'module' => 'module', ); ### Customizing Asset Folders Within the base folder (above), each asset is organized by asset type. By default, the folders are named js, css, and images. This can be changed in the assets.directories setting in the application config file. Again, though this has not been tested to ensure this works. Changing this value might render your site unusable. $config['assets.directories'] = array( 'base' => 'assets', 'cache' => 'cache', 'css' => 'css', 'image' => 'images', 'js' => 'js', 'module' => 'module', ); ## Working With CSS Stylesheets can be hosted with the application or on other servers. However, when it comes time to tweak your site’s front-end performance, only those files that are hosted locally with the site can be combined and minified successfully. It is recommended that you always use the raw stylesheets (not minified) to take full advantage of the minification abilities, as minifying a CSS file twice might corrupt the styles. ### css() This method provides a simple way to render all of your CSS links in one method call. It can be used in two different fashions: to output a single link tag, or to output link tags to all stylesheets that it knows about. Whenever a relative path is provided, it is assumed to be relative to either the main folder being searched in (i.e. /public/assets) or the type-specific folder (e.g. /public/assets/css). When called with no parameters, the css() method will create links for all stylesheets that have been added to it via either the add_css() or add_module_css() methods, below. Assets::css(); // Creates: <link rel="stylesheet" type="text/css" href="http://mysite.com/themes/default/screen.css" media="screen" /> Media Type You can specify the media type for your CSS to render, by passing it as the second parameter. The default value is ‘screen’. Assets::css(null, 'screen'); Bypassing Inheritance Bonfire’s Assets system is designed with a Parent/Child theme framework in mind. That means that you can quickly build a new theme that inherits all of a default (or parent) theme and only changing the files that need to be changed. This applies to both assets and layout files. If you’re using a theme that you’ve created called ‘darthvader’, it will look for files of the same name in both the darthvader theme and the default theme. If you do not want it to look for and include these files, you can pass in TRUE as the third parameter. Assets::css(null, 'screen', TRUE); Global Files A couple of different files will automatically appear within your styles, without you needing to do any work. The Assets library will search for a file within your theme for a file named the same as the media that you’re currently rendering. By default, this is the public/themes/my_theme/screen.css file. It will also look for any stylesheets within your theme that match the name of the controller that is active. So, if the blog controller is currently running, it will look for a file at public/themes/my_theme/blog.css. Rendering a Single File When you just want to output a link to a single CSS file, you can use the css() method with a single parameter that is the name of the file to link to. The link can be either relative or absolute. echo Assets::css('http://mysite.com/path/to/my.css'); // Output: <link rel="stylesheet" type="text/css" href="http://mysite.com/path/to/my.css" media="screen" /> echo Assets::css('/path/to/my.css'); // Output: <link rel="stylesheet" type="text/css" href="http://mysite.com/path/to/my.css" media="screen" /> Rendering Multiple Custom Files If you want to render multiple links to CSS files, you can pass an array of stylesheets. These stylesheets will be merged with any styles that have been previously added via either add_css() or add_module_css(). $styles = array( 'bootstrap.css', 'markitup/sets/minimal/styles' ); Assets::css($styles); ### add_css() Adds additional file(s) to the links that are output with the css() method. The first parameters is the name of the file to be linked to. It should be relative to one of the paths described above. The second, optional, parameter is the media type. This defaults to ‘screen’. Assets::add_css('blog.css'); ### add_module_css() Adds a stylesheet that is part of a module to the styles to be output with the css() method. The first parameter is the name of the module. The second is the name of the file to be linked to. The third, optional, parameter is the media type this file belongs to. It defaults to ‘screen’. Assets::add_module_css('blog', 'posts.css'); Because module files are often inaccessible via a web browser, all module files are combined and cached in the public/assets/cache folder. The name of the file is built as follows for the maximum reuse: {theme name}_{module name}_{controller name}_mod.css The above blog/posts.css file would be in a file named default_blog_blog_mod.css. ## Working With Javascript Script files can be hosted with the application or on other servers. However, when it comes time to tweak your site’s front-end performance, only those files that are hosted locally with the site can be combined and minified successfully. It is recommended that you always use the raw scripts (not minified) to take full advantage of the minification abilities, as minifying a JS file twice might corrupt the script. For the sake of the Assets library, javascript files are broken up into 3 types of scripts: External scripts are javascript files that included with a <script src=""></script> tag. These will typically be hosted with your site, but might be hosted on another server. Inline scripts are scripts that are intended to be written out as part of the page’s HTML. You may include a file as inline for performance reasons or simply because it only affects a single page on your site and including it in a larger external file does not make sense. Module scripts are scripts that are part of a module within Bonfire. Because of security reasons, you often will not be to access the module files from the browser so these scripts are always combined and cached in the main assets/ folder. ### js() This method provides a single call to render all external, module, or inline script tags. Whenever a relative path is provided, it is assumed to be relative to either the main folder being searched in (i.e. /public/assets) or the type-specific folder (e.g. /public/assets/js). When called with no parameters, the js() method will create links/inline-code for all scripts that it knows about. echo Assets::js(); Might produce: <script src="http://bonfire.dev/assets/js/bootstrap.min.js" type="text/javascript" ></script> <script type="text/javascript"> $(document).ready(function(){ $(".dropdown-toggle").dropdown();$(".tooltips").tooltip();$(".login-btn").click(function(e){ e.preventDefault(); $("#modal-login").modal(); }); }); </script> Notice that the inline scripts are automatically wrapped with customizable open and close strings. In this case, it produced an appropriate wrapper for use with jQuery. This can be changed in the application/config/application.php file. $config['assets.js_opener'] = '$(document).ready(function(){'. "\n"; $config['assets.js_closer'] = '});'. "\n"; Single Script Tags If you pass the name of a script file as the first parameter, then it will output a link to only that file. Note that if it cannot find the script in any of the standard locations, it will not create a link for it. echo Assets::js('some_script.js'); Adding Scripts while Rendering You can pass an array of script files as the first parameter of the script and they will be added to the scripts to be linked to. The function will then proceedd as if you had not passed any parameters in, creating links for all external, inline, and module scripts, including the ones that you did actually pass in. An optional second parameter allows you to specify whether the scripts are ‘external’ or ‘inline’; echo Assets::js( array('script1.js', 'script2.js'), 'inline' ); ### external_js() This method creates the links for all external scripts that it knows about. This is called automatically by the js() method and does not need to be called again if you are using that method. You can pass either an array of scripts or a single script as the first parameter and only those script files will have links created for them. If you are using a JS loader, like head.js, you might need a list of files instead of links created. You can get this by passing true as the second parameter. echo Assets::external_js(array('script1.js', 'script2.js'), true); // Produces "http://mysite.com/assets/js/script1.js", "http://mysite.com/assets/js/script2.js" By default, the Assets library will ensure that all files have a .js file extension. If you have some files have a different extension, you can pass false as the third parameter. ### inline_js() Handles the inline script creation for the js() method. You do not need to call this script by itself when using that method. ### module_js() Returns a link to a combined file that includes any scripts added with the add_module_js() method, below. When this method is called, all files are combined into a single file that is cached in the primary public/assets/cache folder. You can affect how the file is named as well as minification of the new file, via options that are discussed in Section 5, below. ## Working With Images With mobile/desktop development becoming so prevalent, you often need a simple method to get an image that is only as big as you need it to be, smaller for mobile browsers and larger for desktops. With responsive design, you can fine-tune the bandwidth that your site’s images are consuming even further based on the width of the browser window. Bonfire’s image controller provides simple, on-the-fly creation of resized images. This is available at: http://mysite.com/images Image Size and Cropping To return a square thumbnail of a large photo, you can choose to let the images library automatically crop the photo for you, while creating a thumbnail image. Pass along a size parameter that will define how wide and how tall the image should be. <a href="http://mysite.com/images?size=80">My Thumbnail</a> If you prefer to set a specific height and width, in pixels, for the image, you can use the height and width params to the url. <a href="http://mysite.com/images?height=60&width=100">My Thumbnail</a> You can also simply pass a width or height params to intelligently resize the image. Whichever param is passed will determine which is the “master” param. ex. If height is passed, the image will resize to a height of 60 and whatever width maintains aspect-ratio. <a href="http://mysite.com/images?height=60"> By default, Bonfire will scale your image to fit within the new image size. To resize the image and disregard aspect-ratio, pass along a ratio=no parameter. <a href="http://mysite.com/images?size=80&ratio=no">My Thumbnail</a> Image File Path Bonfire will look for the images within the public/assets/images folder in your web root. If you need to pull files from a different folder, you can use the assets parameter and pass in a folder relative to the webroot. <a href="http://mysite.com/images?size=80&assets=assets/images">My Thumbnail</a> Module Images If you have images stored in a specific module you can access those images by passing the module name to the module parameter. <a href="http://mysite.com/images/image=name.png?module=blog">Blog Image</a> This will load an image in the assets/images folder in the blog module: /application/modules/blog/assets/images/image-name.png ## Boosting Performance Large strides have been made over the last few years in recognizing techniques to help boost your client-side performance, or apparent performance to make it feel to the user like your site is loading faster. Bonfire provides a couple of different tools to help you with that. ### Combining Assets Into Fewer Files The first step to take usually involves combining your CSS and javascript files into as few files as possible to reduce the number of HTTP connections needed, since these are relatively slow. You can turn on combining files in your application/config/application.php configuration file. It is recommended to turn off combining in your development environment but turn it on in testing and production environments. $config['assets.combine'] = true; This will create 2 files that are cached within the public/assets/cache folder. The first file combines all external files that are hosted within this site into a single file. The second file contains all of your module-specific files. This is the same file that is always generated for module js and css files. Combining works for both CSS and Javascript files. ### Minimizing Assets In addition to just combining the files, you can minimize your CSS and Javascript files, reducing the amount of bandwidth used for every page. You can turn on minizing files in your application/config/application.php configuration file. It is recommended to turn off minimizing in your development environment but turn it on in testing and production environments. $config['assets.js_minify'] = true; $config['assets.css_minify'] = true; ### Encrypting File Names While not a performance booster, those more security-conscious developers might dislike the typical naming convention of your cached asset files which display limited amount of information about the controller and module running. To obscure this information you can turn on file name encryption. This creates an md5 hash of the normal file name to cache the file as. $config['assets.encrypt_name'] = true; ### Clearing the Asset Cache You can delete all of your asset’s cached files by calling the clear_cache() method. ALL cached assets will be deleted. Assets::clear_cache(); ## Helper Functions Three helper functions are provided to help create manual links to assets within your view files. ### assets_path() This returns a full URI to the main asset folder. echo assets_path(); // Produces http://mysite.com/assets/ ### css_path() This returns a full URI to the CSS folder. echo css_path(); // Produces http://mysite.com/assets/css/ ### js_path() This returns a full URI to the scripts folder. echo js_path(); // Produces http://mysite.com/assets/js/ ### img_path() This returns a full URI to the images folder. echo img_path(); // Produces http://mysite.com/assets/images/ [阅读]

Tut_blog

Tut_blog

A Simple Blog Tutorial This tutorial will teach you the basics of how to work with Bonfire. Along the way, you will learn the basic concepts you need to know to best work within the system. You will learn the details and the code. We believe it’s best to learn how to do things the long way, before using the power of the Module Builder. ## Creating A Module While modules are not required to use Bonfire, it makes extensive use of modules to encourage code reuse and organization. Whithin this tutorial we will create a new blog module. The first step is to get the folder structure created and make sure the settings are correct for it to show up in the admin menu. Folder Structure Within the application/modules folder, create a new folder named blog, and create the following subfolders: assets, config, controllers, migrations, models, views. When you’re done your module should look like: application/ modules/ blog/ assets/ config/ controllers/ migrations/ models/ views/ Not every module will require every folder, but these are the basic folders every module can use. Basic Configuration To make sure that your blog shows up in the admin area, you need to create a config file that holds various settings to let Bonfire know about your module. The config file is not required, but allows more control over how your module appears throughout the system. Create a new file in your new config folder, called config.php. <?php defined('BASEPATH') || exit('No direct script access allowed'); $config['module_config'] = array( 'name' => 'Blog', 'description' => 'A Simple Blog Example', 'author' => 'Your Name', 'homepage' => 'http://...', 'version' => '1.0.1', ); Not all of these settings will be used for the Blog module, but you should understand how they work. name is the human-readable name of your module. description is a short description of your module and will appear in a list of installed modules. author is your name or the name of your organization/team. homepage is the URL to the homepage of your module. Will appear as a link in the installed modules page. version is a simple version string. Setup the Database To allow for simple versioning of your database, use Bonfire’s migrations. This is great for working in teams where modifications to the database might be made by several members on the development team. It also makes it fairly simple to bring your changes to the production database. In the case of a module like our blog module, it allows us to easily re-use the module in another application and quickly get the database setup. Migrations are simply a set of commands that are run to make changes to the database or remove changes. They are stored in the module’s migrations folder, using sequentially numbered files. Create a new file at blog/migrations/001_Initial_tables.php. <?php defined('BASEPATH') || exit('No direct script access allowed'); class Migration_Initial_tables extends Migration { private $permissionValues = array( array('name' => 'Bonfire.Blog.View', 'description' => 'View the blog menu.', 'status' => 'active'), array('name' => 'Bonfire.Blog.Delete', 'description' => 'Delete blog entries', 'status' => 'active'), ); private $permittedRoles = array( 'Administrator', ); /** * The definition(s) for the table(s) used by this migration. * @type array */ private $tables = array( 'posts' => array( 'primaryKey' => 'post_id', 'fields' => array( 'post_id' => array( 'type' => 'bigint', 'constraint' => 20, 'unsigned' => true, 'auto_increment' => true, ), 'title' => array( 'type' => 'varchar', 'constraint' => 255, 'null' => false, ), 'slug' => array( 'type' => 'varchar', 'constraint' => 255, 'null' => false, ), 'body' => array( 'type' => 'text', 'null' => true, ), 'created_on' => array( 'type' => 'datetime', 'null' => false, ), 'modified_on' => array( 'type' => 'datetime', 'null' => false, ), 'deleted' => array( 'type' => 'tinyint', 'constraint' => 1, 'null' => false, 'default' => 0, ), ), ), ); /** * Install the blog tables * * @return void */ public function up() { $this->load->dbforge(); // Install the table(s) in the database. foreach ($this->tables as $tableName => $tableDef) { $this->dbforge->add_field($tableDef['fields']); $this->dbforge->add_key($tableDef['primaryKey'], true); $this->dbforge->create_table($tableName); } // Create the Permissions. $this->load->model('permissions/permission_model'); $permissionNames = array(); foreach ($this->permissionValues as $permissionValue) { $this->permission_model->insert($permissionValue); $permissionNames[] = $permissionValue['name']; } // Assign them to the permitted roles. $this->load->model('role_permission_model'); foreach ($this->permittedRoles as $permittedRole) { foreach ($permissionNames as $permissionName) { $this->role_permission_model->assign_to_role($permittedRole, $permissionName); } } } /** * Remove the blog tables * * @return void */ public function down() { // Remove the data. $this->load->dbforge(); foreach ($this->tables as $tableName => $tableDef) { $this->dbforge->drop_table($tableName); } // Remove the permissions. $this->load->model('roles/role_permission_model'); $this->load->model('permissions/permission_model'); $permissionKey = $this->permission_model->get_key(); foreach ($this->permissionValues as $permissionValue) { $permission = $this->permission_model->select($permissionKey) ->find_by('name', $permissionValue['name']); if ($permission) { // permission_model's delete method calls the role_permission_model's // delete_for_permission method. $this->permission_model->delete($permission->{$permissionKey}); } } } } The up() method is run when this migration is ‘installed’. The down() method is run when the migration is ‘un-installed’. We use CodeIgniter’s dbforge class here to create the table, but you could use the database class to run raw queries, if you wanted to. We also load up the permission_model and role_permission_model and create new permissions, then assign the permissions to the admin role so you can actually see the blog page in the Content menu. To install this migration, navigate to Developer / Database / Migrations. Click on the Modules tab. You will see the Blog module there. Select the 001_Initial_tables from the dropdown, and click ‘Migrate Module’. Your up() method will run, installing the posts table into your database. Until we create the controller, though, it will not show up in the menu. Content Context In order to manage your blog, you will create a new entry under the Content menu that takes you to all of the blog management features. To get started you will need one controller and one view. Create a new controller, blog/controllers/content.php. Each context uses a controller of the same name. In this case we want to create some actions for the Content Context, so we create a file named content.php. <?php defined('BASEPATH') || exit('No direct script access allowed'); class Content extends Admin_Controller { /** * Basic constructor. Calls the Admin_Controller's constructor, then sets * the toolbar title displayed on the admin/content/blog page. * * @return void */ public function __construct() { parent::__construct(); Template::set('toolbar_title', 'Manage Your Blog'); } /** * The default page for this context. * * @return void */ public function index() { Template::render(); } } Notice that the class is named the same as the Context and it extends Admin_Controller. The Admin_Controller is one of several controllers provided by Bonfire to take care of a few functions for you. In this case, the controller ensures the user is logged in, sets up pagination defaults, sets the theme to the admin theme, and loads the form_validation library. In the __construct() method we are doing one thing currently, setting the text that shows up in the sub-navigation bar just below the main menu in the admin area. We’ll make more use of this bar in the future. The index() method is the method that will be called by default when you click on the Blog menu item. We use the Template library’s render() method to display the view for this page. By default, this will look for a view in the module’s views folder under the context name and method name. In this case, it would be searching for blog/views/content/index.php. Create that file now. <h1>Blog Index</h1> We are keeping it simple just to make sure everything is in working order for now. Save the files, then navigate to http://yoursite.com/admin/content/blog to view your new page. You can also refresh the screen now, and a link will show up in the Content menu that you can use. The Blog Model In order to view any posts, we will need to create a model that interacts with the database for us. Thanks to Bonfire’s MY_Model base class, this is a very simple task. Create a new model file at blog/models/post_model.php. <?php defined('BASEPATH') || exit('No direct script access allowed'); class Post_model extends MY_Model { protected $table_name = 'posts'; protected $key = 'post_id'; protected $set_created = true; protected $set_modified = true; protected $soft_deletes = true; protected $date_format = 'datetime'; } This is everything needed to get some pretty flexible CRUD setup and running for your post model. There are a lot more options available in the full model file but this is all we need for now. $table_name is the name of the database table in which the data is stored. $key is the name of the table’s primary key. $set_created tells the system whether it should automatically store the date/time the object was created. In order for this to work, you must have a created_on field in your table. $set_modified tells the system whether it should automatically store the date/time the object was last modified. In order for this to work, you must have a modified_on field in your table. $soft_deletes tells the system whether a delete function should permanently delete the row (a ‘hard’ delete), or simply set a deleted flag in the table. This requires that you have a deleted tinyint(1) field in your table. $date_format specifies the format used for the $set_modified and $set_created fields. With the settings above, our post_model will: Store our data in the posts table in our database. Each row will have a primary key called post_id. Store the date the row was created in the created_on field. Store the date the row was last modified in the modified_on field. Set the deleted field to 1 when a row is deleted, instead of permanently removing it. Since the post_model will be used in nearly every method in our content controller, we will autoload it in the controller’s __construct() method. public function __construct() { parent::__construct(); $this->load->model('post_model'); Template::set('toolbar_title', 'Manage Your Blog'); } Listing Posts in Admin It’s now time to expand our blog’s content index method to display a list of all posts in the system. Add the following lines to the index() method of the content controller, before the Template::render() method. $posts = $this->post_model->where('deleted', 0)->find_all(); Template::set('posts', $posts); This calls the post_model’s find_all() method to retrieve all posts in the system. However, we don’t want any deleted posts, so we filter those out with the where() method. We then use the Template class’ set() method to make the data available to our view. In the view, this can be accessed as the $posts variable. Edit the index.php view file to reflect the following: <div class="admin-box"> <h3>Blog Posts</h3> <?php if (empty($posts) || ! is_array($posts)) : ?> <div class="alert alert-warning"> No Posts found. </div> <?php else : $numColumns = 2; $canDelete = $this->auth->has_permission('Bonfire.Blog.Delete')); if ($canDelete) { ++$numColumns; } echo form_open(); ?> <table class="table table-striped"> <thead> <tr> <?php if ($canDelete) : ?> <th class="column-check"><input class="check-all" type="checkbox" /></th> <?php endif; ?> <th>Title</th> <th>Date</th> </tr> </thead> <?php if ($canDelete) : ?> <tfoot> <tr> <td colspan="<?php echo $numColumns; ?>"> <?php echo lang('bf_with_selected') . ' '; ?> <input type="submit" name="delete" class="btn" value="<?php echo lang('bf_action_delete'); ?>" onclick="return confirm('Are you sure you want to delete these posts?')" /> </td> </tr> </tfoot> <?php endif; ?> <tbody> <?php foreach ($posts as $post) : ?> <tr> <?php if ($canDelete) : ?> <td><input type="checkbox" name="checked[]" value="<?php echo $post->post_id; ?>" /></td> <?php endif; ?> <td> <a href="<?php echo site_url(SITE_AREA . "/content/blog/edit_post/{$post->post_id}"); ?>"> <?php e($post->title); ?> </a> </td> <td> <?php echo date('M j, Y g:ia'); ?> </td> </tr> <?php endforeach; ?> </tbody> </table> <?php echo form_close(); endif; ?> </div> This creates a table that will list each blog post, if any exist. If they don’t then a notice will be displayed. Most of this should be self-explanatory, but there is one new function nestled in there, e(). This method is a convenience method that you should consider using wherever you are displaying user-entered data. It simply echos out the string, using the htmlentities() function to help protect against XSS and CSRF attacks. To handle the delete button included in this table, the content controller needs some modifications. First, the index() method needs to be updated to check for the delete button: public function index() { if (isset($_POST['delete'])) { $this->deletePosts($this->input->post('checked')); } // Finished handling the post, now display the list $posts = $this->post_model->where('deleted', 0)->find_all(); Template::set('posts', $posts); Template::render(); } Then we need to add the deletePosts() method to loop through the list of post IDs and delete the records: public function deletePosts($postIds) { // If no posts were selected, display an error message. if (empty($postIds) || ! is_array($postIds)) { Template::set_message('You have not selected any records to delete.', 'error'); return false; } // Only allow users with the correct permission to delete posts $this->auth->restrict('Bonfire.Blog.Delete'); // Track any failures while deleting the selected posts. $failed = 0; foreach ($postIds as $postId) { $result = $this->post_model->delete($postId); if (! $result) { ++$failed; } } $result = false; if ($failed) { Template::set_message("There was a problem deleting {$failed} post(s): {$this->post_model->error}", 'error'); } else { Template::set_message('Deleted ' . count($postIds) . ' post(s)', 'success'); $result = true; } // if any tickets were deleted, log the activity. if ((count($postIds) - $failed) > 0) { log_activity( $this->auth->user_id(), 'Deleted ' . count($postIds) . ' post(s) : ' . $this->input->ip_address(), 'blog' ); } return $result; } Module Sub-Menus Now we just need a way to create new posts. Let’s start by creating a new sub-menu that allows us to access other pages. This is not intended for long menus, but to provide a short list of major areas within your module. You will see this used throughout Bonfire, and it appears on the right side of the page, just under the main menu. This is the same bar that holds your $toolbar_title. First, we create a view file holds the menu itself. Create a new file at blog/views/content/sub_nav.php. <ul class="nav nav-pills"> <li <?php echo $this->uri->segment(4) == '' ? 'class="active"' : '' ?>> <a href="<?php echo site_url(SITE_AREA .'/content/blog') ?>">Posts</a> </li> <li <?php echo $this->uri->segment(4) == 'create' ? 'class="active"' : '' ?>> <a href="<?php echo site_url(SITE_AREA .'/content/blog/create') ?>">New Post</a> </li> </ul> Each link in this list will take us to a method within our content controller. We also check the url to see if this is an active link or not. To make this menu show up, we need to add it to our content controller’s __construct() method. public function __construct() { parent::__construct(); $this->load->model('post_model'); Template::set('toolbar_title', 'Manage Your Blog'); Template::set_block('sub_nav', 'content/sub_nav'); } Reload your page in the admin area, and you will see the new menu appear. Clicking on ‘New Post’ throws an error since we haven’t created that method yet. We will do that next. Create A Post We will start things simple by just displaying the form to create a new post, then deal with saving the post later. Create a new create() method in your content controller. public function create() { Template::set('toolbar_title', 'Create New Post'); Template::set_view('content/post_form'); Template::render(); } This sets the toolbar_title of the page, says that we want to use the view named views/content/post_form.php, and renders the form. Now we need create the form itself. We’re using a file called post_form because we want to be able to use the form for both the create and edit pages. <div class="admin-box"> <h3>New Post</h3> <?php echo form_open(current_url(), 'class="form-horizontal"'); ?> <fieldset> <div class="control-group<?php echo form_error('title') ? ' error' : ''; ?>"> <label for="title">Title</label> <div class="controls"> <input type="text" name="title" id="title" class="input-xxlarge" value="<?php echo isset($post) ? $post->title : set_value('title'); ?>" /> <span class='help-inline'><?php echo form_error('title'); ?></span> </div> </div> <div class="control-group<?php echo form_error('slug') ? ' error' : ''; ?>"> <label for="slug">Slug</label> <div class="controls"> <div class="input-prepend"> <span class="add-on"><?php echo site_url() . '/blog/'; ?></span> <input type="text" name="slug" id="slug" class="input-xlarge" value="<?php echo isset($post) ? $post->slug : set_value('slug'); ?>" /> </div> <span class="help-inline"><?php echo form_error('slug'); ?></span> <p class="help-block">The unique URL that this post can be viewed at.</p> </div> </div> <div class="control-group<?php echo form_error('body') ? ' error' : ''; ?>"> <label for="body">Content</label> <div class="controls"> <span class="help-inline"><?php echo form_error('body'); ?></span> <textarea name="body" id="body" class="input-xxlarge" rows="15"><?php echo isset($post) ? $post->body : set_value('body'); ?></textarea> </div> </div> </fieldset> <fieldset class="form-actions"> <input type="submit" name="submit" class="btn btn-primary" value="Save Post" /> <?php echo ' ' . lang('bf_or') . ' '; ?> <a href="<?php echo site_url(SITE_AREA . '/content/blog'); ?>">Cancel</a> </fieldset> <?php echo form_close(); ?> </div> Most of this is straight-forward. I do want to point out that for the values, we are checking whether a $post value is set or not, and then uses the form helper’s set_value() method to set the value in the case of errors on the form. We also use the form_validation library’s form_error() function to setup individual errors for each field. Saving the Post Now, let’s make it functional. In your post_model, we need to let it know what validation rules to use during both inserts or updates. Add the following class variable to the post_model: protected $validation_rules = array( array( 'field' => 'title', 'label' => 'Title', 'rules' => 'trim|strip_tags' ), array( 'field' => 'slug', 'label' => 'Slug', 'rules' => 'trim|strip_tags' ), array( 'field' => 'body', 'label' => 'Body', 'rules' => 'trim|strip_tags' ) ); These rules follow the same format as the form validation library. The one thing to be aware of is that these rules are used for both inserts and updates. This can cause a problem with required fields on inserts. We’ll add the insert_validation_rules class variable to the post_model to provide any additional rules we want applied during an insert only. protected $insert_validation_rules = array( 'title' => 'required', 'body' => 'required' ); Now, whenever you do an insert or an update, the data is run through the form validation library. If it fails validation, the model will return FALSE and your controller can respond accordingly. Next, modify the controller’s create() method to actually save the data: public function create() { if ($this->input->post('submit')) { $data = array( 'title' => $this->input->post('title'), 'slug' => $this->input->post('slug'), 'body' => $this->input->post('body') ); if ($this->post_model->insert($data)) { Template::set_message('Your post was successfully saved.', 'success'); redirect(SITE_AREA .'/content/blog'); } } Template::set('toolbar_title', 'Create New Post'); Template::set_view('content/post_form'); Template::render(); } Editing Posts Editing our posts is very simple to do now. Simply add the following edit_post() method to your controller and you’re up and running: public function edit_post($id = null) { if ($this->input->post('submit')) { $data = array( 'title' => $this->input->post('title'), 'slug' => $this->input->post('slug'), 'body' => $this->input->post('body') ); if ($this->post_model->update($id, $data)) { Template::set_message('You post was successfully saved.', 'success'); redirect(SITE_AREA .'/content/blog'); } } Template::set('post', $this->post_model->find($id)); Template::set('toolbar_title', 'Edit Post'); Template::set_view('content/post_form'); Template::render(); } The Public Context Now that we have basic administration pages in place, it’s time to actually let the users view your awesome blog posts. This requires that we create a new controller, in the same blog module, called blog. This will handle what we call your Public Context and is simply a front-facing controller that will directly map to the URI. In this case, you can view this controller at http://yoursite.com/blog. Create a new file, modules/blog/controllers/blog.php <?php class Blog extends Front_Controller { public function __construct() { parent::__construct(); $this->load->model('post_model'); } public function index() { $this->load->helper('typography'); $posts = $this->post_model->order_by('created_on', 'asc') ->limit(5) ->find_all(); Template::set('posts', $posts); Template::render(); } } This is just a typical CodeIgniter controller, which means that anything you can do in straight CodeIgniter, you can do here. In this case, we’re loading our model in the constructor, since we know that we’ll be using it in every method. Then we create an index method to list the 5 most recent posts. Then, it looks for a view file at blog/views/index.php. Create that file now. <?php if (! empty($posts) && is_array($posts)) : foreach ($posts as $post) : ?> <div class="post"> <h2><?php e($post->title); ?></h2> <?php echo auto_typography($post->body); ?> </div> <?php endforeach; else : ?> <div class="alert alert-info"> No Posts were found. </div> <?php endif; This is a very simple view, but should be enough to give you an understanding. Navigate to http://yoursite.com/index.php/blog and you should see the 5 most recent blog posts for you. Conclusion If this were a real application, there would be much left to add, but this is enough to get you started. At this point, you should have enough understanding of how to create modules and code for Bonfire to get you well on your way to creating the next killer app. [阅读]

Template_parser

Template_parser

The Template Parser Bonfire ships with a powerful template parser called Lex, which was originally devleoper by Dan Horrigan and then taken over and maintained by the PyroCMS team. Enabling the Parser The parser can be enabled by setting the parse_views option of the Template library to TRUE. Template::$parse_views = TRUE; Now all views will be rendered using the template parser. Lex does allow for PHP to be parsed within the layouts at the same time as the Lex tags so you can keep the parser turned on at all times without any issues. Tag Basics To display data in Lex, you must use a tag. Tags are variables that are wrapped in double curly braces. Note that whitespace before or after the braces does not matter, though more advanced uses will require whitespace. To provide data for your tags, use the Template::set(); method. // In the controller Template::set('name', 'Bonfire'); // In the View // Display: Bonfire You can access elements of an array within a tag by using a period (.) and the array key name. // In the controller $user = array( 'name' = 'Darth Vader' ); Template::set('user', $user); // In the View Your name is . Looping Tags When tags contain an array of data, like blog posts, you can loop through the data by using opening and closing tags. Any array values will then be accessible by their key name. // In the controller $posts = array( array( 'title' => 'Post 1', 'url' => 'blog/post-1' ), array( 'title' => 'Post 2', 'url' => 'blog/post-2' ) ); Template::set('posts', $posts); // In the view <h1><a href=""></a></h1> Conditional Tags Conditionals in Lex are simple and easy to use, allowing for the standard if, elseif and else. It also adds unless and elseunless. unless and elseunless are the EXACT same as using and respectively. <p>My name is .</p> <p>You are admin!</p> <p>You are a normal user.</p> <p>I don't know what you are.</p> Undefined variables in conditionals are translated to NULL. This means you can do things like and not worry about whether it exists or not. Modules, Libraries and Templates The most useful part of using the template library is that we can can module methods and library methods directly from our views. This is done by calling the module name followed by a colon and the name of the method. <li> - - </li> Calling modules is still in its infancy and you might run into a few issues, but here are some guidelines to follow: Only use a controller that extends from CI_Controller and perform any additional validation and security checks, loading libraries, etc, as normal. The controller should be of the same name as the module. The names of the parameters within the tag don’t matter. They are mostly useful for you to remember what parameter is what. The values must be passed in the same order that the method requires them. Full Docs These documentations are just to get your feet wet in using the template parser in your projects. For full documentation, see the Lex GitHub site. [阅读]

Template

Template

Template Bonfire includes a Template library which makes it easier to build pages for a website based on layouts and partial views. Additional information about using the Template library may be found in Layouts and Views. Configuration The Template library can be configured by setting several values in /application/config/application.php. template.site_path The path to the root folder that holds the application. This does not have to be the site root folder, or even the folder defined in FCPATH. $config['template.site_path'] = FCPATH; template.theme_paths An array of folders to look in for themes. There must be at least one folder path at all times, to serve as the fall-back for when a theme isn’t found. Paths are relative to the template.site_path. $config['template.theme_paths'] = array('themes'); template.default_layout This is the name of the default layout used if no others are specified. NOTE: do not include an ending “.php” extension. $config['template.default_layout'] = "index"; template.ajax_layout This is the name of the default layout used when the page is displayed via an AJAX call. NOTE: do not include an ending “.php” extension. $config['template.ajax_layout'] = 'ajax'; template.use_mobile_themes When set to true, the Template library will check the user agent during the rendering process against the template.themes, allowing you to create mobile versions of your site, and versions targetted specifically at a single type of phone (ie, Blackberry or iPhone). NOTE: when rendering, if the file doesn’t exist in the targetted theme, the Template library then checks the default site for the same file. $config['template.use_mobile_themes'] = false; template.default_theme This is the folder name that contains the default theme to use when searching for a view in your site’s themes. $config['template.default_theme'] = 'default/'; template.admin_theme This is the folder name that contains the default theme to use for the site’s admin area (SITE_AREA). $config['template.admin_theme'] = 'admin'; template.message_template This is the template that the Template library will use when displaying messages through the message() function. To set the class for the type of message (error, success, etc), the {type} placeholder will be replaced. The message will replace the {message} placeholder. $config['template.message_template'] =<<<EOD <div class="alert alert-block alert-{type} fade in notification"> <a data-dismiss="alert" class="close" href="#">&times;</a> <div>{message}</div> </div> EOD; template.breadcrumb_symbol Breadcrumb separator, the symbol displayed between the breadcrumb elements. $config['template.breadcrumb_symbol'] = ' : '; template.parse_views If set to true, views will be parsed via CodeIgniter’s parser. If false, views will be considered PHP views only. $config['template.parse_views'] = false; Methods add_theme_path($path) Add a theme path ($path) to the list of paths to be used when searching for themed views. block($block_name[, $default_view[, $data[, $themed]]]) Places a named block in the layout/view which acts as an insertion point for a view. This is ideal for setting locations for recurring elements within a site’s layout, such as sidebars, headers, footers, etc. $block_name is the name used to reference this block, especially when calling set_block() to change/set the view. If $default_view is set to the path/name of an existing view, the view will be used if no other view is set (by calling set_block()). $data may be set to pass an array of data to the view rendered in the block. $themed: If true, the view will be loaded from the current theme, if possible. If false (default), the view will be loaded from the standard view locations. content() Specifies the area in the layout into which the current view will be rendered. Returns a string containing the output of the render process for the view. get($var_name) Returns the value of a variable which has been previously set, or false if the variable does not exist. getLayout() Returns the layout into which views will be rendered. init() Used to initialize the Template library after it is loaded by CodeIgniter. Not intended for external use, despite being a public method. load_view($view, $data = null, $override = ‘’, $is_themed = true, &$output) Load a view from the current theme. - $view the name of the view to load. - $data An optional array of data elements to be made available to the views. Array keys will be the variable names used to access the values in the view. - $override An optional string containing the name of a view to override $view, if available. - $is_themed An optional boolean value (defaults to true) to determine whether themes are checked when attempting to locate a view. - &$output A reference to a variable to store the output of the loaded view. message([$message[, $type]]) Displays a status message. - If $message is not included, displays a message set previously via either set_message() or session->flashdata('message'). Otherwise, displays $message. - $type is the type of message (defaults to 'information'), usually added as a value of the class attribute on the message’s container. This value is only used if not already set on the message to be displayed. parse_views([$parse]) Sets the $parse_views property, which controls whether views will be parsed by CI’s Parser. - If $parse is true, the views will be parsed. - If false (default), they will not be parsed by CI’s Parser. redirect([$url]) Performs a redirect, similar to CodeIgniter’s redirect(), but, if it detects that this is in response to an AJAX request, it will inject a JavaScript redirect into the response. - $url is an optional URL to which the user will be redirected. If omitted, it will be set to the site’s base URL. render([$layout]) Starts the process of rendering the page content and determines the correct view to use based on the current controller/method. Optionally, $layout may be set to the path/name of a layout to use instead of the current layout. This method is usually called in the last line of most controller actions/methods (except when those methods return data for use by another controller or in response to an AJAX call). set($var_name[, $value]) Set a value or an array of values to be provided to the view(s) in the content area. $var_name can be an array of key/value pairs (with the key being the variable name to be used in the view), in which case $value should be omitted. If $var_name is a string, it will be interpreted as the name of a variable to be set to $value in the view. setLayout($layout) Specify the layout into which the views will be rendered. Allows overriding the default layout. This is especially useful to set a default layout for a controller which overrides the default layout of the application. set_block($block_name[, $view_name]) This method is used to override the default view (or set a view if no default was provided) in a named block. - $block_name must match the value passed in the first parameter of the block() method. The name of the block. - $view_name is the path/name of the view to render in the block. set_default_theme($theme) Set the default theme ($theme) to use in case a view is not found in the active theme. This theme should be relative to one of the current theme paths. set_message($message[, $type]) Sets a status message (primarily intended for displaying small success/error messages). This function is used in place of session->flashdata to allow the message to show up without requiring a page refresh. $message is the text of the message. $type is the type of message (defaults to 'info'), usually added as a value of the class attribute on the message’s container. set_theme($theme[, $default_theme]) Set the name of the active theme ($theme). This theme should be relative to one of the current theme paths. The optional $default_theme allows you to also set a default theme to use in case a view is not found in the active theme. set_view($view) Sets the view to be rendered in the content block. setSessionUse($useSession = true) Enable/disable the library’s use of sessions. This is primarily used by the installer (when sessions are not likely to be available), but is also useful for testing. If $useSession is true, the library will use sesssions; if false, the library will not use sessions. theme() Returns the name of the active theme. theme_url([$resource]) Returns the full URL to the currently active theme. If $resource is supplied, returns the full URL to that resource within the currently active theme (does not validate the existence of the resource within the theme). themeView($view[, $data = null[, $ignore_mobile = false]]) Set an insertion point for a view ($view) within a view. - $view: The name of the view to be rendered. - $data: An array of data to be passed to the view. - $ignore_mobile: - If true, the library will not attempt to find a version of this view named for mobile devices (prefixed with mobile_). - If false (default), the library will attempt to find a version of this view named for mobile devices when it detects that the page is being accessed from a mobile device. remove_theme_path($path) Remove a theme path ($path) from the list of paths to be used when searching for themed views. Helper Functions Helper functions are not methods of the Template library (so they are called without using the Template:: prefix). They are included automatically when loading the Template library. breadcrumb([$my_segments[, $wrap = false[, $echo = true]]]) Creates a breadcrumb from either uri->segments or a key/value paired array passed via $my_segments. - If $wrap is true, the breadcrumbs will be wrapped in an un-ordered list (default is false). - If $echo is true (default), the output is sent to echo, if false, the output will be returned. check_class($item[, $class_only = false]) If the current class/controller name matches $item (in a case-insensitive comparison), this function returns 'class="active"' if $class_only is false (default) or 'active' if $class_only is true. If $item does not match, an empty string is returned. This (and the other check_* helper functions in the Template library) is intended primarily for use in menus and other areas of the page to help indicate the active page or active site area, especially when using blocks to display a single view for a portion of the layout displayed on multiple pages. check_method($item[, $class_only = false]) If the current method (controller action) matches $item, this function returns 'class="active"' if $class_only is false (default) or 'active' if $class_only is true. If $item does not match, an empty string is returned. check_segment($segment_num, $item[, $class_only = false]) Checks the value of $item against the value of the specified URI segment ($segment_num). If they match, the function returns 'class="active"' if $class_only is false (default) or 'active' if $class_only is true. If $item does not match, an empty string is returned. theme_view($view[, $data = null[, $ignore_mobile = false]]) Set an insertion point for a view ($view) within a view. A helper function for Template::themeView(). Properties $blocks An array of named blocks and the path/filename of the view for each block. $debug A boolean value which controls the library’s output of debug messages. $ignore_session Deprecated A boolean value which disables the library’s use of sessions, primarily for unit testing. Use setSessionUse() instead. Note that setSessionUse() expects the opposite value of $ignore_session, so setSessionUse(false) is equivalent to setting $ignore_session = true. $layout Deprecated The layout into which views will be rendered. Use getLayout() and setLayout() instead. $parse_views A boolean value which determines whether CI’s Parser will be used to parse the views. $site_path The full server path to the site root. Events after_layout_render Events::trigger('after_layout_render', $output); Triggered near the end of the render() method, before calling output->set_output($output). after_page_render Events::trigger('after_page_render', $output); Triggered near the end of the content() method, before returning $output. [阅读]

System_events

System_events

System Events? Event hooks allow you to integrate your custom programming into various places of Bonfire’s execution, without having to modify the core code. Because this is aimed squarely at the developer, and not the end user, there is no GUI to manage this functionality. Instead, registering events is done by modifying a config file. Why Not Use Hooks? CodeIgniter’s hooks are a great feature, but they don’t always provide enough flexibility. There is no documentation on how to create your own hooks (though it’s not that tough), and it lacks the ability to pass any dynamic parameters to the hook. For a modular system like Bonfire, hooks don’t provide any transparent method to support multiple modules. That’s what System Events aim to solve. Extending The Core Bonfire’s core provides a number of hooks integrated into the system that you can tap into to modify the behavior or data without modifying the core code itself. You tell Bonfire that you want to respond to certain events by creating a class/method and editing the config/events.php file with the name of the hook and the information where to find the code to run. The code can live in any module’s library or controller that you choose. 2.1 Registering An Event To take an action whenever a new user is created in the system, like creating some new data specific to your module, you would first create a method in your class’ controller to handle this. For this example, we have chosen to add a setup_defaults() method in our my_module controller, but it could have been in a library just as easily. php public function setup_defaults($user_id) { ... } We know that the payload the event provides is the id of the user, so we capture that in the first parameter. At this point, we could use the user_model to retrieve the user, or save some new settings just for this user, etc. The next step is to register our event in the configuration file. Open up application/config/events.php and add a new $config array. php $config['after_create_user'][] = array( 'module' => 'my_module', 'filepath' => 'controllers', 'filename' => 'my_module.php', 'class' => 'My_module', 'method' => 'setup_defaults' ); The following parameters are all required within the config array: module - The name of the module to find it it. Must be the same as the folder name of the module. filepath - The path to the file within the module’s folder. This allows you to use any controller, library, or helper file for your event. filename - The name of the file to load. Must include the file extension. class -The name of the class to create an instance of. method - The name of the method within the class to call. Most system events will deliver a payload. This will typically be an array of data that the event allows you to operate on. Each payload will be described in the event descriptions below. Core Events The following table lists all events within the core of Bonfire that are available for you to access. Controllers Event Description before_controller Called prior to the controller constructor being ran. Payload is the name of the current controller. after_controller_constructor Called just after the controller constructor is ran, but prior to the method being ran. Payload is the name of the current controller. Templates and Pages Event Descrpription after_page_render Called just after the main view is rendered. Payload is the view’s output. after_layout_render Called just after the entire page is rendered. Payload is the current output. after_block_render Called just after the block is rendered. Payload is an array with ‘block’ being the name of the block and ‘output’ being the rendered block’s output. Users Event Description after_login Called after successful login. Payload is an array of user_id and role_id. before_logout Called just before logging the user out. Payload is an array of user_id and role_id. after_create_user Called after a user is created. Payload is the new user’s id. before_user_update Called just prior to updating a user. Payload is an array of user_id and ‘data’, where data is all of the update information passed into the method. Note: user_id may be an array if the user_model’s update() method is called with an array as the first parameter. In this case, the user’s ID may not be in the array… after_user_update Called just after updating a user. Payload is an array of user_id and ‘data’, where data is all of the update information passed into the method. Note: user_id may be an array if the user_model’s update() method is called with an array as the first parameter. In this case, the user’s ID may not be in the array… Using Events In Your Modules You can use events in your own modules to provide places for other modules to hook into. It is very simple and only requires that you use a single line of code in your library, model, or controller wherever you would like the hook to fire. php Events::trigger('event_name', $payload); The function takes two parameters. The first parameter is the name of the event to call. You may use any name that you want, so long as it doesn’t conflict with an existing event name. To avoid collisions, it is recommended that you prefix your event name with the name of your module, like forums.after_comment. The second parameter is a single variable that contains the payload that you wish to provide to the event responders. This could be an ID, an array with multiple pieces of data, or anything else that is appropriate to your needs. [阅读]

Site_structure

Site_structure

Site Structure Bonfire’s site is structured with three goals in mind: keep as much of Bonfire out of the application folder as possible, so you can keep Bonfire up to date without overwriting your application’s code keep as much of your code (and ours) outside of the web root as possible for added security help you keep your project organized amid the pressures of everyday development. Hopefully, this page will give you an idea of the reasoning and purpose behind the structure. Folder Structure application/ archives/ cache/ config/ controllers/ core/ db/ backups/ migrations/ docs/ errors/ helpers/ hooks/ language/ libraries/ logs/ models/ modules/ third_party/ MX/ Sparks_Loader.php views/ bonfire/ codeigniter/ controllers/ core/ docs/ helpers/ libraries/ migrations/ modules/ public/ assets/ cache/ css/ images/ js/ index.php themes/ admin/ default/ docs/ tests/ _support/ application/ bonfire/ simpletest/ tools/ lib/ spark/ spark_types/ spark Application The application folder is where you will do most of your work. This contains all of your controllers, libraries, helpers, models, and any modules you might use. As much as possible, Bonfire stays away from this folder. However, there are a few files that we cannot move out of the application folder due to restrictions in either CodeIgniter or the HMVC solution that we use. Most of these files are located in the application/third_party folder or the application/core folder. The application/third_party folder contains Sparks_Loader.php for sparks support and the bulk of the HMVC solution, located in the application/third_party/MX folder. While it is best to stay away from the *_Controller.php files in the application/core folder (you can create your own controllers in this folder to extend them), the MY_Model.php file is intended to be modified as you see fit. Most of the folders within the application folder are the standard CodeIgniter folders you would expect. There are a few new ones that Bonfire adds. DB folder The db folder stores two things: backups contains any backups created using the built-in Database Backup funtionality migrations holds the migration files specific to your application Modules folder This folder is where you should create all of your own modules. It is also where Bonfire creates module-related files for you. Each module should have a folder with its own unique name here. It is also possible to override portions of Bonfire’s core modules by adding files here, following the folder/file names in the Bonfire module you wish to override. Bonfire The bonfire folder holds Bonfire, itself, as well as the codeigniter system files. codeigniter houses the CodeIgniter system files controllers contains Bonfire’s custom controllers for images and the installer core holds Bonfire’s overrides for HMVC and custom routing functionality docs you are here… helpers has additional helper files that Bonfire provides for extra functionality, including extensions of CodeIgniter helpers libraries Bonfire’s libraries, like the Assets and Template libraries, including extensions of CodeIgniter libraries migrations migration files specific to the core of Bonfire only, these are typically run during installation and when updating the Bonfire core modules all of Bonfire’s core modules are stored here, to keep them separate from your modules (and make upgrading a bit simpler) Public This folder is where you should point your domain name to. It holds the files and folders that should be accessible from the web. assets a place to put all of your scripts, images, and styles that can be used site-wide. themes holds the admin, docs, and default (front-end) themes. Also where you should put your own themes. Reverting To Traditional Structure In some situations, you may prefer a more traditional folder structure that has all of the files and folders located in the web root. This might be due to restrictions on shared hosting, or becuase you prefer easier installation for your customers. This can be easily done by moving the files and folders from the public folder into the same folder as the others, overwriting the root index.php with the public/index.php file. This would leave a folder structure like: application/ assets/ bonfire/ index.php tests/ themes/ After you’ve moved the files, you need to edit the main index.php file to let CodeIgniter know where to find the application and system folders. $path = '.' Changing this variable will set all of the other paths. [阅读]

Routes

Routes

Improved Routes The addition of Packages in CodeIgniter 2.x branch was a welcome improvement, but did not go far enough. It only allowed for shared code, not Routing support. True support of modules is necessary to help developers with code sharing and to help build up the community once again. In addition, CodeIgniter’s Router is showing it’s age against the powerful solutions found in other PHP frameworks like Laravel. Bonfire’s Routing is meant to help bring CodeIgniter into the modern age, or at least help it take a step in that direction. CodeIgniter Mods This is one area where we have decided that modifying the core of CodeIgniter is allowed. We’ve completely overridden the core Loader and Router classes with our own strange combination of WireDesignz’ HMVC code and jenssegers’ HMVC code and tweaked it to allow loading core files from the bonfire folder and more. Route Library The Route library is the core of the new flexibility. It is inspired by Jamie Rumbelow’s excellent Pigeon class, as well as Laravel’s routing system. HTTP Verb Routing To make building REST-based routing simpler and more consistent, you can use the Route::resources('controller_name'); This function will automatically create RESTful resources for the common HTTP verbs. In this example, controller_name is the name of the controller you want to map the resources to. If you controller is named photos, you would call it like: Route::resources('photos'); If the photos controller is part of the Gallery module, then you would route it like: Route::resources('gallery/photos'); This would map the resources to the Photos controller, like: HTTP Verb Path action used_for GET /photos index display a list of photos GET /photos/new create_new return an HTML form for creating a new photo POST /photos create create a new photo GET /photos/{id} show display a specific photo GET /photos/{id}/edit edit return the HTML for editing a single photo PUT /photos/{id} update update a specific photo DELETE /photos/{id} destroy delete a specific photo You can also set a single verb-based routes with any of the route methods: Route::get('from', 'to'); Route::post('from', 'to'); Route::put('from', 'to'); Route::delete('from', 'to'); Route::head('from', 'to'); Route::patch('from', 'to'); Route::options('from', 'to'); These routes will then only be available when the corresponding HTTP verb is used to initiate the call. Customizing Resourceful Routes While the standard naming convention provided by the resources Route method will often serve you well, you may find that you need to customize the route to easily control where your URL’s route to. Specifying a controller to use You can pass an array of options into the resources method as the second parameter. By specifying a controller key, you will tell the router to replace all instances of the original route with the defined controller, like: Route::resources('photos', array('controller' => 'images')); Will recognize incoming paths beginning with /photos but will route to the images controller: Specifying the module to use You can also specify a module to use in the options array by passing a module key. This is helpful when the module and controller share different names. Route::resources('photos', array('module' => 'gallery', 'controller' => 'images')); Will recognize incoming paths beginning with /photos but will route to the gallery/images module and controller. Constraining the {id} format By default, the {id} used in the routing allows any letter, lower- or upper-case, any digit (0-9), a dash (-) and an underscore(_). If you need to restrict the {id} to another format, you may use the constraint option to pass a new, valid, format string: Route::resources('photos', array('constraint' => '(:num)')); Would restrict the {id} to be only numerals, while: Route:resources('photos', array('constraint' => '([A-Z][A-Z][0-9]+)')); would restrict the {id} to be something like RR27. Offsetting Parameters By default, the resulting parameters in the $to portion of the route will start at $1. In most cases this is what you want. However, there may be times where you need to change that and offset the value in some form or another. This is most often see when dealing with an API version number in the URL that you’re fixing manually later in the routes config file, or when taking out a language string from the URL. In these cases, you would be removing $1 from the routes and would need the parameters to start at $2 instead. You can do this by passing ‘offset’ in the options array with a value matching the number you need to offset. Route::resources('photos', array('offset' => 1)); Blocking Routes You might find times where you need to block access to one or more routes. For example, you might have relocated the default user login page so that script-kiddies couldn’t find your page by assuming it’s a Bonfire site and would be at a normal location. In this case, you would want to block any access to /users/login, which would normally work just fine. In this case you can use the block() method to block as many routes as you’d like. Route::block('users/login', 'photos/(:num)'); // The same as: $route['users/login'] = ''; $route['photos/(:num)'] = ''; Route Prefixing There are times when you’ll want to group a disparate set of routes under a single section. You can use route prefixing for this. Route::prefix('api', function() { Route::all('users', 'users/index'); Route::get('photos', 'photos/show'); }); Would be equivalent to the following routes: $route['api/users'] = 'users/index'; $route['api/photos'] = 'photos/show'; Named Routes You can save routes with a name associated with them that makes it much easier and safer to call routes within your application. The provides a single name that you can always count on being the same that maps to the $from portion of the route. If you need to restructure your site, simply change the routing while keeping the name the same. Any place in your application that called that route will still work. This works with prefixing and all of the other flexbile routing the class provides. Route::prefix('area', function(){ Route::any('posts', 'posts/index', array('as' => 'blog')); }); redirect( Route::named('blog') ); Routing Contexts Contexts provide a way for modules to assign controllers to an area of the site based on the name of the controller. This can be used for making a /developer area of the site that all modules can create functionality into. This can be better explained with an example. We want to provide a collection of tools available under the /developer URL of our site. We have a number of modules, like a database manager, a code builder, etc, that all need to have easy access to that area. Instead of creating routes for each module, we’ll just create a general set of routes that will take any controller named ‘developer.php’ in any of our modules, and route it to developer/{module_name}/{method}. Route::context('developer'); If, we change our mind down the road and want to rename all of the URL’s to /tools instead of /developer, we can do that by passing in two parameters instead. The first is the name of route (tools in this case), and the second is the controller to map to. Route::context('tools', 'developer'); This creates a series of routes that map the parameters into the module. It’s a little hacky but works well for up to 5 parameters. If you need more than that, you might examine your application to see if you could use the routes differently or restructure your application. The equivalent CI routes would be: $route['tools/(:any)/(:any)/(:any)/(:any)/(:any)/(:any)'] = '$1/developer/$2/$3/$4/$5/$6'; $route['tools/(:any)/(:any)/(:any)/(:any)/(:any)'] = '$1/developer/$2/$3/$4/$5'; $route['tools/(:any)/(:any)/(:any)/(:any)'] = '$1/developer/$2/$3/$4'; $route['tools/(:any)/(:any)/(:any)'] = '$1/developer/$2/$3'; $route['tools/(:any)/(:any)'] = '$1/developer/$2'; $route['tools/(:any)'] = '$1/developer'; If you need to offset your parameter numbers for the above routes, you can pass on ‘offset’ key/value in your options array as the last parameter. Context Homes You can also have it create a ‘home’ controller that would handle the calls to ‘/developer’ all by itself. This will map to a controller outside of any modules, but in your application/controllers folder, under a new folder named after the context. The controller can be any name you wish, but can be made to match the name of the default_controller by using a {default_controller} tag. Route::context('developer', array('home' => 'some_controller')); // Creates... $route['developer'] = 'developer/some_controller'; // Maps to... application/controllers/developer/some_controller.php Route::context('developer', array('home' => '{default_controller}')); // Creates $route['developer'] = 'developer/welcome'; // Maps to application/controllers/developer/welcome.php [阅读]

Route

Route

Route Bonfire includes a Route library to supplement the functionality provided by CodeIgniter’s (and the Wiredesignz HMVC) router(s). Additional information may be available in the section on Improved Routes. Methods map([$routes]) Combines the routes which have been defined in the Route class with the passed $routes. This is intended to be used after all routes have been defined to merge CI’s default $route array with routes defined with this Route library. Note that in CI3 the 'translate_uri_dashes' setting should be set after calling this method. Example: $route['default_controller'] = 'home'; Route::resource('posts'); $route = Route::map($route); $routes is an array of routes to merge with the routes defined by the Route library. Usually, the variable passed into this method will be the CI $route array. If a ‘default_controller’ route is not set in the passed $routes, it will be set to 'home' (or whatever value is defined in the Route library’s protected $default_home property). Returns the merged array, which should be assigned to the CI $route array. any($from, $to[, $options[, $nested = false]]) Create a basic route. In its most basic form, this method will create a route similar to defining a CI route in the form $route[$from] = $to;. If the $options array contains a value in the 'as' key, the value will be used to configure a named route, allowing you to easily map names to pre-existing routes. $nested may be set to a callable function to define your own handler for this route. HTTP Verb-based routing get($from, $to[, $options[, $nested = false]]) Creates a route which will only be accessible when the $_SERVER['REQUEST_METHOD'] indicates that the current request is a GET request. The arguments match those in the any() method. post($from, $to[, $options[, $nested = false]]) Creates a route which will only be accessible when the $_SERVER['REQUEST_METHOD'] indicates that the current request is a POST request. The arguments match those in the any() method. put($from, $to[, $options[, $nested = false]]) Creates a route which will only be accessible when the $_SERVER['REQUEST_METHOD'] indicates that the current request is a PUT request. The arguments match those in the any() method. delete($from, $to[, $options[, $nested = false]]) Creates a route which will only be accessible when the $_SERVER['REQUEST_METHOD'] indicates that the current request is a DELETE request. The arguments match those in the any() method. head($from, $to[, $options[, $nested = false]]) Creates a route which will only be accessible when the $_SERVER['REQUEST_METHOD'] indicates that the current request is a HEAD request. The arguments match those in the any() method. patch($from, $to[, $options[, $nested = false]]) Creates a route which will only be accessible when the $_SERVER['REQUEST_METHOD'] indicates that the current request is a PATCH request. The arguments match those in the any() method. options($from, $to[, $options[, $nested = false]]) Creates a route which will only be accessible when the $_SERVER['REQUEST_METHOD'] indicates that the current request is an OPTIONS request. The arguments match those in the any() method. block($paths) Prevents access to an array of routes by setting each of the supplied values in the $paths array to an empty path. If $paths is not an array, this method will do nothing. context($name[, $controller[, $options]]) Provides a method for assigning controllers in modules to an area of the site based on the name of the controller. Note that $options can be passed as the second argument if the $controller argument is not needed. $name is the name of the URL segment for the context. $controller is the controller name which will be mapped into this context. If not supplied, $name will be used for $controller. $options is an array of options with the following (optional) keys: 'offset' allows the numeric arguments in the $to portion of the route to be increased by the offset value (so, if 'offset' is 1, $1 becomes $2, $2 becomes $3, etc.). 'home' allows the definition of a default route for the context. named($name) Returns the $from portion of a route which was previously saved as $name. Returns null if a route was not found with the given $name. prefix($name, Closure $callback) Prefix a set of routes (defined in the $callback closure) with the $name prefix. All routes defined in the closure will be defined with the $from portion of the route prefixed with $name (e.g. 'users' becomes 'api/users' if $name is 'api'). reset() Resets the internal state of the Route library, eliminating any routes which have not already been output. resources($name[, $options[, $nested = false]]) Creates a pre-defined set of HTTP-verb based routes for the $name controller. $name specifies the name used in the $from portion of the routes. $options may include the following keys: 'controller' specifies a name to be used for the controller in the $to portion of the created routes (if not included, $name will be used). 'module' specifies a module name to be included in the $to portion of the created routes. 'constraint' specifies permitted values for ID arguments in get/put/delete routes, defaults to '([a-zA-Z0-9\-_]+)'. 'offset' specifies an offset for numbered parameters in the route. Usually numbered parameters start at $1, but supplying an 'offset' allows starting the numbers at a higher value. For instance, setting 'offset' to 1 would cause the numbered parameters to start at $2. $nested may be set to a callable function to define your own handler for these routes (note that the same handler will be used for all of the routes generated by this method). Example: Route::resources('photos'); Generates the following routes: Verb Path Action used for GET /photos index displaying a list of photos GET /photos/new create_new return an HTML form for creating a photo GET /photos/{id}/edit edit return the HTML form for editing a single photo GET /photos/{id} show display a specific photo POST /photos create create a new photo PUT /photos/{id} update update a specific photo DELETE /photos/{id} delete delete a specific photo [阅读]

Roles_and_permissions

Roles_and_permissions

Roles and Permissions Bonfire uses a Role-Based Access Control (RBAC) system for its authentication and authorization system. This provides enough granularity and flexibility for most situations, though may not be suitable for every website. Stock Roles Creating New Roles Permissions Restricting Access Managing Passwords ## Stock Roles Bonfire ships with 4 roles by default. They are Administrator, Developer, Editor, and User. Each of these roles has some basic access provided, though you will need to ensure that they all have the appropriate permissions for your site. While their names assume certain capabilities within the site, they can all be changed as needed, though we do highly suggest that Administrator remains unchanged. Administrator The Administrator is the highest level user of the site. This is often the client that you are creating the site for. This is the ‘owner’ of the site and, as such, is typically given the most power of the site operators. By default, Bonfire provides this role with permissions over the entire site. Developer While the Administrator is the owner of the site, there are still some tools that Bonfire provides that they will never need, like the Module Builder, Translation tools, etc. The Developer role was created to keep the dangerous tools away from the other users of the site, while still providing powerful tools for the development and maintenance process. Editor Editors will typically be the staff hired by the Administrator to handle the day to day operations of the site. They will have a lot of capability, but there are still some sensitive areas that the Administrator might not want them to have access to. User This is the default role that anyone registering to the site is given. As such, it will typically have very limited rights to most of the site. ## Creating New Roles New roles are easily created within the admin panel by navigating to Settings / Roles and then selecting New Role in the navigation bar. The elements of the form are: Role Name - The name of the role as you want it to appear to users. It should be one word, with no spaces, though you can use underscores in their place. Description - This field is primarily used on the Roles overview page, but can be used by yourself throughout your template when needed. Login Destination - This is the relative path that a user is directed to when they login. For example, you can force all admins to be directed to the main admin page by setting this value to /admin. Alternatively, you could have Users be directed to their own dashboard or account management page by entering the appropriate relative URL here. Default Admin Context - When a user logs into the admin area, this allows you to set the context they are directed to, like /admin/content The Settings and Developer contexts are unavailable for selection here. Default Role - The role assigned to new users when they register at the site. By selecting it here, it will be removed from any other role that currently has it. Removable? - Allows you to provide access to roles other than the Admistrator, while not giving them the power to delete certain roles, keeping them safe from accidents or malicious actions. If this is set to ‘Yes’, then anyone with the Bonfire.Roles.Delete permission can delete this role. When you first create a role, no permissions will be shown. You can go back and edit the permissions available to the role by selecting the Role from the Role overview page, or by editing through the Permission Matrix. ## Permissions in Bonfire Permissions in Bonfire are modeled after the excellent and easily-understandable permission naming system in Vanilla Forums. Permissions are described in 3-part, human-readable formats that allow for nearly any type of permission to be created. This allows both the admin screens and your code to maintain a high degree of readability. ### Permission Names Permission names are split into three parts, separated by periods. Core Bonfire permissions use the following naming convention (Site is always used as the first part): Site.Action.Permission e.g. Site.Signin.Allow Modules included with Bonfire use the following naming convention (Bonfire is always used as the first part): Bonfire.Module.Action e.g. Bonfire.Roles.View In application modules (e.g. modules you create or those created by the Code Builder) the names should follow this convention: Module.Context.Action e.g. Blog.Content.View Module is typically the name of your module, or a portion of it. Context is typically the name of the context, e.g. Content, Reports, Settings, or Developer. Action is a single action that can be checked. Common actions are Manage, View, Edit, and Delete. The permission naming convention can be changed to meet your requirements, but it is recommended that you use this format to prevent conflicts. To be safe in naming custom permissions, the use of Bonfire or Site in the first region of the permission name should be considered reserved. If you choose to use Site in the first region for a custom permission, you should consider using an identifier in the second region which will be suitably unique to your site. ### Creating Permissions New permissions can easily be created through the Admin UI by navigating to Settings / Permissions. This screen will provide a list of all existing permissions as well as the option to create new ones. Each permission has the following three properties… Name is the permission itself, following the naming scheme outlined above. Description is a short string describing the permission and its use. This is only used for display in the Permissions overview page. Status allows permissions to still be available in the system, but not to actually be used. This can be used as a placeholder for in-development features. ### Assigning Permissions Permissions can be assigned to roles through the Edit Role screen. Alternatively, they can be assigned to all roles at once by viewing the Permission Matrix, available from both the Roles and Permissions screen. ## Restricting Access The Auth library provides several useful methods to restrict access, or check access, from any place in your application. If not already loaded, you can load the Auth library with the following code: $this->load->library('users/auth'); ### restrict() The restrict() method can be used to protect an entire method or even class. If used without any parameters, it will simply verify that the user is logged in. If they are not, it will redirect them to the login page. $this->auth->restrict(); You can require that a user has a certain Permission granted by passing the name of the permission as the first parameter. You do not have to match the case of the original permission string, as it will be converted to lowercase prior to checking. $this->auth->restrict('Bonfire.Users.Manage'); If a user does not have the required permission granted to them, they will be directed to their previous page. You can change the URI they are redirected to by passing it in as the second parameter. This can be either a relative or full URI path. $this->auth->restrict('Bonfire.Users.Manage', '/get-outtat-here.html'); ### is_logged_in() You can check if a user is logged in with the is_logged_in() method. This can be used in your own controller and libraries, as well as in your views to display different information to logged in and logged out users. if ($this->auth->is_logged_in()) { . . . } else { . . . } Note that the first time in a session that this function is called, it will verify their identity stored in the session matches their hashed password information in the database. It then sets a flag that can be used for later checks to increase performance, while still maintaining a high level of security. ### has_permission() The has_permission() method allows you to check if the current logged-in user has a specified permission. You pass the name of the permission to check in as the first parameter. if (! has_permission('Bonfire.Users.Manage')) { . . . } ### permission_exists() This function allows you to quickly check whether a permission exists in the databse or not. Simply pass in the permission name to check as the first parameter. if (permission_exists('Bonfire.Users.Manage')) { . . . } ## Passwords While passwords are generally managed through the users module, the auth library includes a couple of basic functions for password management. check_password() The check_password() method allows you to verify that a given password matches a password hash. if ($this->auth->check_password('password to check', 'HashedPassword')) { // The passwords match ... } hash_password() The hash_password() method allows you to hash a password with an optional number of iterations (if not supplied, the site’s password_iterations setting will be used). This should not be used to check a password, since hashing the same password again won’t match a stored hash. $password = $this->auth->hash_password('password'); $hash = $password['hash']; $iterations_used = $password['iterations']; Note that although the number of iterations used in hashing the password is returned by this method, it can be safely ignored. The primary use of the returned value would be to check whether the hash_password() method is accepting your input (or using the config value instead) in debugging, since the PasswordHash library stores the number of iterations in the hash and only uses the value in the hash when checking a password. [阅读]