Beginning advanced module in v1
Hi,
I'm trying to begin an advanced module using Fuel CMS v1.
Using the CLI, I've generated a module skeleton (in this case it's for ion_auth).
Issue 1 is that the generated controller has a class name of "Ion Auth" not "Ion_auth". I've tried generating other names with underscores and that seems to be a repeatable bug.
That aside, the admin now shows the new module with a default link. Clicking on that link gets an error "Call to a member function info() on a non-object" (after correcting the controller class name). This must be via the ion_auth controller (which extends Module), although I'm not certain. It does seem that the info() method is failing on line 44 of module.php's construct()
$params = $this->module_obj->info();
What is the next step to prevent this? How do I provide "info"?
Comments
php index.php fuel/generate/simple ion_auth ion_auth
The documentation for that was not clear so I've pushed an update for that.
Fatal error: Call to a member function info() on a non-object in ... module.php on line 44
when I hit the ion_auth controller, which is currently:
<?php require_once(FUEL_PATH.'controllers/module.php'); class Ion_auth extends Module { public $nav_selected = 'ion_auth|ion_auth/:any'; function __construct() { parent::__construct(); } function index() { // Put your code here echo 'Hello'; } }
The nav config for this module is
$config['nav']['ion_auth'] = array( 'ion_auth' => 'Ion Auth', );
I've renamed the original library "ion_auth_lib" so there is no clash of classnames, and replaced load->config & other load duties with the appropriate load->module_config etc.
I also tried making the controller extend Fuel_base_controller rather than Module, but the error remains exactly the same, pointing to module.php?
php index.php fuel/generate/simple ion_auth ion_auth
This will generate the sub-module ion_auth (and generate an ion_auth_model) for your advanced module ion_auth.
I've been taking a look at other advanced modules (eg Blog and Google Analytics amongst others) and it is hard to thresh out best practice or procedures when building advanced modules, when just looking at examples. This is my 3rd effort, and most ambitious, and I'm still not sure when I should use load->config (which works in some cases) or load->module_config (module_library etc), or what render method to use for front-end views, or how to work with admin forms making the most of Fuel's module classes. I've tried to examine this aspect in http://adventuresincms.blogspot.co.uk/2012_08_19_archive.html
Also, I've had success more readily on v0.93 and I need to rethink for v1.
I believe a great deal more needs to be outlined about what happens when you take a simple module and try and make it advanced (for all the good reasons there are). A new blog entry or user guide step-by-step? It's natural for developers to try with simple modules and get results, but what then if they want to share a packaged, advanced module on Github?
Advanced modules are a tremendous feature ( a sort of proto CI "sparks" ) and need more cheerleading.
Thanks for your help as usual!
I was using a customised repository of Fuel v1 that has various modifications to it, including replacing the default controller and custom MY_controller. Perhaps they are interfering with the proper execution of the generate functionality, although most of the files get created, there remains an issue ultimately with Module.php. Darn!
I want to create a "site_users" advanced module, using the ion_auth library and views, where I can! So the module name is now "site_users", as this is the core table name.
What I would like to do is create a site_users model (I have this setup, mostly thanks to the CLI generate functionality) to which one can assign groups to users. So not so different from the categories to articles example in the user guide, except, this is in an advanced module.
So far I have this site_users form_fields()
function form_fields($values = array(), $related = array()) { $related = array('site_users_groups' => 'site_users_groups_to_site_users_model'); $fields = parent::form_fields($values, $related); $CI =& get_instance(); $CI->load->module_model(SITE_USERS_FOLDER, 'site_users_groups_model'); $CI->load->module_model(SITE_USERS_FOLDER, 'site_users_groups_to_site_users_model'); return $fields; }
which doesn't work with the $related array. Remove that and the form fields display OK. I'm not sure if I need to load the 'site_users_groups_model' and 'site_users_groups_to_site_users_model', but this is as per the categories to articles example. I've tried both load->model() & here, load->module_model(), but in either case, the edit page errors with "Unable to locate the file: site_users_groups_model.php", although this file exists in /fuel/modules/site_users/models.
Another nav entry in this advanced module would point to the site_users_groups model, with the usual CMS functionality. Other links might exist to settings and other features, maybe a dashboard. Is the Blog module a good reference, or this being v1, is that example outmoded? It seems to route the links off to the fuel module controller, but when I try that, I keep getting the site_users list/edit, even when trying to link to site_users_groups.
1. The issue with the record model being "Ite_user" is a bug and I've just pushed a fix for it.
2. With regards to the table "users" mapping to "fuel_users", that is because there is a fuel config value of "tables" that maps tables to aliases. If the alias already exists, then it uses that instead of the table name. In your case, "users" aliases to "fuel_users"
3. I would definitely check out the new Model's documentation in particular using relationships with has_many and belongs_to. This will save you the need of having to create lookup tables for things.
4. All the modules found here are 1.0 compatible including the blog which is a good example of an advanced module with multiple simple modules. All the controllers for the blog are for the front end. It uses the "module" fuel controller to manage the sub modules:
https://github.com/daylightstudio/FUEL-CMS
5. With regards to use $this->load->module_model vs $this->load->model, it's always safest to use $this->load->module_model. The reason is because it will always pull from the module specified. If you use the latter, it will try and guess, depending on where it is being called from. If it is being called from a different module altogether, then it won't work.
Thanks, I didn't bother getting the blog module from Github before as I didn't realise it was v1 ready.
Thanks again, great progress in v1
The parent model (which has the same name as the module) is linked to the module controller OK, via the module routing (as per the Blog example). So the CRUD for this model is fine. However, the child model "site_users_groups" is similarly linked/routed to the module controller, but instead returns the same list + edit pages as the parent.
In the module/config I have "site_users_fuel_modules.php" as follow:
$config['modules']['site_users'] = array( 'preview_path' => '', 'model_location' => 'site_users', 'module_name' => 'Site Users', 'module_uri' => 'site_users/site_users', 'model_name' => 'site_users_model', 'model_location' => 'site_users', ); $config['modules']['site_users_groups'] = array( 'preview_path' => '', 'model_location' => 'site_users', 'module_name' => 'Users Groups', 'module_uri' => 'site_users/site_users_groups', 'model_name' => 'site_users_groups_model', 'model_location' => 'site_users', 'display_field' => 'name', 'permission' => 'site_users', 'instructions' => lang('module_instructions_default', 'users groups'), 'archivable' => TRUE, 'configuration' => array('site_users' => 'site_users'), 'nav_selected' => 'site_users/site_users_groups', 'default_col' => 'name', 'default_order' => 'asc', 'sanitize_input' => array('template','php'), 'table_headers' => array( 'id', 'name', 'description', 'active', ), );
but "model_name" property in the Module controller remains as "site_users_model" even when the url is "/fuel/site_users/site_users_groups".
I don't know what I'm missing here?
$route[FUEL_ROUTE.'site_users'] = 'site_users'; $site_users_controllers = array('site_users', 'site_users_groups'); foreach($site_users_controllers as $c) { $route[FUEL_ROUTE.'site_users/'.$c] = FUEL_FOLDER.'/module'; $route[FUEL_ROUTE.'site_users/'.$c.'/(.*)'] = FUEL_FOLDER.'/module/$1'; }
If I generate an advanced module called 'newsletter' with
php index.php /fuel/generate/advanced newsletter
then create models with the command
php index.php /fuel/generate/simple publications:issues:articles newsletter
I then want to route these models (as per the blog advanced module) through the Fuel module controller, so in newsletter_routes.php I have:
$con = array('publications','issues','articles'); foreach($con as $c) { $route[FUEL_ROUTE.NEWSLETTER_FOLDER.'/'.$c] = FUEL_FOLDER.'/module'; $route[FUEL_ROUTE.NEWSLETTER_FOLDER.'/'.$c.'/(.*)'] = FUEL_FOLDER.'/module/$1'; }
Then for the admin navigation in newsletter.php in the config folder:
$config['nav']['newsletter'] = array( 'newsletter/publications' => 'Publications', 'newsletter/issues' => 'Issues', 'newsletter/articles' => 'Articles', );
So in theory, each link will be routed to the module controller. But instead, the message
"An Error Was Encountered You are missing the module newsletter." is shown.
Now, there is no need for a model "newsletter" - it's just the name of the folder / module. And yet the structure here seems to be following the Blog module example - route the module's models through the Fuel module controller, where the module has no model of the same name.
What am I doing wrong? I can see on line 50 of module.php that the "missing module" message is generated, but I'm not sure why?
$config['modules']['publications'] = array( 'preview_path' => '', 'model_location' => 'publications', ); $config['modules']['issues'] = array( 'preview_path' => '', 'model_location' => 'issues', ); $config['modules']['articles'] = array( 'preview_path' => '', 'model_location' => 'articles', );
The model files also exist in the module of course.
I should also have mentioned that the url /fuel/newsletter responds ok, with the auto-generated view, and that, if the newsletter_routes.php array does not map to the Fuel module controller, the links to each model have the same auto-generated view ("This view is located in the fuel/modules/newsletter/views/_admin/ folder.")
$config['modules']['publications'] = array( 'preview_path' => '', 'model_location' => 'newsletter', );
That is how the Blog module is setup.
If I change publications' model_location to "newsletter" as above, the Fuel module controller "works" (I get a list page, albeit with the spinner.gif ) but then if I try to "create" a new item (say for "publications") I then get a 404, as the url linked to the "create" button in the top toolbar is "/fuel/publications/create" not "fuel/newsletter/publications/create" - which if put in manually, works just fine.
I used the very latest Fuel commit to double-check this.
However, I'm doubly confused, as now I've copied the latest module.php controller into the project I'm working on (the codebase for which is probably a couple of months old), changed the model_location to 'newsletter', and everything works as I expect (more or less) - the url '/fuel/newsletter/publications' goes to a list page - in fact, both '/fuel/newsletter/publications/' and '/fuel/publications/' work identically - and the 'create' link goes to '/fuel/publications/create' which works OK: I might have expected it to use '/fuel/newsletter/publications/create' but I can see why it works as it does.
But for this to work, MY_Fuel_modules has to have these modules present, so they are registered twice on the navigation (under "Modules" & "Newsletter"). Removing them from that file results in the '/fuel/publications/create' url pattern stopping working (of course) while '/fuel/newsletter/publications/create' still works, but is not linked via the toolbar. Aagh! At least the modules can be hidden from the menu, I've just found out.
I've got the Blog installed too, and that works using the module name in the url for both the list and the create views, which is contrary to the above, but "correct" eg:
/fuel/blog/posts
/fuel/blog/posts/create
'module_uri' => 'newsletter/publications',
$config['nav']['newsletter'] = array( 'newsletter/publications' => 'Publications', 'newsletter/issues' => 'Issues', 'newsletter/articles' => 'Articles', );
with routing like:
$con = array('publications','issues','articles'); foreach($con as $c) { $route[FUEL_ROUTE.NEWSLETTER_FOLDER.'/'.$c] = FUEL_FOLDER.'/module'; $route[FUEL_ROUTE.NEWSLETTER_FOLDER.'/'.$c.'/(.*)'] = FUEL_FOLDER.'/module/$1'; }
with newsletter_fuel_modules.php as:
$config['modules']['publications'] = array( 'preview_path' => '', // put in the preview path on the site e.g products/{slug} 'model_location' => 'newsletter', // put in the advanced module name here 'module_uri' => 'newsletter/publications', ); ...etc...
and it seems OK - although I think the cache needed breaking to get it to work - initially it 404'd.
'module_uri' => 'newsletter/articles',
'module_uri' => 'newsletter/issues',
Bu, another oddity, I created a sub model "subscribers", and the record class came out as "Ubscribers" in the model?!