So after three days I am about to bail out on this product. I have been working heavily with codeignitor for three years now, and rolled some interesting modifications of my own, but this seems impossible.
The screens are pretty, but the documentation is not complete, and the tutorials are broken.
The ver0.91 tutorial worked mostly, but the ver0.93 is missing stuff all over. And since there is no documentation to explain what is going on internally, its not possible to figure out what steps are missing from the tutorial. Its very clear that the author never actually tried following the tutorial step by step. As an example: The author never mentioned creating an entry in MY_fuel_modules for the articles module. Another example: The author never mentioned setting up the "variables" file for the page 'example.php' so that it can process various categories. I was able to figure out this only because I had run into the same problem in Ver 0.91. In the end, it still won't work because the mechanism for matching articles to the categories in the example.php is completely broken. Instead of returning an array of articles, it does a var_dump of the category to the screen. Thus the tutorial cannot be completed.
There is no explanation at all of how the internals work. There are no PHP-doc or reasonable comments in the code, and the UserGuide does not explain how FuelCms works. (As an example: How do the various cache directories relate to each other? How to best integrate FuelCms cacheing with CodeIgnitor output cacheing? What are the steps that Fuel goes through to resolve routing? Why are some classes extended, and then every method in the base class is overridden, and the base class is not inherited by any other class or used itself?)
In short, there is no "meat" in the user guide, and at the same time, no plug-and-play reliability. In the end, we are left with something that must be heavily configured, and no clear explanation for how to configure it.
Comments
I'd suggest taking a look at the 1.0 branch if you've not done so already.
The user guide in that is better (some areas aren't yet complete), and the comments in the code are very reasonable.
In all honesty, I've not taken any of the tutorials so I can only assume your criticisms are valid. I'm sure that is frustrating.
I can see in the sample code that the author invokes a module in this fashion: $posts = fuel_model('blog_posts', array('find' => 'all', 'limit' => 3, 'category'=>'announcements', 'order' => 'sticky, date_added desc', 'module' => 'blog'))
However, I will be damned if I can find any documentation on what he is doing here, what the parameters are, or what their effect is, let alone how I can do something similar with another module or any module I create.
I have tried invoking the blog_model with a parameter of categories, I have tried invoking a "getPosts()" from the categories_model. Neither of these worked because the framework refused to accept the line I attempted to use to invoke the module, which brings me back to the same problem. Incomplete information on how to invoke a module.
I think that if the author wants people to adopt his product, a bit of documentation that will explain everything will go a long way. If I have to dissect the author's code to learn how to use it, I might as well write my own.
$posts = fuel_model('blog_posts', array('find' => 'all', 'limit' => 3, 'category'=>'announcements', 'order' => 'sticky, date_added desc', 'module' => 'blog'))
fuel_model is a wrapper for loading a model with parameters to fetch records. The parameters available are described here: http://www.getfuelcms.com/user_guide/helpers/fuel_helper
It's just short hand for:
$this->load->module_model('blog', 'blog_posts'); $posts = $this->blog_posts->find_all('category = "announcements"', 'sticky, date_added desc', 3);
If you have and advanced module, that should work for you also. I'd recommend your model always extend Base_module_record as well.
If you module is a simple module, you don't use the module => "" bit. Not sure if this needs to be said or not, simple modules are files (models, controllers, views) in the app directory. Advanced modules are in modules/{your name} and are HMVC triads in their own right.
As per CI coding convections you'll not see any camel cased methods. They're all lower case/underscored.
With the 1.0 branch you'll see the posts model has a $has_many property and the categories model has a $belongs_to property. Those make fetching related data easier.
The Daylight guys are aware the docs are a bit thin and are working on it.
$sSql =
"Select a.* from fuel_blog_posts a
where a.id in
(select b.post_id from fuel_blog_posts_to_categories b
join fuel_blog_categories c on b.category_id = id
and c.name = 'announcements')";
$oResult = $this->db->query($sSql);
The Fuel way seems to use some kind of ORM or active record technique and some kind of abstraction to do the joins.... can you please show me how to do this in fuel... and point me to the place in the documentation that I will find instructions/examples on how to do it?
http://www.getfuelcms.com/user_guide/libraries/my_model
Method one:
Write the query out in full as you have. I've rewritten it to avoid the subquery.. $sql = ' select p.* from fuel_blog_posts p join fuel_blog_posts_to_categories ptc on ptc.post_id = p.id join fuel_blog_categories c on c.id = ptc.category_id where c.name = "announcements" ';
Usage is the same as any other CI app as a method of your model.
Method two:
Use active record in your own method. public function find_all_the posts($category) { return $this->db ->join('fuel_blog_posts_to_categories ptc', 'ptc.post_id = p.id') ->join('fuel_blog_categories c', 'c.id = ptc.category_id') ->get_where('fuel_blog_posts', 'c.name="announcements"') ->result(); }
Method three
If you wanted to be a bit more 'FUEL-Y' you could use a method in a record_class. So in your model called mmm, 'categories_model', have at the bottom: <code> class Category_model extends Base_module_record { public function find_all_the_posts() { # Note that $this here is your record return $this->db ->join('fuel_blog_posts_to_categories ptc', 'ptc.post_id = p.id') ->join('fuel_blog_categories c', 'c.id = ptc.category_id') ->get_where('fuel_blog_posts', 'c.name = "'.$this->name.'"') ->result(); # Could also lazy load the posts model here } }
Method four (1.0 branch)
There is no posts_to_categories joining table. If both models have the right $has_many/$belongs_to class members the posts should be available once the 'parent' object has been retrieved. Roughly: $category = $this->categories_model->find_one('name = "announcements"'); foreach ($category->posts as $post) { # $post related info here } Should work in reverse too: $post = $this->posts_model->find_one('permalink = "some-post"'); foreach ($post->categories as $category) { # $category info }
I was actually expecting some kind of an answer that involved loading multiple modules (articles & categories) and linking them in the view/controller. I thought I saw it done that way someplace in one of the files, but I can not find it now (maybe in V0.91?).
Based on your answer (method 2), and the comments around the Tables Model section on $this->examples_model->query(params) , am I correct in thinking that there is an active record or similar ORM at play here? Does this preclude database result cacheing since no "hint" can be passed in the query?
Active record is used heavily. If there's a single file I suggest you look at it would be MY_model.php. In 1.0 you'll find this in /modules/fuel/core. It's pretty big but understanding how find_one and find_all work are, in my view, very important.
Since method three sounds like a bit of you, here's a lift from a current project (1.0 mind) that uses the lazy_load method I touched on:
The prerequisite here is I already have the product public function get_attributes() { if ( ! $this->has_attributes) return false; $sql = array( 'order_by' => 'sequence asc', 'join' => array('store_attributes_order', 'id = attribute_id'), ); $attributes = $this->lazy_load(array('product_id' => $this->id), array(STORE_FOLDER => 'attributes_model'), true, $sql); foreach ($attributes as $key => $attribute) { $data[$key]['attribute'] = $attribute; $data[$key]['values'] = $attribute->get_values($this->id); } return $data; }
Meanwhile, I notice there is a library in the [blog module] named "Fuel_blog.php" and within that library is a method named "get_category_posts()". It is not clear to me however how I may initialize and invoke a library of a module from within a view of the main project. I suppose I could lift the entire method and copy it into the main project, but that seems to defeat the idea of having modules. What say you?
I am sorry if these questions seem annoying, but no matter how I search, I cannot find a book on FuelCMS on amazon.com (smile).
J
The code I pasted above was an extension of method three so that goes in the Base_module_record bit of your model.
So the entire skelton of the model is:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); require_once(FUEL_PATH.'models/base_module_model.php'); class Products_model extends Base_module_model { function __construct() { parent::__construct('store_products'); } # Things like form_fields and list_items here. Any method you want to call that's not in the context of a record } class Product_model extends Base_module_record { # Record level methods here such as get_attributes() above }
I've been showing you different ways of getting data out of your own models/modules. The blog is a pretty complex advanced module that works how the daylight guys wrote it.
To access the blogs get_category_posts method:
To load an advanced module's library/model/view etc: $this->load->module_library(BLOG_FOLDER, 'fuel_blog'); # Usage is then like any other normal CI method $posts = $this->fuel_blog->get_category_posts('some-permalink');
[blog/blog_categories_model.php]
function get_category_posts($sCategory = NULL)
{
$CI =& get_instance();
$CI->load->module_library('blog', 'fuel_blog');
$oPosts = $CI->fuel_blog->get_category_posts($sCategory);
return $oPosts;
}
[view: home.php]
$CI->load->module_model('blog', 'blog_categories_model');
$aPosts= $CI->blog_categories_model->get_category_posts('announcements');
So now that I have groked this, the old Codeignitor way took 5 minutes, and the FuelCMS way takes 1 minute. Ya got to love modernization.......