<?xml version="1.0" encoding="UTF-8"?> <!-- Application Description Language framework adl2controllerclasses.xsl (c) 2007 Cygnet Solutions Ltd Transform ADL into (partial) controller classes $Author: sb $ $Revision: 1.31 $ $Date: 2008-05-27 16:27:27 $ --> <!-- WARNING WARNING WARNING: Do NOT reformat this file! Whitespace (or lack of it) is significant! --> <xsl:stylesheet version="1.0" xmlns="http://cygnets.co.uk/schemas/adl-1.2" xmlns:adl="http://cygnets.co.uk/schemas/adl-1.2" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:include href="csharp-type-include.xslt"/> <xsl:output encoding="UTF-8" method="text"/> <!-- The locale for which these controllers are generated TODO: Controllers should NOT be locale specific. Instead, the controller should render views and generate messages based on the client's locale. However, there may still need to be a concept of a 'default locale', for when we don't have messages which suit the client's locale --> <xsl:param name="locale" select="en-UK"/> <!-- bug 1896 : boilerplate text in views should be tailored to the locale of the expected user. Unfortunately I haven't yet worked out how to do conditional includes in XSLT, so this is a step on the way to a solution, not a solution in itself. --> <xsl:include href="i18n-en-GB-include.xslt"/> <!-- The C# namespace within which I shall generate controllers --> <xsl:param name="controllerns" select="Unset"/> <!-- The C# namespace used by the entities for this project --> <xsl:param name="entityns" select="Unset"/> <!-- Whether to authenticate at application or at database layer. If not 'Application', then 'Database'. --> <xsl:param name="authentication-layer" select="Application"/> <!-- the name and version of the product being built --> <xsl:param name="product-version" select="'Application Description Language Framework'"/> <!-- bug 1800 : the name of the Velocity layout to use --> <xsl:param name="layout-name" select="adl-default-layout"/> <!-- bug 1800 : the name of the Velocity rescue view to use --> <xsl:param name="rescue-name"/> <!-- bug 1800 : the name of the area (i.e. URL path part) to use --> <xsl:param name="area-name"/> <xsl:template match="adl:application"> <xsl:call-template name="collection-factory"/> <xsl:apply-templates select="adl:entity"/> </xsl:template> <xsl:template name="collection-factory"> /* ---- [ cut here: next file '<xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/>.auto.cs'] ---------------- */ //------------------------------------------------------------------ // // <xsl:value-of select="$product-version"/> // <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller.auto.cs')"/> // // (c) 2007 Cygnet Solutions Ltd // // Automatically generated abstract super class for controllers for the // <xsl:value-of select="/adl:application/@name"/> application; generated using // adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.31 $', 10)"/> // // This file is automatically generated; DO NOT EDIT IT. // //------------------------------------------------------------------ using System; using System.Data; using System.Collections.Generic; using NHibernate; using NHibernate.Expression; using Cygnet.Web.Controllers; using <xsl:value-of select="$entityns"/>; namespace <xsl:value-of select="$controllerns"/> { /// <summary> /// Automatically generated abstract super class for controllers for the /// <xsl:value-of select="/adl:application/@name"/> application /// /// DO NOT EDIT THIS FILE! /// </summary> public abstract partial class <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/> : BaseController { <xsl:for-each select="//adl:entity"> /// <summary> /// Return a list of all instances of <xsl:value-of select="@name"/> for use in menus, etc; /// </summary> protected IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> <xsl:value-of select="concat( 'FetchAll', @name)"/>( ISession hibernator) { return hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)) <xsl:for-each select="descendant::adl:property[@distinct='user']"> .AddOrder( <xsl:value-of select="concat('new Order( "', @name, '", true)')"/>) </xsl:for-each> .SetCacheable( true) .SetCacheRegion( "<xsl:value-of select="/adl:application/@name"/>") .List<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); } </xsl:for-each> } } </xsl:template> <!-- Don't bother generating anything for foreign entities --> <xsl:template match="adl:entity[@foreign='true']"/> <xsl:template match="adl:entity"> <xsl:comment>Not generating controller for entity <xsl:value-of select="@name"/>, as it has no forms, pages or lists. </xsl:comment> </xsl:template> <xsl:template match="adl:entity[adl:form|adl:page|adl:list]"> /* ---- [ cut here: next file '<xsl:value-of select="@name"/>Controller.auto.cs'] ---------------- */ //------------------------------------------------------------------ // // <xsl:value-of select="$product-version"/> // <xsl:value-of select="@name"/>Controller.auto.cs // // (c) 2007 Cygnet Solutions Ltd // // Controller for auto-generated forms for editing <xsl:value-of select="@name"/>s // Automatically generated from application description using // adl2controllerclasses.xslt version <xsl:value-of select="substring( '$Revision: 1.31 $', 10)"/> // // This file is automatically generated; DO NOT EDIT IT. // //------------------------------------------------------------------ using System; using System.Data; using System.Collections.Generic; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using Castle.MonoRail.Framework.Helpers; using Cygnet.Exceptions; using Cygnet.Web.Helpers; using Cygnet.Web.Controllers; using Cygnet.Web.SmartControls; using NHibernate; using NHibernate.Expression; using Castle.MonoRail.Framework; using Iesi.Collections.Generic; using <xsl:value-of select="$entityns"/>; namespace <xsl:value-of select="$controllerns"/> { /// <summary> /// Automatically generated partial controller class following 'thin controller' /// strategy, for entity <xsl:value-of select="@name"/>. Note that part of this /// class may be defined in a separate file called /// <xsl:value-of select="@name"/>Controller.manual.cs, q.v. /// /// DO NOT EDIT THIS FILE! /// </summary> [ <xsl:if test="$layout-name"> Layout("<xsl:value-of select="$layout-name"/>"), </xsl:if> <xsl:if test="$rescue-name"> Rescue("<xsl:value-of select="$rescue-name"/>"), </xsl:if> ControllerDetails("<xsl:value-of select="@name"/>", Area = "<xsl:value-of select="$area-name"/>"), Helper(typeof(<xsl:value-of select="concat( @name, 'FieldHelper')"/>), "<xsl:value-of select="concat( @name, 'FieldHelper')"/>") ] public partial class <xsl:value-of select="concat( @name, 'Controller')"/> : <xsl:value-of select="concat( 'Abstract', /adl:application/@name, 'Controller')"/> { /* The SmartFormHelper stuff in generated controller classes does not yet work. There is some * hope that in future it will offer definite benefits and in the mean time it is doing no harm. * However if you are looking for bugs look elsewhere - this is not currently used */ protected class <xsl:value-of select="concat( @name, 'FieldHelper')"/> : SmartFormHelper { public <xsl:value-of select="concat( @name, 'FieldHelper')"/>() { <xsl:for-each select="descendant::adl:property[@type='entity']"> <xsl:variable name="entityname" select="@entity"/> <xsl:variable name="entity" select="//adl:entity[@name=$entityname]"/> <xsl:choose> <xsl:when test="$entity/@foreign='true'"> /* Entity <xsl:value-of select="$entityname"/> is foreign..? */ <xsl:variable name="foreignkey" select="$entity/adl:key/adl:property[position()=1]/@name"/> Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", new TypeMenuControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "<xsl:value-of select="$foreignkey"/>","<xsl:value-of select="$foreignkey"/>")); </xsl:when> <xsl:otherwise> Register<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>( "", EntityMenuControl<<xsl:value-of select="concat( $entityns, '.', $entityname)"/>>.Instance); </xsl:otherwise> </xsl:choose> </xsl:for-each> } } <xsl:if test="adl:property[@type='message']"> /// <summary> /// Temporary hack to sort a problem with uninitialised messages /// </summary> public void fixupMessages() { ISession hibernator = NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">Session[ NHibernateHelper.USERTOKEN], Session[NHibernateHelper.PASSTOKEN]</xsl:if>); ICollection<<xsl:value-of select="concat($entityns, '.', @name)"/>> instances = hibernator.CreateCriteria( typeof( <xsl:value-of select="concat($entityns, '.', @name)"/>)) .List<<xsl:value-of select="concat($entityns, '.', @name)"/>>(); foreach ( <xsl:value-of select="concat($entityns, '.', @name)"/> instance in instances) { <xsl:for-each select="adl:property[@type='message']"> if ( <xsl:value-of select="concat( 'instance.', @name)"/> == null || <xsl:value-of select="concat( 'instance.', @name, '.MessageId')"/> == 0 ){ <xsl:value-of select="concat( 'instance.', @name)"/> = new Message(); hibernator.Save( <xsl:value-of select="concat( 'instance.', @name)"/>); } </xsl:for-each> hibernator.Save( instance); } hibernator.Flush(); <xsl:if test="adl:list[@name='list']"> list(); </xsl:if> } </xsl:if> <xsl:if test="adl:form"> <!-- unless there's at least one form, we won't generate a 'store' method --> /// <summary> /// Store the record represented by the parameters passed in an HTTP service /// Without Id -> it's new, I create a new persistent object; /// With Id -> it's existing, I update the existing persistent object. /// NOTE: Should only be called from a handler for method 'POST', never 'GET'. /// </summary> private void Store() { ISession hibernator = NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">Session[ NHibernateHelper.USERTOKEN], Session[NHibernateHelper.PASSTOKEN]</xsl:if>); List<string> messages = new List<string>(); /* A 'newborn' instance can be updated even if the current user doesn't have * update permissions, seeing that we use an update operation to set the * field values and save the entity. */ Boolean isnewborn = false; /* the instance (record) of type <xsl:value-of select="@name"/> we're dealing with */ <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; try { <xsl:if test="adl:property[@distinct='system' or @distinct='all']"> /* a criteria object to use in distinctness checks */ ICriteria matchCriteria = null; </xsl:if> record = FetchRecord( hibernator); <xsl:apply-templates select="descendant::adl:property"/> if ( HasNoErrors()) { if ( record == null) { /* it seems to be new, create persistent object - if the user is permitted to */ AssertUserCanCreate(); try { record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(<xsl:for-each select="adl:key/adl:property"> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$basetype='integer'">Int32.Parse( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])</xsl:when> <xsl:when test="$basetype='entity'"> <!-- Maybe TODO: this doesn't work recursively - if an entity has a key which is an entity and the key of that entity is an entity, you're on your own, mate! --> <xsl:variable name="keyentity" select="@entity"/> <xsl:variable name="keyenttype"> <xsl:call-template name="primary-key-csharp-type"> <xsl:with-param name="entity" select="//adl:entity[@name=$keyentity]"/> </xsl:call-template> </xsl:variable> hibernator.CreateCriteria( typeof( <xsl:value-of select="concat( $entityns, '.', $keyentity)"/>)) .Add(Expression.Eq( "<xsl:value-of select="//adl:entity[@name=$keyentity]/adl:key/adl:property[position()=1]/@name"/>",<xsl:choose> <xsl:when test="$keyenttype = 'int'">Int32.Parse( Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"])</xsl:when> <xsl:otherwise>Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"]</xsl:otherwise> </xsl:choose>)) .UniqueResult<<xsl:value-of select="concat( $entityns, '.', $keyentity)"/>>()</xsl:when> <xsl:otherwise>Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]</xsl:otherwise> </xsl:choose> <xsl:choose> <xsl:when test="position() = last()"/> <xsl:otherwise>, </xsl:otherwise> </xsl:choose> </xsl:for-each>); } catch ( FormatException) { /* failed to parse a number - not wholly unexpected, since it's most likely * that an empty string was passed in */ record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); } catch ( NullReferenceException) { /* again, probably more normal than otherwise */ record = new <xsl:value-of select="concat($entityns, '.', @name)"/>(); } messages.Add( "New <xsl:value-of select="@name"/> record created"); isnewborn = true; } if ( record != null) { /* a transaction to ensure our database operations are atomic */ ITransaction tx = null; if ( ! isnewborn) { /* isnewborn cannot be true unless we've already checked user can create * so no need to do it again here */ AssertUserCanUpdate(); } try { /* begin our atomic transaction */ tx = hibernator.BeginTransaction(); /* actually update the record */ BindObjectInstance( record, ParamStore.Form, "instance"); <xsl:if test="descendant::adl:property[@type='message']"> /* there is at least one slot whose value is an internationalised message; * if these have yet to be initialised they must be handled specially */ Locale locale = GetBestLocaleForUser(); <xsl:for-each select="descendant::adl:property[@type='message']"> if ( ! String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'i18n.instance.', @name)"/>"])){ /* there's an uninitialised message for this slot */ Message mess = record.<xsl:value-of select="@name"/>; if ( mess == null) { mess = new Message(); } hibernator.Save( mess); Translation trans = mess.GetTranslationObject( locale, hibernator); if ( trans == null) { trans = new Translation( mess, locale); } trans.MessageText = Form["<xsl:value-of select="concat( 'i18n.instance.', @name)"/>"]; record.<xsl:value-of select="@name"/> = mess; hibernator.Save( trans); } </xsl:for-each> </xsl:if> <xsl:for-each select="descendant::adl:property[@type='entity']"> /* for properties of type 'entity', it should not be necessary to do anything * special - BindObjectInstance /should/ do it all. Unfortunately it sometimes * doesn't, and I haven't yet characterised why not. */ <xsl:variable name="entityname" select="@entity"/> <xsl:choose> <xsl:when test="//adl:entity[@name=$entityname]"> if ( ! String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { record.<xsl:value-of select="@name"/> = <xsl:call-template name="fetch-property-instance"> <xsl:with-param name="property" select="."/> <xsl:with-param name="valuename" select="@name"/> </xsl:call-template>; } </xsl:when> <xsl:otherwise> <xsl:message terminate="yes"> ADL: ERROR: Could not fix up value of <xsl:value-of select="@name "/>, because no entity was found called <xsl:value-of select="$entityname"/> </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:for-each> <xsl:for-each select="property[@type='link']"> /* to update a link table which has no other data than the near and far keys, it is * sufficient to smash the existing values and create new ones. It's also a lot easier! */ string[] <xsl:value-of select="concat(@name, 'Values')"/> = Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>"); if ( <xsl:value-of select="concat(@name, 'Values')"/> != null) { /* update the linking table for my <xsl:value-of select="@name"/>; first smash the old values */ if ( <xsl:value-of select="concat( 'record.', @name)"/> != null) { <xsl:value-of select="concat( 'record.', @name)"/>.Clear(); } else { <xsl:value-of select="concat( 'record.', @name)"/> = new HashedSet<<xsl:value-of select="@entity"/>>(); } /* then reinstate the values from the indexes passed */ foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) { <xsl:value-of select="concat( 'record.', @name)"/>.Add( hibernator.CreateCriteria(typeof(<xsl:value-of select="@entity"/>)) .Add(Expression.Eq("<xsl:value-of select="@entity"/>Id", index)) .UniqueResult<<xsl:value-of select="$entityns"/>.<xsl:value-of select="@entity"/>>()); } } </xsl:for-each> <xsl:for-each select="descendant::adl:property[@type='list']"> /* with a list we cannot just smash the old values! Instead we need to check * each one and exclude it if no longer required */ if ( Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>") != null) { string[] <xsl:value-of select="concat(@name, 'Values')"/> = Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>"); /* updating <xsl:value-of select="@name"/> child records; first remove any not on the submitted list */ foreach ( <xsl:value-of select="@entity"/> item in record.<xsl:value-of select="@name"/>) { String itemId = item.KeyString; bool found = false; foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) { if ( index.Equals( itemId)) { found = true; break; } } /* foreach ( string index... */ if ( ! found) { record.<xsl:value-of select="@name"/>.Remove( item); } } /* foreach ( <xsl:value-of select="@entity"/> item ... */ /* then add any on the included list which are not already members */ foreach ( string index in <xsl:value-of select="concat(@name, 'Values')"/>) { <xsl:variable name="entityname" select="@entity"/> <xsl:value-of select="@entity"/> item = hibernator.CreateCriteria(typeof(<xsl:value-of select="@entity"/>)) .Add(Expression.Eq("<xsl:value-of select="@entity"/>Id", index)) .UniqueResult<<xsl:value-of select="$entityns"/>.<xsl:value-of select="@entity"/>>(); if ( ! record.<xsl:value-of select="@name"/>.Contains( item)) { record.<xsl:value-of select="@name"/>.Add( item); } } /* foreach ( string index... */ } /* if ( Form.GetValues( "<xsl:value-of select="concat( 'instance.', @name)"/>") != null) */ </xsl:for-each> /* write the record to the database, in order to guarantee we have a valid key */ hibernator.Save(record); hibernator.Flush(); tx.Commit(); messages.Add( "<xsl:call-template name="i18n-record-saved"/>"); } /* try actually commit */ catch ( Exception any) { tx.Rollback(); messages.Add( "<xsl:call-template name="i18n-record-not-saved"/>"); throw any; } } /* if ( record != null) */ else { throw new ApplicationException( String.Format( "<xsl:call-template name="i18n-record-not-found"> <xsl:with-param name="entity-name" select="@name"/> </xsl:call-template>")); } } /* if ( HasNoErrors()) */ } /* try */ catch ( DataSuitabilityException dse) { AddError( dse); } catch ( ApplicationException axe) { AddError( axe.Message); } if ( ! HasNoErrors()) { /* the session may be polluted; create a new session */ NHibernateHelper.CloseSession(); hibernator = NHibernateHelper.GetCurrentSession(<xsl:if test="$authentication-layer = 'Database'"> Session[ NHibernateHelper.USERTOKEN], Session[NHibernateHelper.PASSTOKEN]</xsl:if>); record = FetchRecord( hibernator); } /* if ( ! HasNoErrors()) */ TypedPropertyBag = new { <xsl:call-template name="formmenus"> <xsl:with-param name="form" select="adl:form[position()=1]"/> </xsl:call-template> <xsl:if test="$authentication-layer = 'Database'"> username = Session[ NHibernateHelper.USERTOKEN], </xsl:if> messages = messages, instance = record }; RenderViewWithFailover("<xsl:value-of select="concat( adl:form[position()=1]/@name, '.vm')"/>", "<xsl:value-of select="concat( adl:form[position()=1]/@name, '.auto.vm')"/>"); } </xsl:if> <xsl:if test="adl:form"> <!-- unless there's at least one form, we won't generate a 'delete' method --> /// <summary> /// Actually delete the selected record /// </summary> [AccessibleThrough(Verb.Post)] public void Delete() { AssertUserCanDelete(); ISession hibernator = NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">Session[ NHibernateHelper.USERTOKEN], Session[NHibernateHelper.PASSTOKEN]</xsl:if>); if ( "true".Equals( Params["reallydelete"])) { <xsl:value-of select="concat($entityns, '.', @name)"/> record = FetchRecord( hibernator); if ( record != null) { hibernator.Delete( record); hibernator.Flush(); } else { throw new ApplicationException( "No such record?"); } } <xsl:choose> <xsl:when test="adl:list"> Redirect( "<xsl:value-of select="concat(adl:list[position()=1]/@name, '.rails')"/>"); </xsl:when> <xsl:otherwise> Redirect( FormsAuthentication.DefaultUrl); </xsl:otherwise> </xsl:choose> } </xsl:if> <xsl:apply-templates select="adl:form"/> <xsl:if test="adl:list"> <xsl:variable name="listname" select="adl:list[position()=1]/@name"/> <xsl:apply-templates select="adl:list"/> /// <summary> /// list all instances of this entity to allow the user to select one for editing /// this method invokes the default list view - which is probably what you want unless /// you've a special reason for doing something different /// </summary> public void InternalShowList() { InternalShowList( "<xsl:value-of select="$listname"/>"); } /// <summary> /// list all instances of this entity to allow the user to select one for editing /// </summary> /// <param name="view">The name of the list view to show</param> public void InternalShowList( String view) { AssertUserCanRead(); ISession hibernator = NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">Session[ NHibernateHelper.USERTOKEN], Session[NHibernateHelper.PASSTOKEN]</xsl:if>); ICriteria search = hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)); <xsl:for-each select="adl:property"> <xsl:variable name="base-type"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="@type='message'"> <!-- search.Add( Expression.Like( "<xsl:value-of select="@name"/>.LocalText", "%"+Params["<xsl:value-of select="concat( 'search_', @name)"/>"]+"%")); --> </xsl:when> <xsl:when test="$base-type = 'integer'"> if ( ! String.IsNullOrEmpty( Params[ "<xsl:value-of select="concat( 'search_', @name)"/>"])) { search.Add( Expression.Eq( "<xsl:value-of select="@name"/>", Int32.Parse( Params["<xsl:value-of select="concat( 'search_', @name)"/>"]))); } </xsl:when> <xsl:when test="$base-type = 'real'"> if ( ! String.IsNullOrEmpty( Params[ "<xsl:value-of select="concat( 'search_', @name)"/>"])) { search.Add( Expression.Eq( "<xsl:value-of select="@name"/>", Int32.Parse( Params["<xsl:value-of select="concat( 'search_', @name)"/>"]))); } </xsl:when> <xsl:when test="$base-type = 'money'"> if ( ! String.IsNullOrEmpty( Params[ "<xsl:value-of select="concat( 'search_', @name)"/>"])) { search.Add( Expression.Eq( "<xsl:value-of select="@name"/>", Int32.Parse( Params["<xsl:value-of select="concat( 'search_', @name)"/>"]))); } </xsl:when> <!-- xsl:when test="$base-type = 'entity'"> search.Add( Expression.Like( "<xsl:value-of select="@name"/>.UserIdentifier", "%"+Params["<xsl:value-of select="concat( 'search_', @name)"/>"]+"%")); </xsl:when doesn't work --> <xsl:otherwise> if ( ! String.IsNullOrEmpty( Params[ "<xsl:value-of select="concat( 'search_', @name)"/>"])) { search.Add( Expression.Like( "<xsl:value-of select="@name"/>", "%"+Params["<xsl:value-of select="concat( 'search_', @name)"/>"]+"%")); } </xsl:otherwise> </xsl:choose> </xsl:for-each> <xsl:for-each select="adl:property[@distinct='user' or @distinct='all']"> search.AddOrder(<xsl:value-of select="concat( ' new Order( "', @name, '", true)')"/>); </xsl:for-each> IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> instances = search.List<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); <xsl:if test="$authentication-layer = 'Database'"> PropertyBag["username"] = Session[ NHibernateHelper.USERTOKEN]; </xsl:if> PropertyBag["instances"] = PaginationHelper.CreatePagination( this, instances, 25); RenderViewWithFailover(view + ".vm", view + ".auto.vm"); } </xsl:if> /// <summary> /// Fetch the record represented by the values in the current Form /// </summary> protected <xsl:value-of select="concat($entityns, '.', @name)"/> FetchRecord(ISession hibernator) { /* the instance (record) of type <xsl:value-of select="@name"/> we're dealing with */ <xsl:value-of select="concat($entityns, '.', @name)"/> record = null; /* whether we have valid values for all the key fields */ bool allkeys = true; /* check whether values for all key slots have been passed in; if so, we're probably dealing with an * existing record */ <xsl:for-each select="adl:key/adl:property"> if ( String.IsNullOrEmpty( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { allkeys = false; } else if ( "<xsl:value-of select="concat('$instance.', @name)"/>".Equals( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])) { /* nasty artefact of NVelocity forms - default 'null value' is dollar followed by fieldname */ allkeys = false; } </xsl:for-each> if ( allkeys){ /* it's (probably) existing, retrieve it */ record = hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', @name)"/>)) <xsl:for-each select="adl:key/adl:property"> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> .Add( Expression.Eq( "<xsl:value-of select="@name"/>", <xsl:choose> <xsl:when test="$basetype='integer'"> Int32.Parse( Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"]) </xsl:when> <xsl:when test="$basetype='entity'"> <!-- Maybe TODO: this doesn't work recursively - if an entity has a key which is an entity and the key of that entity is an entity, you're on your own, mate! --> <xsl:variable name="keyentity" select="@entity"/> <xsl:variable name="keyenttype"> <xsl:call-template name="primary-key-csharp-type"> <xsl:with-param name="entity" select="//adl:entity[@name=$keyentity]"/> </xsl:call-template> </xsl:variable> hibernator.CreateCriteria( typeof( <xsl:value-of select="$keyenttype"/>)) .Add(Expression.Eq( "<xsl:value-of select="//adl:entity[@name=$keyentity]/adl:key/adl:property[position()=1]/@name"/>",<xsl:choose> <xsl:when test="$keyenttype = 'int'"> Int32.Parse( Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"]) </xsl:when> <xsl:otherwise> Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"] </xsl:otherwise> </xsl:choose>)) .UniqueResult<<xsl:value-of select="$keyenttype"/>>() </xsl:when> <xsl:otherwise> Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>"] </xsl:otherwise> </xsl:choose>)) </xsl:for-each> .UniqueResult<<xsl:value-of select="concat( $entityns, '.', @name)"/>>(); } return record; } } } /* ---- [ cut here: next file 'junk'] ------------------------- */ </xsl:template> <xsl:template match="adl:property"> <xsl:if test="@required='true'"> if ( String.IsNullOrEmpty( Form[ "<xsl:value-of select="concat( 'instance.', @name)"/>" ])) { AddError( <xsl:choose> <xsl:when test="adl:ifmissing[@locale=$locale]"> <xsl:apply-templates select="adl:ifmissing[@locale=$locale]"/> </xsl:when> <xsl:otherwise> "<xsl:call-template name="i18n-value-required"> <xsl:with-param name="property-name" select="@name"/> </xsl:call-template>" </xsl:otherwise> </xsl:choose>); } </xsl:if> <xsl:if test="@distinct='system' or @distinct='all'"> <xsl:call-template name="check-property-value-distinct"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:if> </xsl:template> <xsl:template match="adl:ifmissing"> "<xsl:value-of select="normalize-space(.)"/>" </xsl:template> <xsl:template match="adl:form"> /// <summary> /// Handle the submission of the form named <xsl:value-of select="@name"/> /// </summary> [AccessibleThrough(Verb.Post)] public void <xsl:value-of select="concat( @name, 'SubmitHandler')"/>( ) { string command = Form[ "command"]; if ( command == null) { throw new Exception( "<xsl:call-template name="i18n-command-not-found"/>"); } else <xsl:for-each select=".//verb"> if ( command.Equals( "<xsl:value-of select="@verb"/>")) { /* NOTE: You must write an implementation of this verb in a * manually maintained partial class file for this class */ <xsl:value-of select="@verb"/>(); } else </xsl:for-each> if ( command.Equals( "delete")) { ISession hibernator = NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">Session[ NHibernateHelper.USERTOKEN], Session[NHibernateHelper.PASSTOKEN]</xsl:if>); <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record = FetchRecord( hibernator); TypedPropertyBag = new { <xsl:if test="$authentication-layer = 'Database'"> username = Session[ NHibernateHelper.USERTOKEN], </xsl:if> instance = record }; RenderViewWithFailover( "maybedelete.vm", "maybedelete.auto.vm"); } else if ( command.Equals( "store")) { Store(); } else { throw new Exception( String.Format("<xsl:call-template name="i18n-command-not-found"> <xsl:with-param name="command" select="'{0}'"/> </xsl:call-template>", command)); } } /// <summary> /// Show the form named <xsl:value-of select="@name"/>, with no content /// </summary> [AccessibleThrough(Verb.Get)] public void <xsl:value-of select="@name"/>( ) { AssertUserCanRead(); /* we don't actually instantiate this local variable; it exists to that * TypedPropertyBag can do introspection to infer property types */ <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record = null; ISession hibernator = NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">Session[ NHibernateHelper.USERTOKEN], Session[NHibernateHelper.PASSTOKEN]</xsl:if>); TypedPropertyBag = new { <xsl:if test="$authentication-layer = 'Database'"> username = Session[ NHibernateHelper.USERTOKEN], </xsl:if> <xsl:call-template name="formmenus"> <xsl:with-param name="form" select="."/> </xsl:call-template> instance = record }; RenderViewWithFailover("<xsl:value-of select="concat( @name, '.vm')"/>", "<xsl:value-of select="concat( @name, '.auto.vm')"/>"); } <xsl:if test="ancestor::adl:entity/adl:key/adl:property[@type='entity']"> <!-- if there's a key which is an entity, the actual entity can't be passed in. So what will be passed in is the key value, from which we can find the entity --> /// <summary> /// Show the form named <xsl:value-of select="@name"/>, containing the indicated record. As /// the primary key of the record is itself an entity, we need to first fetch that entity /// </summary> <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> <xsl:choose> <xsl:when test="@type='entity'"> /// <param name="<xsl:value-of select="concat( @name, '_Value')"/>">the key value of the key value of the record to show</param> </xsl:when> <xsl:otherwise> /// <param name="<xsl:value-of select="@name"/>">the key value of the record to show</param> </xsl:otherwise> </xsl:choose> </xsl:for-each> [AccessibleThrough(Verb.Get)] public void <xsl:value-of select="@name"/>( <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> <xsl:choose> <xsl:when test="@type='entity'"> <xsl:call-template name="csharp-base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> <xsl:value-of select="concat( ' ', @name, '_Value')"/> </xsl:when> <xsl:otherwise> <xsl:call-template name="csharp-base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> <xsl:value-of select="concat( ' ', @name)"/> </xsl:otherwise> </xsl:choose> <xsl:if test="not( position() = last())">,</xsl:if> </xsl:for-each>) { ISession hibernator = NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">Session[ NHibernateHelper.USERTOKEN], Session[NHibernateHelper.PASSTOKEN]</xsl:if>); this.<xsl:value-of select="@name"/>( <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> <xsl:choose> <xsl:when test="@type='entity'"> <xsl:variable name="entity" select="@entity"/> hibernator.CreateCriteria(typeof(<xsl:value-of select="concat($entityns, '.', @entity)"/>)) .Add( Expression.Eq( "<xsl:value-of select="//adl:entity[@name=$entity]/adl:key/adl:property[position()=1]/@name"/>", <xsl:value-of select="concat( @name, '_Value')"/>)) .UniqueResult<<xsl:value-of select="concat($entityns, '.', @entity)"/>>() </xsl:when> <xsl:otherwise> <xsl:value-of select="concat( ' ', @name)"/> </xsl:otherwise> </xsl:choose> <xsl:if test="not( position() = last())">,</xsl:if> </xsl:for-each>); } </xsl:if> /// <summary> /// Show the form named <xsl:value-of select="@name"/>, containing the indicated record /// </summary> <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> /// <param name="<xsl:value-of select="@name"/>">the key value of the record to show</param> </xsl:for-each> [AccessibleThrough(Verb.Get)] public void <xsl:value-of select="@name"/>( <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> <xsl:call-template name="csharp-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> <xsl:value-of select="concat( ' ', @name)"/> <xsl:if test="not( position() = last())">,</xsl:if> </xsl:for-each>) { ISession hibernator = NHibernateHelper.GetCurrentSession( <xsl:if test="$authentication-layer = 'Database'">Session[ NHibernateHelper.USERTOKEN], Session[NHibernateHelper.PASSTOKEN]</xsl:if>); <xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/> record = hibernator.CreateCriteria(typeof(<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>)) <xsl:for-each select="ancestor::adl:entity/adl:key/adl:property"> .Add(Expression.Eq("<xsl:value-of select="@name"/>", <xsl:value-of select="@name"/>)) </xsl:for-each> .UniqueResult<<xsl:value-of select="concat($entityns, '.', ancestor::adl:entity/@name)"/>>(); TypedPropertyBag = new { <xsl:if test="$authentication-layer = 'Database'"> username = Session[ NHibernateHelper.USERTOKEN], </xsl:if> <xsl:call-template name="formmenus"> <xsl:with-param name="form" select="."/> </xsl:call-template> instance = record }; RenderViewWithFailover("<xsl:value-of select="concat( @name, '.vm')"/>", "<xsl:value-of select="concat( @name, '.auto.vm')"/>"); } </xsl:template> <xsl:template match="adl:list"> /// <summary> /// list all instances of this entity to allow the user to select one /// this method invokes the named view. /// </summary> public void <xsl:value-of select="@name"/>() { InternalShowList( "<xsl:value-of select="@name"/>"); } </xsl:template> <xsl:template match="adl:documentation"> /* <xsl:apply-templates/> */ </xsl:template> <!-- for properties with @distinct='all' or @distinct='system', check that values are indeed distinct --> <xsl:template name="check-property-value-distinct"> <xsl:param name="property"/> <xsl:variable name="basetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$property/ancestor::adl:key and not( $property/ancestor::adl:entity/adl:key[position()=2])"> <!-- if I'm the property of a key field and it is the only key field of my entity then it is pointless trying to establish my distinctness --> </xsl:when> <xsl:when test="$property/@distinct = 'system' or $property/@distinct='all'"> /* <xsl:value-of select="$property/@name"/> should be distinct: check that it is */ matchCriteria = hibernator.CreateCriteria(typeof(<xsl:value-of select="$property/ancestor::adl:entity/@name"/>)); matchCriteria.Add(Expression.Eq("<xsl:value-of select="$property/@name"/>", <xsl:choose> <xsl:when test="$basetype='string'">Form["<xsl:value-of select="concat('instance.', $property/@name)"/>"]</xsl:when> <xsl:when test="$basetype='integer'">Int32.Parse( Form["<xsl:value-of select="concat('instance.', $property/@name)"/>"])</xsl:when> <xsl:when test="$basetype='entity'"> <xsl:call-template name="fetch-property-instance"> <xsl:with-param name="property" select="."/> <xsl:with-param name="valuename" select="adl:property[position()=1]/@name"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:message terminate="yes"> ADL: ERROR: don't yet know how to do distinctness checks for properties with base type <xsl:value-of select="$basetype"/> </xsl:message> </xsl:otherwise> </xsl:choose>)); if ( record != null) { /* i.e. we do have values for each of our key fields... */ <xsl:for-each select="$property/ancestor::adl:entity/adl:key/adl:property[position()=1]"> <xsl:variable name="keybasetype"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:variable> matchCriteria.Add(Expression.Not(Expression.Eq("<xsl:value-of select="@name"/>",<xsl:choose> <xsl:when test="$keybasetype='entity'"> <xsl:call-template name="fetch-property-instance"> <!-- recurse --> <xsl:with-param name="property" select="."/> <xsl:with-param name="valuename" select="@name"/> </xsl:call-template> </xsl:when> <xsl:when test="$keybasetype='integer'">Int32.Parse( Form["<xsl:value-of select="concat( 'instance.', @name)"/>"])</xsl:when> <xsl:otherwise>Form["<xsl:value-of select="concat( 'instance.', @name)"/>"]</xsl:otherwise> </xsl:choose>))); </xsl:for-each> } if ( matchCriteria.List<<xsl:value-of select="$property/ancestor::adl:entity/@name"/>>().Count > 0) { AddError( String.Format("There is already a {0} with the {1} '{2}'", "<xsl:value-of select="$property/ancestor::adl:entity/@name"/>", "<xsl:value-of select="$property/@name"/>", Form["<xsl:value-of select="concat('instance.', $property/@name)"/>"])); } </xsl:when> </xsl:choose> </xsl:template> <!-- produce all menus for a given form: harder, but more efficient --> <xsl:template name="formmenus"> <!-- an entity assumed to be of type adl:form --> <xsl:param name="form"/> <xsl:choose> <xsl:when test="$form/@properties = 'all'"> <xsl:call-template name="entitymenus"> <xsl:with-param name="entity" select="$form/ancestor::adl:entity"/> </xsl:call-template> </xsl:when> <xsl:otherwise> /* form menus */ <xsl:for-each select="$form//adl:field"> <xsl:variable name="propname" select="@property"/> <xsl:choose> <xsl:when test="parent::adl:auxlist"/> <xsl:when test="$form/ancestor::adl:entity/adl:property[@name=$propname and @type='entity']"> /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity/adl:property[@name=$propname]/@entity"/> to populate the select for <xsl:value-of select="$propname"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="$form/ancestor::adl:entity/adl:property[@name=$propname]"/> </xsl:call-template> </xsl:when> <xsl:when test="$form/ancestor::adl:entity/adl:property[@name=$propname and @type='link']"> /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity/adl:property[@name=$propname]/@entity"/> to populate the LHS of the shuffle for <xsl:value-of select="$propname"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="$form/ancestor::adl:entity/adl:property[@name=$propname]"/> </xsl:call-template> </xsl:when> <xsl:when test="$form/ancestor::adl:entity/adl:property[@name=$propname and @type='list']"> /* produce a list of <xsl:value-of select="$form/ancestor::adl:entity/adl:property[@name=$propname]/@entity"/> to populate the multi-select for <xsl:value-of select="@name"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="$form/ancestor::adl:entity/adl:property[@name=$propname]"/> </xsl:call-template> </xsl:when> </xsl:choose> </xsl:for-each> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- produce all menus for a given entity: easier, but less efficient --> <xsl:template name="entitymenus"> <xsl:param name="entity"/> /* there's no way I can find of producing a set of just those entities * we'll need menus for. So we set up variables for all the menus we might * need, and then only instantiate those we do need. */ <!-- xsl:for-each select="//adl:entity"> IList<<xsl:value-of select="concat( $entityns, '.', @name)"/>> <xsl:value-of select="concat( 'all', @name)"/> = null; </xsl:for-each --> <xsl:for-each select="$entity//adl:property[@type='entity']"> <!-- $entity//adl:property because it is possible to have type='entity' in the key --> <xsl:call-template name="menu"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:for-each> <xsl:for-each select="$entity/adl:property[@type='link']"> <!-- $entity/adl:property because it is not possible to have type='link' in the key --> /* produce a list of <xsl:value-of select="@entity"/> to populate the LHS of the shuffle for <xsl:value-of select="@name"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:for-each> <xsl:for-each select="$entity/adl:property[@type='list']"> /* produce a list of <xsl:value-of select="@entity"/> to populate the multi-select for <xsl:value-of select="@name"/> */ <xsl:call-template name="menu"> <xsl:with-param name="property" select="."/> </xsl:call-template> </xsl:for-each> </xsl:template> <xsl:template match="adl:key"> <!-- the key shouldn't be matched directly - at least, not in this implementation --> </xsl:template> <xsl:template name="menu"> <xsl:param name="property"/> <xsl:variable name="entity" select="//adl:entity[@name=$property/@entity]"/> <xsl:value-of select="concat('all_', $property/@name)"/> = <xsl:value-of select="concat( 'FetchAll', $entity/@name)"/>( NHibernateHelper.GetCurrentSession()), </xsl:template> <xsl:template name="primary-key-csharp-type"> <xsl:param name="entity"/> <xsl:if test="not( $entity)"> <xsl:message terminate="yes"> ADL: ERROR: No entity passed to template primary-key-csharp-type </xsl:message> </xsl:if> <xsl:if test="not($entity/adl:key/adl:property)"> <xsl:message terminate="no"> ADL: WARNING: entity '<xsl:value-of select="$entity/@name"/>' has no primary key. You will have to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> </xsl:message> </xsl:if> <xsl:call-template name="csharp-type"> <xsl:with-param name="property" select="$entity/adl:key/adl:property[ position() = 1]"/> <xsl:with-param name="entityns" select="$entityns"/> </xsl:call-template> </xsl:template> <xsl:template name="primary-key-name"> <!-- return the name of the primary key of the entity with this name --> <xsl:param name="entity"/> <xsl:if test="not($entity/adl:key)"> <xsl:message terminate="yes"> ADL: ERROR: No key for entity: <xsl:value-of select="$entity/@name"/> </xsl:message> </xsl:if> <xsl:choose> <xsl:when test="$entity/adl:key/adl:property[position()=2]"> <xsl:message terminate="no"> ADL: WARNING: Entity <xsl:value-of select="$entity/@name"/> has a composite primary key. You will need to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> </xsl:message> <xsl:value-of select="$entity/adl:key/adl:property[position()=1]/@name"/> </xsl:when> <xsl:when test="$entity/adl:key/adl:property"> <xsl:value-of select="$entity/adl:key/adl:property[position()=1]/@name"/> </xsl:when> <xsl:otherwise> <xsl:message terminate="no"> ADL: WARNING: Entity <xsl:value-of select="$entity/@name"/> has no primary key. You will need to manually edit <xsl:value-of select="concat( $entity/@name, 'Controller.auto.cs')"/> </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- argument: a property returns 'true' if that property is of a type which makes it searchable, else 'false'. See also how search fields are generated in adl2views.xsl --> <xsl:template name="is-searchable"> <xsl:param name="property"/> <xsl:variable name="base-type"> <xsl:call-template name="base-type"> <xsl:with-param name="property" select="$property"/> </xsl:call-template> </xsl:variable> <xsl:choose> <xsl:when test="$base-type='string'">true</xsl:when> <xsl:when test="$base-type='integer'">true</xsl:when> <xsl:when test="$base-type='real'">true</xsl:when> <xsl:when test="$base-type='money'">true</xsl:when> <xsl:when test="$base-type='text'">true</xsl:when> <xsl:when test="$base-type='entity'">true</xsl:when> <xsl:otherwise>false</xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template name="fetch-property-instance"> <!-- the property for which the instance is sought; it is assumed that the property passed has type 'entity' --> <xsl:param name="property"/> <!-- the name of the value in the returned values from which the instance must be resolved --> <xsl:param name="valuename"/> <xsl:if test="not( $property/@type='entity')"> <xsl:message terminate="yes"> ADL: ERROR: property passed to fetch-property-instance whose type is not 'entity' </xsl:message> </xsl:if> hibernator.CreateCriteria(typeof(<xsl:value-of select="concat( $entityns, '.', $property/@entity)"/>)) <xsl:for-each select="//adl:entity[@name=$property/@entity]/adl:key/adl:property"> .Add(Expression.Eq("<xsl:value-of select="@name"/>",<xsl:choose> <xsl:when test="@type='entity'"> <xsl:call-template name="fetch-property-instance"> <!-- recurse --> <xsl:with-param name="property" select="."/> <xsl:with-param name="valuename" select="$valuename"/> </xsl:call-template> </xsl:when> <xsl:when test="@type='integer'">Int32.Parse( Form["<xsl:value-of select="concat( 'instance.', $valuename)"/>"])</xsl:when> <xsl:otherwise>Form["<xsl:value-of select="concat( 'instance.', $valuename)"/>"]</xsl:otherwise> </xsl:choose>)) </xsl:for-each> .UniqueResult<<xsl:value-of select="concat( $entityns, '.', @entity)"/>>() </xsl:template> </xsl:stylesheet>