Create a bind property for a preside object


#1

for page types which have a hierarchical relationship, i think it would be useful if you could bind values to them. I’m thinking specifically for parent/child relationships but maybe it should be expanded beyond this.

An example would be:

/Country/England/London.html
/Country/England/Skipton.html
/Country/France/Paris.html

If these are implemented as a regular preside object, with a custom route handler to build the url, then when you add Skipton, you would simply select England as the country.

For a page-type however, it would be useful if when i add the child page Skipton to England, that the country field for the city page-type is initially set and bound to the parent id, ie, England, rather than have to select it when the hierarchy already known.

Here is an example of how these page types could be defined:

country.cfc

component { }

city.cfc

component  allowedParentPageTypes="country" {
   property name="country" relationship="many-to-one"  relatedTo="country" bind="parent.id" 
}

I realise that you can infer the city’s country using the hierarchy, however it complicates simple queries and making the field searchable. So i propose the City page-type would have a column called country on its table, and therefore you can do a simple selectData to find all cities in England.

Thoughts?


#2

I like it. It would need then to have some kind of watcher for when the source field changes. i.e. you change the parent page, so the ‘country’ field would need updating accordingly.

I’m not sure about the language of ‘binding’ (though I’m not sure I don’t like either ;). But I like the concept.


#3

Thinking a little further around the idea of generated fields based on other fields, perhaps generatedFrom and generator attributes could work.

Some examples:

component  allowedParentPageTypes="country" {
   property name="country" relationship="many-to-one"  relatedTo="country" generatedFrom="page.parent_page" generator="copy";
}

A field could be based on multiple other fields:

/**
 * @labelfield full_name
 *
 */
component {
    property name="first_name";
    property name="last_name";
    property name="title" relationship="many-to-one" relatedto="lookup_title";
    
    property name="full_name" generatedFrom="title.label,first_name,last_name" generator="method:generateFullName";

    public string function generateFullName( struct data={} ) { 
        return "#data[ 'title.label' ]# #data.first_name# #data.last_name#";
    }
}

In the case above, the generateFullName() function would be run, and the full_name field updated, when:

  • When record first added
  • Either the title, first_name or last_name fields changed
  • When the related record in lookup_title changed…

Another example, where we could simplify for common uses:

property name="expressions" type="string" dbtype="text"...;
property name="expressions_hash" generatedFrom="expressions" generator="hash" ...;

#4

Of course, we should look at what other frameworks are doing :smirk:

From CF’s ORM:

formula: SQL to generate the value of the field in runtime queries... (a separate but v important requirement)
generated: never|insert|always
...

So, I think this could work:

// for PKs
generated=insert
generator=uuid

// for fields based on other fields
generated=always
generatedfrom=list,of,fields
generator=method:mycustommethod

// for fields based on another field with common usage patterns, e.g. hashing the generatedfrom field values
generated=always
generatedfrom=somefield
generator=hash

etc.


#5

Final thought for the night, the idea of watching related records for changes and updating generated fields sounds like a real recipe for disastrous performance. If we didn’t allow that, we could then force the use of formula for this kind of property. e.g.

property name="full_name" formula="Concat( title.label, Concat( ' ', Concat( person.first_name, Concat( ' ', person.last_name )  )  ))";

or

component  allowedParentPageTypes="country" {
   property name="country" formula="page.parent_page";
}

It would be helpful if the formula value could be something like "method:myFormulaGenerator" so that you could dynamically create the formula based on DB engine, etc.


#6

But then again, we could do this in the scenario you’re describing:

property name="country" ... generate="always" generator="copy" generateFrom="parent_page";

If parent_page is then present in the data for insertData() / updateData(), it will be updated (and it will if you’re using the edit/add page forms)


#7

We have implemented both formula and some cool generators in the upcoming 10.8.0 release. See:

https://presidecms.atlassian.net/browse/PRESIDECMS-817 (Formula fields)
https://presidecms.atlassian.net/browse/PRESIDECMS-754 (Generators)