filtering data with d2w
TRANSCRIPT
Filtering data with D2W Philippe Rabier - twitter.com/prabierSophiacom
What is the problem to solve?
Company
EOEntityA
EOEntityB
User
EOEntityC
• Use D2W
• Limit the visibility of the data
• Use conventions to name relationships (for example, any toOne relationship to Company entity, is called company)
• Minimize the code
• Be magic!
The Requirements
Feedback from You ’N Push
First Solution
Working at the editingContext level
modified fetchspec
notificationec factory ec
company
objectsWithFetchSpecification()
creates businessFP
fetchspec
How the qualifier is modified?
public void alterFetchSpecification(final NSNotification aNotification) { EOEditingContext ec = (EOEditingContext) aNotification.object(); if (shouldAddRestrictionQualifier) { Company aCompany = (NOClient) ec.userInfoForKey(NBEditingContextFactory.COMPANY_KEY); final EOFetchSpecification fs = (EOFetchSpecification) aNotification.userInfo().valueForKey(COEditingContext.FETCH_SPEC_KEY); if (aCompany != null && fs != null) { EOEntity aEntity = EOUtilities.entityNamed(ec, fs.entityName());
EOQualifier fsQualifier = fs.qualifier(); if (fsQualifier != null) { NSSet<String> keys = fsQualifier.allQualifierKeys(); for (String aKey : keys) { if (aKey.contains("company")) { shouldAddRestrictionQualifier = false; break; } } } if (shouldAddRestrictionQualifier) { EOQualifier aRestrictionQualifier = clientRestrictionQualifier(aEntity, aClient); if (aRestrictionQualifier != null) { if (fsQualifier != null) fsQualifier = new EOAndQualifier(new NSArray<EOQualifier>(new EOQualifier[] {fsQualifier, aRestrictionQualifier})); else fsQualifier = aRestrictionQualifier; fs.setQualifier(fsQualifier); } } } } }
How the qualifier is modified?
public EOQualifier companyRestrictionQualifier(final EOEntity entity, final Company company) {
EOQualifier aQualifier = null; if (entity.name().equals(Company.Keys.ENTITY_NAME)) aQualifier = new EOKeyValueQualifier(Company.Keys.NAME, EOQualifier.QualifierOperatorEqual, company.name()); else if (entity.relationshipNamed("company") != null) aQualifier = new EOKeyValueQualifier("company", EOQualifier.QualifierOperatorEqual, company); else if (entity.relationshipNamed("entityB") != null) aQualifier = new EOKeyValueQualifier("entityB.company", EOQualifier.QualifierOperatorEqual, client); else if (entity.relationshipNamed("entityC") != null) ...;
if (log.isDebugEnabled()) log.debug("method: qualifier: " + aQualifier); return aQualifier; }
It works great
but there is a little problem
it’s too low level
An Example of Problem
public void validateForSave() throws ValidationException { super.validateForSave(); ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.LOGIN); ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.EMAIL); }
public void validateForSave() throws ValidationException { super.validateForSave(); editingContext().setUserInfoForKey(Boolean.FALSE, NBEditingContextFactory.NO_RESTRICTION_QUAL_KEY); ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.LOGIN); ERXEOControlUtilities.validateUniquenessOf(this, NOUser.Keys.EMAIL); editingContext().setUserInfoForKey(Boolean.TRUE, NBEditingContextFactory.NO_RESTRICTION_QUAL_KEY); }
Second Solution
• Displaying a list
• Using a query component
• Using ERD2WEditToManyRelationship component
• Using ERD2WEditToOneRelationship component
When should we filter?
• Modify the NavigationController object
• Change the data source
Displaying a list
public WOComponent listPageForEntityName(final String entityName) { ListPageInterface newListPageInterface = D2W.factory().listPageForEntityNamed(entityName, session()); EODatabaseDataSource dataSource = new EODatabaseDataSource(ERXEC.newEditingContext(), entityName); EOEntity entity = ERXEOAccessUtilities.entityNamed(null, entityName); EOQualifier auxQual = NBBusinessLogicPrincipal.getSharedInstance().clientRestrictionQualifier(entity, ((Session)session()).getCompany());
dataSource.setAuxiliaryQualifier(auxQual);
newListPageInterface.setDataSource(dataSource); return (WOComponent) newListPageInterface; }
• Use a query delegate
• Override the method queryDataSource(ERD2WQueryPage sender)
Using a query component
{ author = 100; class = "com.webobjects.directtoweb.Rule"; lhs = { class = "com.webobjects.eocontrol.EOKeyValueQualifier"; key = pageConfiguration; selectorName = isEqualTo; value = QueryMyEntity; }; rhs = { class = "er.directtoweb.ERDDelayedObjectCreationAssignment"; keyPath = queryDataSourceDelegate; value = "ca.wowodc.very.util.pascal.delegate.SomeOneElse"; };}
• Maybe subclass the 2 component is the best solution
• Use restrictingFetchSpecification key. If all fetchspec have the same name, it’s possible to build a generic rule.
• Need to be modified to add the possibility to set a binding to the fetchspec
• Maybe a lot of pain to create many fetchspec in the EOModel
EditRelationship components
How the qualifier is modified?
public Object restrictedChoiceList() { String restrictedChoiceKey=(String)d2wContext().valueForKey("restrictedChoiceKey"); if( restrictedChoiceKey!=null && restrictedChoiceKey.length()>0 ) return valueForKeyPath(restrictedChoiceKey); String fetchSpecName=(String)d2wContext().valueForKey("restrictingFetchSpecification"); if(fetchSpecName != null) { EORelationship relationship = ERXUtilities.relationshipWithObjectAndKeyPath(object(), (String)d2wContext().valueForKey("propertyKey")); if(relationship != null) return EOUtilities.objectsWithFetchSpecificationAndBindings(object().editingContext(), relationship.destinationEntity().name(),fetchSpecName,null); } return null; }
@prabier
Follow me!
Q&ATBD