It's taken me a week to get my configuration objects working, and I still don't know how to fire the 'default hook', and have my objects in code.
Some of my problems were I think known caching issues, but I want to draw attention to inconsistencies and lack of documentation.
I started by looking at the services module, which was a bad idea, because services module wasn't using hook_ctools_plugin_directory. RC2, out today, is. I only found it when I couldn't see how to import via the 'default hook', then I had to start all over again. I shall write them about that.

UI export documentation could explain that this plugin is responsible for building the router item for the list page and all its children. I spent some time looking for $items['admin/structure/views'].

I got confused about human_name, machine_name and plain 'name'. machine_name field seems to implemented as a form element #type => 'textfield' in ctools. Should be #type 'machine_name'. However views overrides this. Tricky for me to work out what to do. And then how to handle the 'name' field in form submission.

Make it clearer that hook_ctools_plugin_directory returns a directory which will be scanned for '.inc' files. The example returns a 2 segment path, ['plugins/'.$plugin] which I was assumed was directory/filename less inc extension, then I wondered why file_scan directory didn't pick it up. Sure I should have looked at the function name more closely, hook_ctools_plugin_directory, but I'm just saying

The export_type property, is loaded into the object by ctools, but then not included in the form, but required in the submitted form data. I put the following line in my submit handler, but I felt I shouldn't have had to
$form_state['item']['export_type'] = $form_state['item']->export_type;

Could use some advice on setting up the database table, and more on what the load/save functions should do. I think an example module would be terrific here. But please don't ask me, I'm already a volunteer in my main job!

Comments

merlinofchaos’s picture

...did you read the documentation in the advanced help? Because this post acts as though there is no documentation.

merlinofchaos’s picture

The bit about the plugin directory is also documented more fully...in the plugin section.

merlinofchaos’s picture

On your machine_name bit, I don't know what you're talking to.

'human_name' is a Views construct and obviously Export UI isn't going to document that.

'machine_name' is a specific FAPI type. Not sure that export UI should be documenting that.

That's all that export ui uses:


[merlin@furor ctools]$ grep -R machine_name *
CHANGELOG.txt:#941800 by me and aspilicious: Use Drupal 7 #machine_name automation on page manager pages and all export_ui defaults.
page_manager/plugins/tasks/page.admin.inc:    '#type' => 'machine_name',
page_manager/plugins/tasks/page.admin.inc:    '#machine_name' => array(
page_manager/plugins/tasks/page.admin.inc:    '#type' => 'machine_name',
page_manager/plugins/tasks/page.admin.inc:    '#machine_name' => array(
plugins/export_ui/ctools_export_ui.class.php:      $form['info'][$export_key]['#type'] = 'machine_name';
plugins/export_ui/ctools_export_ui.class.php:      $form['info'][$export_key]['#machine_name'] = array(
plugins/export_ui/ctools_export_ui.class.php: * Test for #machine_name type to see if an export exists.

There are 3-4 small modules within CTools that use export_ui that are reasonably good examples. stylizer might be the most straightforward in that it doesn't have as much strange integration with other plugins, but ctools_custom_content isn't a bad one either.

he export_type property, is loaded into the object by ctools, but then not included in the form, but required in the submitted form data. I put the following line in my submit handler, but I felt I shouldn't have had to

You're mistaken. There is no requirement to have export_type in the submitted form data.

matslats’s picture

I was observing that machine_name is used inconsistently, and I'm still not clear what fields I need to declare in my edit handler. I've looked a little more closely, at function edit-form in ctools_export_uid.class.php, and I see that $this->plugin['export']['admin_title'] influences the machine name field, but I don't see how to set admin_title. In page manager, it is a db_field...
So I still think more documentation is needed here, and some consensus across Drupal about the use of terms like 'title', 'admin title', 'name', 'human name', and whether to name fields 'machine_name' even though that is now a field type name!

With the export type property, if I don't set it explicitly (in my form submit handler), I get this Exception:

  • Notice: Undefined property: stdClass::$export_type in ctools_export_crud_save() (line 151 of /var/www/drupal7/sites/all/modules/ctools/includes/export.inc).
  • PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY': INSERT INTO ...
  • Thanks for all your great work!

    merlinofchaos’s picture

    I was observing that machine_name is used inconsistently,

    I can't answer for what other modules do. If another module is using 'machine_name' as the identifier, there's little to nothing I can do about it. I don't use that as an identifier anywhere (as the above grep suggests) nor does my documentation encourage them to do so. I have zero control over what modules I'm not a contributor call their stuff. I can make recommendations, but my policy is to force them to as little as possible. And even modules where I own, such as Views, I let 'human_name' get committed without thinking strongly enough about the name of the field, when I really think it should've been 'admin_title'.

    $this->plugin['export']['admin_title'] influences the machine name field, but I don't see how to set admin_title.

    Oh, I see. Yes this little feature did fail to get documented. Created an issue to document that here: http://drupal.org/node/1137096 -- mostly need to check and see what else didn't get documented when that was added. That one is totally my fault.

    The short description is that export['admin_title'] points to the 'human readable' db field, if you're using a title/name pair. That way Export UI can handle it automatically in places where it makes sense. I think there is a similar setting for 'admin_description'. I can see where a paragraph or two in export.html to discuss the recommended ways to handle these fields.

    merlinofchaos’s picture

    With the export type property, if I don't set it explicitly (in my form submit handler), I get this Exception:

    Oh! I see. That's probably because you're not using ctools_export_crud_new() to create a new object with the appropriate data filled in, and then attaching your form input to it.

    The way CTools export UI does that is when editing an object, if the object is a new one it creates a blank one using ctools_export_crud_new($this->plugin['schema']); -- that way, you get a default object with everything set properly, including whatever defaults you specified in the schema. Then this is edited, and when saved, it saves normally.

    See ctools_export_ui::add_page() for the code that handles that, though I will be the first to admit that how objects are handled in the export UI at that level is abstract enough that it's a little hard to really follow.

    merlinofchaos’s picture

    I won't argue that export-ui.html documention is a little sparse. In part that's because export UI is a relatively new feature, still, and this is an open source project. I am constantly pulled in 25 different directions for where I spend my time, and I rely a LOT on contributors to help flesh out documentation on this stuff.

    danielb’s picture

    I am also going through this process right now, and it has also taken me quite a bit of time to work things out. I would like to point out the problems I had in the hope that it might highlight some pressure points for newbies to ctools.

    First of all, I think 'exportables' is not a good enough name for what this truly does - more like 'awesomables'. Working with exportables basically gives you the blueprints for how to implement a Drupal module that manages objects (and their sub-objects). The ability to export the objects is really icing on the cake, and the fact that you can have objects live in code: nice feature but hardly a selling point. This was not clear to me going in, but a pleasant surprise - because I needed something like that. I'd actually been to a lecture all about ctools exportables back in jan or feb at a Drupal convention type thing in Australia, and even from that experience I didn't catch on to what this really was. Perhaps thinking of it as a full object manager type thing is too much of a paradigm shift for where you're coming from, but I think embracing that idea could lead to great things and more features. I imagine one day there could be a tool where you could fill out a form with some facts about your objects and it would build you a ctools-based module skeleton for you.

    Another issue I had was with the documentation, and the heavy reliance on being familiar with your other modules. I don't have 'advanced help' but the files are provided as .html files - so I thought: 'brilliant', I will just open those directly, but alas they don't interlink properly when just viewed directly, and it would be really convenient if they did - not an easy thing to change at this point though, and this is not the module to talk about that. Not a huge problem, I could have installed advanced help - but I didn't want to, I had installed it a couple years ago for views help and I didn't particularly love it from a user perspective. The other problem is that the documentation frequently mentions panels. I have very little idea about what panels is, and it feels counterproductive at this point to learn about another module in order to figure out how to build mine.

    Further documentation issue - it really needs to be QA'd. There are a few typos, syntax errors in the code samples, advice to seek out files that don't actually exist, and occasionally the documentation and code samples sometimes don't match up. I also learnt a few things from looking at the Views' source code that isn't documented. I wish I kept better track of this stuff so I could actually give specific feedback, but just quickly looking back over the help files: a missing semi-colon in export.html's doc of mymodule_myobj_load_multiple(), and export-ui.html tells me to find ctools_export_ui_defaults() in includes/export-ui.inc which I can't.

    The load callback stuff, I think needs to be reworded and explained a bit more thoroughly, I had to make a few guesses. The following phrases made my mind wander way too much: "The default handlers should be sufficient for most uses." (is a default handler what I think it is?), "Using ctools_export_load_object() you can easily do both, as well as quite a bit in between." (in between where?) - I cottoned on eventually, but I think it was too casual for me to be confident in what I was doing. I also did not know how to implement an 'all' callback until I dug around in ctools code for how it is called. Furthermore the load functions provide a static reset variable, but no mention of how to reset the ctools load cache (If using ctools functions for the load, as the examples show) - I found some info on google though in another module's issue queue where they had the same problem.

    I also must have spent a few hours trying to find which hook_menu() implements 'admin/structure/views' for an example.

    I also did not understand how to name the plugin file, this really isn't clear in the documentation about hook_ctools_plugin_directory(). Another thing that was not clear is exactly which module to put in $module in the ctools hooks. When I was trying to implement an 'export_ui' plugin, I had renamed the example code from 'ctools' to 'mymodule' - and then spent hours wondering why it didn't work.

    I wanted to make an administrative interface for my exportables, like Views has - with the little twisty widgets and stuff, and I did not even guess, after 2 days of using ctools, that export-ui is what provides this. I thought export-ui would literally be a screen with a var_export() of my object, so I didn't look into it. I had actually found all the CSS and JS files in ctools that provide a lot of the cool ui functionality - but couldn't figure out how it came together.

    Some of this stuff makes me feel stupid when I realise the answer, but I also think the available info could be more explicit, so there is no doubt.

    I have only just switched my module on, and it's giving off some errors. That's what leads me to this issue (found it on google). It errors about undefined name and export_type property. This sounds familiar from the schema stuff - but I'm obviously missing some facts here on what ctools expects my object to have. I will no doubt work it out eventually bit by bit, but it would be great to have documentation on that.

    Anyway, I'll leave my thoughts here. Maybe when I am more experienced with ctools, I'll be able to look back on these comments and easily be able to contribute documentation for people such as myself.

    I might make an effort to specifically document any more problems I have so I can actually be useful here.

    danielb’s picture

    Would you be willing to a link a documentation page from the project page that people could contribute to? It could start off simple and just replicate the advanced help, and we go from there?
    When people make changes to the basic advanced help pages, you could periodically review the revision log and possibly use that as a snapshot to update the in-module advanced help?

    danielb’s picture

    OK here are my notes from today:

    in help/export.html:

    admin_description
    A convenience field that may contain the field which represents the human readable administrative title for use in export UI. If a field "admin_title" exists, it will automatically be used.

    I'm guessing "admin_title" is copy pasta for "admin_description"?

    On the 'Add' interface, the form element has this description:

    The unique ID for this (object).

    But this is kinda awkward because the terminology 'ID' has other implications, and in fact it is the name of my table's primary key.

    It was a bit dubious trying to establish what this form element was because the title of the form element comes from ''key name" in the schema, the value is called "key" in the schema, but it's called "name" elsewhere in ctools, and I thought it was a machine name, but there is no indication on the form that it should be a machine name.

    There is also no validation on this field for duplicate names (crashes the database call), or for machine readable format. You can actually create really bogus names like '$$5%^#$^$', but when you try to export -> import some validation kicks in and rejects the name.
    Also wouldn't it be better to specify a human name and then auto generate a machine name based on it? Certainly a few other things in Drupal work like that.

    I guess I plan to override this stuff, so you could just say that I can control all this anyway. But my plan was to see how far I could get without writing the extra code, and I'll bet other people will too.

    danielb’s picture

    As I go along I'm slowly understanding more stuff, but also asking more questions as I try to use more features. I've caved in to installing Advanced Help as well, but unfortunately something is stuffed with the menu callbacks and I can't get to the help pages :/

    Now reflecting on this issue, and when I am confident enough with my ctools experience to contribute:

    - Find out whether Merlin is willing to allow the user contributed documentation page for this project?
    - Any of the other stuff mentioned here that likely constitutes bugs or feature requests should be posted into individual issues?

    merlinofchaos’s picture

    I'm afriad I have little sympathy for trying to use the .html files directly and not install the advanced help module to read them. It's a really easy module to install and use.

    If we replicate the advanced help pages, and people just change them, then the advanced help itself is immediately obsolete. the two will diverge, and that is going to be nearly impossible to deal with.

    Also, "You can just" periodically review them.

    You say that as though it's a simple matter, but IMO it is not. I have a volume problem, and that is a responsibility I cannot accept, unfortunately.

    mgifford’s picture

    martin_q’s picture

    Some clarification in response to #4 and #6 above. I have add/edit forms defined in my Export UI plugin .inc file (one might think of them as hook_ctools_export_ui_form() etc). I got the errors described in the OP, namely

    • Notice: Undefined property: stdClass::$export_type in ctools_export_crud_save() (line 151 of /var/www/drupal7/sites/all/modules/ctools/includes/export.inc).
    • PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '1' for key 'PRIMARY': INSERT INTO ...

    In my case, I didn't need to add ctools_export_crud_new() because as Merlin describes, this is what CTools does. I did however need to handle the item carefully in my $form_state['item']. In the _form() function I obtained default values for each field by examining $form_state['item'], which was set up for me even when adding new objects, so that was fine. But I originally had the following line in my submit handler, which was my way of passing back the new form values to CTools:

      $form_state['item'] = (object) $form_state['values'];
    

    Simply overwriting $form_state['item'] was wrong, and instead I now have the following, which eliminates the errors above.

      foreach ($form_state['values'] as $key => $value) {
        $form_state['item']->$key = $value;
      }

    I hope this helps someone else who is wading their way through this brilliantly powerful, but sometimes bewildering tool!