Beginning advanced module in v1

edited October 2012 in Modules
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

  • edited October 2012
    I've pushed a fix for the generated controller name as well as some improvements to the documentation. In your case, you've only generated the advanced module and the advanced module does not contain any simple modules so you will need to generate them like so:
    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.
  • edited 11:45AM
    The controller class name is OK now, but I'm still getting
    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?
  • edited 11:45AM
    I noticed I had in the code above to generate the simple modules "ion_auth_model ion_auth". It should be what is displayed below:
    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.
  • edited 11:45AM
    Yes, I noticed I had a "_model_model"! I think I will have to start from scratch, just to be clear about what I'm doing and how I got there.

    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!
  • edited 11:45AM
    I went back to basics, with a new install of Fuel, and it's all worked out as expected.

    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!
  • edited 11:45AM
    This is interesting: if I change the table name in the generated model's construct to "users", it will display the table "fuel_users". I guess these are synonymous somehow within Fuel?
  • edited 11:45AM
    Just noticed another gremlin: I created a module & model "site_users" and the model record class became "Ite_user" via generate.
  • edited 11:45AM
    If I could outline what I want to do with this advanced module maybe you could save me some time if it isn't going to work the way I expect?

    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.
  • edited 11:45AM
    I'll try and answer many of your questions below:

    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.
  • edited 11:45AM
    OK - just worked out the "has_many" property for my module. Picking jaw off floor now.

    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
  • edited 11:45AM
    I'm still stuck on getting the sub models to show up using the Fuel "module" controller.

    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?
  • edited 11:45AM
    I can't see anything wrong in your configuration file. What are the defined routes for this advanced module?
  • edited 11:45AM
    site_users_routes.php is:
    $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'; }
  • edited 11:45AM
    I think the issue has to do with there being a sub module the same name as the advanced module (e.g. site_users/site_users). In looking at the logic in the __constructor of the fuel/modules/fuel/controllers/module.php controller, it checks to see if the module site_user exists and if it does it uses that. Try changing the name of the submodule "site_users" or perhaps the name of the advanced module to see if it fixes the issue.
  • edited 11:45AM
    Yep, creating, say, an advanced module "membership" with sub models of "members" and "groups" works fine. It does mean you end up with a model "membership" that may be surplus to requirements, but that isn't necessarily an issue (it could be a model that holds settings or other meta info). So lesson learned is - emulate the blog structure!
  • edited April 2013
    OK, I'm still not clear on the structure of an advanced module:

    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?
  • edited 11:45AM
    Are those simple modules added to a fuel/modules/newsletter/config/newsletter_fuel_modules.php?
  • edited April 2013
    yes - I should have mentioned that! The code is:

    $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.")
  • edited April 2013
    I think the generated newsletter_fuel_modules arrays are assigning the wrong "model_location"? Maybe? The value to that key should be the module name "newsletter"? Eg

    $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
  • edited 11:45AM
    The model_location value is indeed incorrect and should be set to "newsletter". I'll look into that issue. It looks like you may also need to change the module_uri value:
    'module_uri' => 'newsletter/publications',
  • edited April 2013
    I downloaded today's commits (including your fix for model_location), installed fuel, ran the generate code as above and now creating navigation like:

    $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.
  • edited 11:45AM
    Oddly though, the H2 ico class is 'ico ico_newsletter_publications' across all sub model pages? 'Publications' happened to be the first model in the generate command?
  • edited 11:45AM
    You can set the "icon_class" parameter for the module. However, by default, it should be using the module_uri value to generate the icon class just like the blogs does. Did you change the other module's module_uri's respectively?
    'module_uri' => 'newsletter/articles',
    'module_uri' => 'newsletter/issues',
  • edited April 2013
    Duh, forgot to change those - now they are OK.

    Bu, another oddity, I created a sub model "subscribers", and the record class came out as "Ubscribers" in the model?!
  • edited 11:45AM
    I see where that issue is (rtrim vs ltrim in the generate controller). I've posted a fix for that. Thanks.
Sign In or Register to comment.