Recall that our "mission" is to create a model that will generate code similar to the following:
In this help we will describe how to implement the main components that make up the faq model. Creating the faq ModelLet's jump ahead a little bit and show what our faq model input form will look like: This form is what you would expect given the properties and methods of our runtime faq class (html_page_faq). Let's review the fields on this form:
Before we create our faq model object, let's create the select field and flexgrid since we will need to refer to these in our model. Create Special Fields Used by the ModelWhile logged into the genhelm site edit the select model to build our auto open selector. Here we see the three options from which the user can select: We stow this as auto_open_faq. Next we will use the flexgrid model to create the grid that is used to enter the section headings, questions and answers. First let's look at the scalar properties that we need: Let's review the fields that we have set:
Next we need to configure the columns of the flexgrid as shown below (note that some empty columns right of what is shown have been excluded): The rows define each of the columns in the flexgrid. Most of the settings are self-explanatory. The fourth row uses a reserved column name of new(). This row will be used to configure new columns that are added by the users of the flexgrid to insert more answer paragraphs. Without this new() definitions, new columns would be inserted without a header. Refer to the flexgrid model help for more information about configuring flexgrids. Create the Model ClassNow we will turn our attention to the faq model class. All models are named using the convention model_[name] so this model class is named model_faq. All models are created within the genhelm site. Here we see the scalar parameters for this model. Let's go over all of these settings. Base ClassSince the faq model will be used to generate an entire web page, we set our Base Class to page_spec. This allows us to inherit all of the page-oriented properties and methods such as those dealing with meta tags, CSS, script, layouts, etc. For models that are not intended to generate pages, the base class is normally left empty. In such a case the model will inherit from the spec class by default. On rare occasions you might create a model that inherits another model. This is done when the functionality of one model closely aligns with another. Default Spec NameIn cases where a website would typically only have one component of a certain type (generated by the model) you can indicate a default spec name within the model. When a default is specified, users can use the stow command without specifying a specification name. If a specification does not already exist with the default name it will be used as the name for the newly stowed specification. If there is a default spec name indicated, this specification will also be loaded by default whenever the model is used. Spec SubfolderIf specifications for this model are to be stored within a certain subfolder of the spec folder, enter the name of the subfolder here. Special Form NameBy default, the form used to enter the specification for all models is e_[model_name]. If your model does not use this default naming convention you can enter an alternate name here. Required Access LevelDevelopers can be assigned access rights using the logon_access model. This field can be used to restrict use of the current model to only those developers who have sufficient access. Default TranslationAll supplied models use classes generated using the translation model to provide values for field labels and associated help. As we will see, the name of the translation class will be specified as part of the form associated with the model. Occasionally, you may want to use an alternate translation class to translate flexgrid headings used by the model. If so, enter the name of the class here. Model DescriptionUse this field to describe the purpose or usage of the model. This description is shown when developers use the new command to obtain a list of models from which to choose. GeneratesProvide information about what the model generates. This will also be shown by the new command so try to keep this relatively short. Typical examples include php include, php class, css, xml, etc. Supports Dollar FunctionsIf the current model is used in conjunction with certain dollar functions, list these here. This will also be shown by the new command. Default Spec DescriptionWhenever any model is used to generate certain components, it is necessary to enter a description to be associated with the specification. You can use this field to provide a default description that the user (developer) can change to something more specific. Site SpecificIf the current model can only be used in conjunction with a certain site, enter the site directory here. For example, all dollar_functions are generated within the system site so that the resultant classes (dollar functions) can be used by any site. Runtime Page ClassIf this model is supported by a certain class at runtime (when the content produced by the model is rendered), you can enter the name of the class here. This is used for documentation purposes. Standard Model ImageWhen users use a model, it is possible to show an image in the model summary pane. If this option is selected, you must define an image definition with the same name as the model within the genhelm image rendition folder. Here we see an example of the faq rendition image definition (rendition/faq). Don't make these rendition images very large since they need to fit in the component summary area. Spec Specific ImageSometime it is more suitable to show a rendition that is specific to the specification being edited. For example, when editing image definitions it is helpful to see the actual image that is being defined. When this option is selected, the model class must define a method named get_spec_image. This method must return a url reference to the image to be shown in the rendition window. ObfuscateCheck this option to obfuscate the code for your model. Of the supplied model, only the model_model is obfuscated to prevent users from breaking this model. Defining the Fields Used by the ModelAll of the fields used as part of the model specification must be defined in the model definition. These are broken down into Scalar Fields and Flexgrid fields. Here we see the Scalar Fields used by the faq model. All scalar fields must be given a name, XML Type and UI Control. The XML Type determines how the XML used to save the specification will be structured. Generally speaking, simple properties can be defined as attributes while more complex or lengthy properties should be stored as elements. When in doubt use the Element option. Choose the UI control that is most appropriate for the field value to be entered. In this example, since we are using a select field to enter the auto_open value, we must identify the name of the select class within the UI Parms. We don't need to provide Field Labels or Translation classes since we will be using the defaults. By default, the labels are defined with popup help to give users of the model hints as to the purpose of the fields. This feature can be suppressed for certain labels by marking the Suppress Infobox option. You can provide an initial default value for certain fields if you wish using the next column. Certain values can also be indicated as being required. The Validations column can be used to define built in field validation. Validations must be defined as classes within genhelm/classes/field_validator and must be named validate_[name]. The validation class must contain a method named is_valid. Here is an example of such a class that is used to validate whether a supplied value coincides with the name of a class in the system classes folder:
Next we add the flexgrid definition that was created to enter the questions and answers:: Developing the Model CodeAt the very least, the model must contain one function named generate_code. This function must return an array for each component to be saved. The actual saving of components is handled by the spec base class, as is the generation of the XML used to capture the specification. Each array occurrence used to describe components to be saved must contain the following keys: folderThis is name of the folder in which the component will be saved. This is not a full folder path but rather just the first node under the site's public_html or private_data folder. nameThis is the file name under which the generated component will be saved. contentsThis is the (generated) contents that will be saved. When the name refers to a zip file, the contents defines the list of files to be included in the zip. subfolderThe subfolder key is optional. If supplied, this will be used to define the subfolder in which to save the generated content. Before working out all of the details of what your model will be generating, you might want to create a simple function such as the one we show below: This will just generate some static code but it will give you a chance to build a form for your model without getting bogged down with what the model will be generating. In the example above, the code will only generate one component since only one occurrence of an array is returned. Notice that we don't include the function statement or the opening and closing function bracket. This is because we have entered the function name in the Section Id and used Replace Body as the Location indicator. The $spec_name field is a parameter that is passed to the generate_code function. This is the name that the user included in the stow command. For example, if the user issued the command stow fred/flintstone, the value of $spec_name would be 'fred/flintstone'. We will come back to the model custom code later but first we will define a form for the model so that we can properly test the model code as we develop it. Model Input FormRecall that, by default, the name of your model form is e_[model_name]. Next we will go over the contents of our e_faq form. Here we see the main form parameters: We have indicated that the translation class will be faq. This is where the form's labels will be saved. By using ? as the default label, this means that, by default, all labels will be taken from the translation class and will include popup help. In the Field Definitions field we have specified the class associated with our model. The form is able to call this object to obtain the field definitions because the spec base class defines the required field_definitions method. Next we see the form definition which defines the layout for the faq model form: The first three rows simply show scalar fields with :: used in column 1 as the placeholder for the translated labels. On row 4 we have used the infolabel dollar function to introduce the flexgrid. Row 5 is the flexgrid itself. On the last row we include the common_page_properties form which contains all of the other properties associated with all forms. We define e_faq as a Page Component without URL access since this only runs within the context of the main GenHelm form. That's all we need to do to create our model form. Define Translation ClassThe final step in building our model interface is to create the translation class named faq. This will provide all of the labels and popup help values to the form. At this point the model could be loaded and the model screen will be shown. Next we are going to dive deeper into how we complete the coding of the generate_code method. |