Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Customizing fieldset template
  • Hi,

    I'd like to customize fieldset template to follow Bootstrap form rules.

    I only use the ORM parameters array to set parameters for the form and then in my controller I do build it this way:

    $form  = Fieldset::forge( 'settings' )
    ->add_model( Model_Settings::forge() )
    ->build( Uri::current() );

     I have few questions:

    1. Can I set the form class from the ORM level or I have to use the 'form_attributes' in the template, globally?
    2. Can I customize the label class from the parameters array level? Seems like array is not accepted there all I can do is 'label' => "Text". I'm able to set label class only using the custom config passed to the Fieldset::forge(),
    3. Depending on form types and sizing I'd have to modify the grid (eg. col-sm-3 for label and col-sm-9 for the input) these values may be different on certain forms. Can I do this from the ORM parameters level (would be handy) or I'd have to pass new templates for that fieldset (which will be dirty, since I need to modify only one character and would have to deliver long template),
    4. Can I move the required aster risk within the label? Since bootstrap requires label class to follow grid system for horizontal forms (col-*-*). I havent seen any label template to modify,

    In general, bootstrap requires form schema's to be more complex. Not to mention other form types like inline ones. Would be great if we could have more control of the form building process. For example, field description may be only set within the form_template, when we wrap it like <p>{description}</p> it will render <p></p> even for fields without description.

    More questions to come :-)
    1. I'm not sure I understand this question. Form-attributes are defined in the form.php config file, which contain the HTML needed to generate a form. It also makes sure your forms all have the same look and feel. It is not a problem to define form attributes for Bootstrap, we have quite a few applications that do the same. You can pass a custom form-attributes array in the config array you can pass to Fieldset::forge(), so theoretically you can have a different set for every form. But that defaults the point of a Fieldset a bit...
    2. There is one label class at the level of the form-attributes, so your forms have a uniform look-and-feel. It can be overridden on a field by field basis, using the set_label() method of the Fieldset_Field object.
    3. See 1.
    4. The required mark is defined by the macro "{required"}, by default defined in the field_template and multi_field_template. You can move that whereever you want (or remove it), and it can also contain HTML, for example if you want to use a fontawesome or a fontello icon instead.
    If you want more fancyness and/or more flexibility, I can suggest you look at the new fieldset and validation packages that we've created. We use these in most apps these days.


    It comes with a Bootstrap3 renderer, and allows you to create your own custom renderers for forms, so the sky is the limit.
  • 1. and 2. I was asking if it's possible to set form/label attributes (including class) or add submit button within ORM $_parameters array, since we config all fields right there including label, such possibility would be handy but I understand now from what you've said that it's not possible, since form.php is responsible for this globally.

    Regarding the apps, they look neat and modern but I don't think they will be compatible with ORM validation, until few changes in the ORM structure.

    Btw. are there any examples on using Fieldset class with ORM out there? Documentation appears to be a little bit poor for it. I'd like to add a submit button wrapped by the HTML and it this another obstacle I have to face.

    I'd like the submit to be separated from the other inputs so I need it to look like <div class="mysubmit"><input type="submit .../></div>

    Oh, and just another one came to my mind - how to create a <button> instead of <input type="submit"/>? Only buttons support things like fontawesome icons in their value.

    Btw2. Can I catch you on the IRC somewhere? 
  • I decided to throw an eye on the 2.0 packages, even without ORM $_parameters support... (or maybe there is a way to initialize inputs/validation from the array?) I really liked it so far, however... what is the future of those? I mean there are no commits, recently Steve West responsible for those packages has left the Fuel team which in fact means that Fuel became one person project(?). I'm confused about the future plans of it.
  • The ORM - Fieldset - Validation triangle has always been a bit of black magic, ever since Jelmer created it. I always have to dive into the code to exactly see how it works. ;-)

    You can define the label in the ORM field form array, you can use a lang string as well to have it automatically translated. But you can't define/override the label class at the moment, it is hardcoded to the form config in Fieldset_Field, L#592.

    You can modify the Fieldset after generation in the model class set_form_fields() method. Define it in your model, call the parent first to have the fieldset created form your $_properties definition, after which you can change it any way you want. We use this to add buttons, conditionally hide fields or set fields to readonly, populate dropdowns from relations or other tables, etc.

    This is an example from one of our models: https://bin.fuelphp.com/snippet/view/OQ

    Fieldset supports every field type supported by the Form class. 'button' is explicitly supported, see Fieldset_Field, L#566.
  • set_form_fields() method was the one I was missing :-) Big thanks. You made me sad though, since I liked 2.0 packages way more :-( I even created my own renderer class for Bootstrap 4 horizontal forms including grids.. but since it doesn't work well with $_parameters I think I will throw it away for later.

    Hey, did you read my second post? 

    I'm kinda worried about FuelPHP team. Steve West has left the team and Fuel appears to now be a one person project. 2.0 development is going very slow, almost no commits lately. Could you comment that? What is the FuelPHP future? :-)
  • HarroHarro
    Accepted Answer
    As to your last question: up until now, Fuel has been a purely community driven project, meaning people working on it in their free time, or as part of their dayjob. 

    This is great because it means you're completely independent (the main reason we started, because the company behind CodeIgniter refused most community input). The downside is that it is always a struggle to find enough people, since spare time is scarce, personal circumstances change, and work environment change.

    Both Steve and I have been struggling with our health over the last few years. I've not been able to work at all, Steve needed to focus on his day jon, and also moved to a work environment that hardly uses any PHP at all. Both of these issues are behind his decision to retire.

    At the same time, it is very difficult to recruit new developers, who are willing to spend 20 or more hours a week of their free time developing software for other people, for free. The latest generation of programmers are more consumers, with a 9 to 5 mentality. Programming these days is a job, like all others.

    Obviously, that leads to questions about the furture. I currently have two answers:

    First, there's Fuel v1. Which is very much active, very much maintained (by me), and will be maintained for many years to come, if only because we have a lot of applications in the field running on Fuel v1, and most clients don't want to pay for a rewrite just because there's a new framework, as that is a cost without functional and/or business benefits, and therefore impossible to swallow.

    Then there's the question about Fuel v2. When we started with it, we listed all the shortcomings we thought were part of v1, which we wanted to address. These plans are now outdated, because they would have made v2 very complex and heavy, and if you really want that, there's already Laravel, which has implemented most of the v2 plans.

    Recently, within my company we've started a debate about how the new framework architecture should look like, given how the world has changed in the last few years. Think about API's, microservices, distributed applications, multi-channel, etc.

    The option currently on the table is that the company, which already sponsors Fuel and has contributed quite a bit of code originally written for client applications, takes over the project. I will continue maintaining v1 in my spare time, the company will develop their new application framework, and will open source a large part of that, as Fuel v2.

    Some parts of the current codebase, that are already quite mature and used, will be incorporated. Think about fieldset and validation, for some bits logic will be reused (dependency, routing, etc), and some will be replaced (like events, which Frank now maintains as Leaque\Event), etc.

    v2 will most likely be workflow pipeline based. One pipeline to process the request from entry to business logic, and a second pipeline from the result data to the output. Within the pipeline you chain tasks together, each passing the result on to the next, but the design is still very much on the drawing board.

    I really have to make a blog post of this... ;-)
  • Great answer :-) Thank you for that. I'm very happy that there are still many years to come with Fuel.

    Regarding Laravel: it's incredibile heavy, complex and has many dependencies (not to mention almost half of it comes from Syphony). Result? 0.2~ sec. page load for the page with a theme containing some assets on the stack plus few queries. Fuel does the same in 0.09 sec. with a lot smaller footprint. 

    Fuel makes things simple when they have to be. The main disadvantages are poor documentation and a poorly thought-out classes like mentioned form builder (v2 is the way it should be done in my opinion). 

    Regarding the main subject of this thread:

    If someone would be struggling around with a similar issue here is the class I used in the model for the current v1 form builder to fully support bootstrap + more fancy things like not displaying description HTML if it's not specified + new template for the submit button:


    public static function set_form_fields( $form, $instance = NULL )
    {
    // Add the csrf token field to the form
    $form->form()->add_csrf();

    // Create submit button from template workaround
    $form->set_config( 'form_template', str_replace( '{submit}', $form->get_config( 'submit_template' ),
    $form->get_config( 'form_template' ) ) );

    // Create the base fieldset
    parent::set_form_fields( $form, $instance );

    // Apply valid bootstrap class to inputs & set validation rules to HTML tag rules
    foreach ( $form->field() as $field )
    {
    if ( $field->type == 'text' )
    {
    $field->set_attribute( 'class', $form->get_config( 'input_class', 'form-control' ) );

    foreach ( $field->rules as $rule )
    {
    if ( $value = (int)reset( $rule[ 1 ] ) )
    {
    $rule[ 0 ] == 'max_length' and $field->set_attribute( 'maxlength', $value );
    $rule[ 0 ] == 'min_length' and $field->set_attribute( 'minlength', $value );
    }
    }
    }

    // Workaround for lack of description template.
    // Since we don't want <p></p> to be visible on fields without description
    trim( $field->description ) != '' and
    $field->set_description( '<p class="help-block">' . $field->description . '</p>' );
    }
    }
  • (Exceeded characters limit)


    It's also a good idea to split your form template config on the default one and others I did it like this (non-default ones contains only modified templates so you need to call array_merge on the default and currently used template to not duplicate already defined templates)

    (Still modify it to fit your needs, I have added some additional divs right there)
    <?php

    return [
    'default' => [
    'prep_value' => TRUE,
    'auto_id' => TRUE,
    'auto_id_prefix' => 'form_',
    'form_method' => 'post',
    'form_template' => "\n\t\t{open}\n\t\t<table>\n{fields}\n\t\t</table>\n\t\t{close}\n",
    'fieldset_template' => "\n\t\t<tr><td colspan=\"2\">{open}<table>\n{fields}</table></td></tr>\n\t\t{close}\n",
    'field_template' => "\t\t<tr>\n\t\t\t<td class=\"{error_class}\">{label}{required}</td>\n\t\t\t<td class=\"{error_class}\">{field} <span>{description}</span> {error_msg}</td>\n\t\t</tr>\n",
    'multi_field_template' => "\t\t<tr>\n\t\t\t<td class=\"{error_class}\">{group_label}{required}</td>\n\t\t\t<td class=\"{error_class}\">{fields}\n\t\t\t\t{field} {label}<br />\n{fields}<span>{description}</span>\t\t\t{error_msg}\n\t\t\t</td>\n\t\t</tr>\n",
    'error_template' => '<span>{error_msg}</span>',
    'group_label' => '<span>{label}</span>',
    'required_mark' => '*',
    'inline_errors' => FALSE,
    'error_class' => NULL,
    'label_class' => NULL,

    // tabular form definitions
    'tabular_form_template' => "<table>{fields}</table>\n",
    'tabular_field_template' => "{field}",
    'tabular_row_template' => "<tr>{fields}</tr>\n",
    'tabular_row_field_template' => "\t\t\t<td>{label}{required}&nbsp;{field} {error_msg}</td>\n",
    'tabular_delete_label' => "Delete?",
    ],

    'bootstrap3-admin' => [
    'form_template' => "\n\t\t{open}\n\t\t<div class=\"box-body\">\n{fields}</div>\n\t\t<div class=\"box-footer\">{submit}</div>\n\t\t{close}\n",
    'form_attributes' => ['class' => 'form-horizontal'],
    'field_template' => "\t\t<div class=\"form-group {error_class}\">\n\t\t\t<div class=\"col-sm-3 text-right\">{label} {required}</div>\n\t\t\t<div class=\"col-sm-4\">{field}{description} {error_msg}</div>\n\t\t</div>\n",
    'description_template' => '\n\t\t<p class="help-block">{description}</p>',
    'submit_template' => '<button type="submit" class="btn btn-primary" role="button">' .
    __( 'form.save' ) . '</button>',
    'error_class' => 'has-error',
    'label_class' => 'control-label',
    'input_class' => 'form-control',
    'inline_errors' => TRUE,
    'error_template' => '<span class="help-block">{error_msg}</span>',
    'required_mark' => '<span class="field-required">Required</span>',
    ]
    ];

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion