Foros de discusión

Firing error for required category

Julien Tabouret, modificado hace 9 años.

Firing error for required category

Junior Member Mensajes: 27 Fecha de incorporación: 17/05/13 Mensajes recientes
Hello guys,

I implemented asset categorization following the official documentation and wiki for Liferay 6.2 (I am under liferay 6.2-GA2).

Everything works fine except that no javascript error is fired when the user fails to select a required category.

When displaying the form, the information "(Required)" is displayed next to the label of the categories selector. So it seems that the framework detects that this vocabulary is mandatory for this asset.

In the same form, I attached a form-validator to a simple input with the <aui:validator> tag and it works perfectly fine, displaying my custom message when needed. So javascript is not the problem here.

Here is the part of my JSP used to display the categories :

<liferay-ui:asset-categories-error />
<aui:fieldset column="true">
		<aui:input name="categories" type="assetCategories" />
		&lt;%-- 		<liferay-ui:asset-categories-selector --%>
		&lt;%-- 			className="&lt;%=JapaneseWord.class.getName()%&gt;" --%&gt;
		&lt;%-- 			classPK="${japaneseWord.wordId}" /&gt; --%&gt;
</liferay-ui:asset-categories-selector></aui:fieldset>


The rendered HTML is as follow :

<fieldset class="fieldset " id="yui_patched_v3_11_0_1_1428094789381_1521">
   <div class="row-fluid" id="yui_patched_v3_11_0_1_1428094789381_1520">
      <div class="control-group" id="yui_patched_v3_11_0_1_1428094789381_1519">
         <span class="field-content" id="yui_patched_v3_11_0_1_1428094789381_1518">
         
            <label id="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_assetCategoriesLabel_23702" for="yui_patched_v3_11_0_1_1428094789381_207"> Catégorie grammaticale <span class="label-required">(Requis)</span> </label>
            
            <div id="yui_patched_v3_11_0_1_1428094789381_207" class="yui3-widget component autocomplete textboxlist tagselector categoriesselector" aria-labelledby="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_assetCategoriesLabel_23702" tabindex="0">
               <div id="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_sxvx_column2_0_assetCategoriesSelector_23702" class="lfr-tags-selector-content autocomplete-content textboxlist-content tagselector-content categoriesselector-content">
               
                  <ul class="helper-clearfix textboxlistentry-holder unstyled">
                     <li class="textboxlist-input-container hide-accessible">
                        <span class="field yui3-widget component textfield field-text" id="yui_patched_v3_11_0_1_1428094789381_252">
                           <span class="field-content textfield-content" id="yui_patched_v3_11_0_1_1428094789381_254">
                              <input type="text" name="yui_patched_v3_11_0_1_1428094789381_252" id="yui_patched_v3_11_0_1_1428094789381_252" class="field-input field-input-text" autocomplete="off" tabindex="null">
                           </span>
                        </span>
                     </li>
                  </ul>
                  
                  <div id="yui_patched_v3_11_0_1_1428094789381_392" class="toolbar-content yui3-widget component toolbar">
                     <button type="button" class="btn yui3-widget btn-content" title="Sélectionner Catégorie grammaticale" id="yui_patched_v3_11_0_1_1428094789381_1480"><i class="icon-search"></i> Sélectionner</button>
                  </div>
                  
                  <input type="hidden" value="" name="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_assetCategoryIds_23702" id="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_assetCategoryIds_23702" class="field">
               </div>
            </div>
         </span>
         
         <span class="field-content">
         
            <label id="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_assetCategoriesLabel_15501" for="yui_patched_v3_11_0_1_1428094789381_515"> Thématique </label>
            
            <div id="yui_patched_v3_11_0_1_1428094789381_515" class="yui3-widget component autocomplete textboxlist tagselector categoriesselector" aria-labelledby="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_assetCategoriesLabel_15501" tabindex="0">
               <div id="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_sxvx_column2_0_assetCategoriesSelector_15501" class="lfr-tags-selector-content autocomplete-content textboxlist-content tagselector-content categoriesselector-content">
                     
                  <ul class="helper-clearfix textboxlistentry-holder unstyled">
                     <li class="textboxlist-input-container hide-accessible">
                        <span class="field yui3-widget component textfield field-text" id="yui_patched_v3_11_0_1_1428094789381_560">
                           <span class="field-content textfield-content" id="yui_patched_v3_11_0_1_1428094789381_562">
                              <input type="text" name="yui_patched_v3_11_0_1_1428094789381_560" id="yui_patched_v3_11_0_1_1428094789381_560" class="field-input field-input-text" autocomplete="off" tabindex="null">
                           </span>
                        </span>
                     </li>
                  </ul>
                     
                  <div id="yui_patched_v3_11_0_1_1428094789381_683" class="toolbar-content yui3-widget component toolbar">
                     <button type="button" class="btn" title="Sélectionner Thématique"><i class="icon-search"></i> Sélectionner</button>
                  </div>
                  
                  <input type="hidden" value="" name="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_assetCategoryIds_15501" id="_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_assetCategoryIds_15501" class="field">
               </div>
            </div>
         </span>
      </div>
   </div>
</fieldset>


I don't know if asset-categories-error is supposed to generate any markup but there is nothing before the <fieldset> tag.

As far as Javascript is concerned, I localized these piece of code :

Liferay.Form.register(
		{
			id: '_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_fm'
				, fieldRules: [
							{
								body: '',
								custom: false,
								errorMessage: '\u0056\u0065\u0075\u0069\u006c\u006c\u0065\u007a\u0020\u0073\u0061\u0069\u0073\u0069\u0072\u0020\u006c\u0061\u0020\u0074\u0072\u0061\u006e\u0073\u0063\u0072\u0069\u0070\u0074\u0069\u006f\u006e\u0020\u0064\u0075\u0020\u006d\u006f\u0074\u0020\u0065\u006e\u0020\u0068\u0069\u0072\u0061\u0067\u0061\u006e\u0061\u0073\u0020\u006f\u0075\u0020\u006b\u0061\u0074\u0061\u006b\u0061\u006e\u0061\u0073\u002e',
								fieldName: '_minnanonihongovocabularyadmin_WAR_minnanonihongoportlet_kanaSpelling',
								validatorName: 'required'
							}
				]
		}
);


One can recognize the piece of code responsible for the validation of the simple <input> tag I refered to earlier. But there is nothing targetting the categories <select>.

I can't figure out what I am missing. Could anyone give me a hint ?
Julien Tabouret, modificado hace 9 años.

RE: Firing error for required category

Junior Member Mensajes: 27 Fecha de incorporación: 17/05/13 Mensajes recientes
I forgot to mention that I also placed the <liferay-ui:asset-categories-error /> inside the fieldset, before and after <aui:input name="categories" type="assetCategories" /> but it didn't changed anything.
Julien Tabouret, modificado hace 9 años.

RE: Firing error for required category

Junior Member Mensajes: 27 Fecha de incorporación: 17/05/13 Mensajes recientes
After diving into Liferay code, I think I figured out how the asset framework is supposed to be used regarding categories validation. For those like me who are interested in this mecanism, I will post what I found here.

1. Exception
The <liferay-ui:asset-categories-error> taglib requires an instance of AssetCategoryException available in the context of the page to display error messages.

A typical way of putting such an exception in the page context is to use SessionErrors. For exemple :

SessionErrors.add(actionRequest, e.getClass(), e);


2. Validation
The AssetEntry entity comes with a validator defined by the AssetEntryValidator interface implemented by the BaseAssetEntryValidator class (which is the only one to throw AssetCategoryException exceptions).

Before being saved through the AssetEntryLocalServiceUtil#updateEntry method, asset entries are consistently validated against the default validator defined in portal.properties (the well named DefaultAssetEntryValidator).

3. Conclusion
To automagically display error messages when an entity breaks the rules of the associated vocabularies, all you need to do is :
  • call updateEntry
  • catch the exception thrown
  • put the exception in the context with SessionErrors
  • place the <liferay-ui:asset-categories-error /> tag in your page


4. Flaw
If simple, this mecanism seems dangerous to me because it can lead to data integrity issues at the database level.

The most common pattern when saving an entity and its related asset entry is as follow :
  • validate the entity (MyCustomEntityValidator#validate)
  • save the entity (MyCustomEntityPersistence#update)
  • save the related asset entry (AssetEntryLocalService#updateEntry)

This pattern is implemented by CalEventLocalService, BookmarksLocalService, WikiPageLocalService and many more.

The fact is that the validation of the asset entry does not prevent the entity from being saved. Which means that even if an exception is thrown when validating the asset entry, the entity is already saved anyway. And since we are at service level, database transaction is already closed and there is no way to rollback.

One can see that Liferay is a well coded portal and I am sure that developers are already aware of that. So I think I missed something here.
If somebody has a clue, please let me know.

Regards.