· 8 years ago · Mar 01, 2018, 08:28 AM
1// ==========================================================================
2// OrionFw.ManyToManyController
3// ==========================================================================
4
5require('core');
6
7/** @class
8
9 (Document Your View Here)
10
11 @extends SC.Controller
12 @author Maurits Lamers
13 @version 0.1
14 @static
15*/
16OrionFw.ManyToManyController = SC.Controller.extend({
17 /*
18 The setup of the ManyToMany Controller
19
20 In a many-to-many relationship there are three entities:
21 - two entity tables (firstEntity and secondEntity)
22 - one linking table (linkEntity)
23
24 The ManyToMany controller controls all three of them. The many-to-many controller works one way,
25 only the second entity is reduced by the value from the first entity
26 You can bind view to display all entities:
27 - the firstEntityArrangedObjects returns all first entity objects
28 - the linkingEntityArrangedObjects returns all valid links as second Entity objects
29 - the secondEntityArrangedObjects returns either all second entity objects or the second entity objects
30 not already in the linkingEntityArrangedObjects depending on the filterSecondEntityArrangedObjects property
31
32 Sometimes it can be really nice to have the relation expressed in different ways.
33 For many uses the linkingEntityArrangedObjects will suffice, but sometimes a list with checkboxes
34 can be much easier to use.
35 So a callback function exists that is called with every second entity object that normally would be in the linking
36 table as parameter. This function needs to return the record for inclusion in the secondEntityArrangedObjects list,
37 but enables manipulation of the object before it is included.
38 As a default, this function just returns the object, but can be overridden to create custom behaviour.
39 In this way you can set values for checkboxes or selections etc.
40
41 to set up this controller, set
42 - firstEntityModel is the model of the first entity,
43 - the secondEntityModel is the second entity,
44 - and the linkEntityModel should get the model for the link table
45
46
47 */
48
49 // name of the model of the first Entity, say songs
50 firstEntityModel: null,
51
52 // name of the property holding the reference to the primary key of the first entity in the link table
53 firstEntityKey: null,
54
55 // name of the model of the second entity, say composers
56 secondEntityModel: null,
57
58 // name of the property holding the reference to the primary key of the second entity in the link table
59 secondEntityKey: null,
60
61 // the name of the model of the link table
62 linkEntityModel: null,
63
64 // what value from the first entity should be showed in the relation?
65 firstEntityValueForRelation: null,
66
67 // Order by flags for each entity table
68 firstEntityOrderBy: null,
69 secondEntityOrderBy: null,
70
71 // selection stuff:
72 firstEntitySelection: [],
73 linkEntitySelection: [],
74 secondEntitySelection: [],
75
76 // if the setting bwlow is true, the reverse of the secondEntityArrangedObjects
77 // the reverse selection is put inside the secondEntityReverseArrangedObjects array
78 filterSecondEntityArrangedObjects: false,
79
80 // set to true if you want the combination of first and second entity in the linking table to be true
81 //combinationFirstAndSecondIsUnique: true,
82
83 // property to bind to to get the array of first Entity records
84 _firstEntityArrangedObjects: function(){
85 // no filtering necessary, so just get all records of a specific type,
86 // set them to be the content, set the orderBy if not null
87 // retrieve and return the arrangedObjects
88 debugger;
89 if(this.firstEntityModel){
90 var recs = SC.objectForPropertyPath(this.firstEntityModel).findAll();
91 this._firstEntityController.set('content',recs);
92 //if(this.firstEntityOrderBy){
93 // this._firstEntityController.set('orderBy',this.firstEntityOrderBy);
94 //}
95 ///return this._firstEntityController.get('arrangedObjects');
96 }
97 }.observes('firstEntityValueForRelation','firstEntityModel'),
98
99 /* linkEntityArrangedObjects: function(){
100 this._calculateEntityRelations();
101 return this._linkEntityArrangedObjects;
102 }.property(),
103
104 secondEntityArrangedObjects: function(){
105 this._calculateEntityRelations();
106 return this._secondEntityArrangedObjects;
107 }.property(), */
108
109
110 // callback function for manipulation
111 handleRelation: function(rec){
112 return rec;
113 },
114
115 // Adding and removing links
116 // TODO: finish
117 addSelectedSecondEntityRelation: function(){
118 var curSel = this.get('secondEntitySelection');
119
120 },
121
122 removeSelectedSecondEntityRelation: function(){
123 var curSel = this.get('linkEntitySelection');
124
125 },
126
127
128 // private stuff
129 // Binding for arrangedObjects
130 firstEntityArrangedObjectsBinding: "._firstEntityController.arrangedObjects",
131 linkEntityArrangedObjectsBinding: "._linkEntityController.arrangedObjects",
132 secondEntityArrangedObjectsBinding: "._secondEntityController.arrangedObjects",
133
134 _getValidSecondEntityRecordIds: function(){
135 var linkCond = {};
136 linkCond[this.firstEntityKey] = this.get('firstEntityValueForRelation');
137 var validSecondEntityRecords = SC.objectForPropertyPath(this.linkEntityModel).findAll(linkCond);
138 if(validSecondEntityRecords.length > 0){
139 var validIds = validSecondEntityRecords.get(this.secondEntityKey);
140 return validIds;
141 }
142 else {
143 return [];
144 }
145 },
146
147 _getValidSecondEntityRecords: function(validIds){
148 var conditions = {};
149 conditions["guid"] = validIds;
150 return SC.Store.findRecords(conditions,SC.objectForPropertyPath(this.secondEntityModel));
151 },
152
153
154 _processHandleRelation: function(recs){
155 if(recs.length > 0){
156 var handleRelation = this.handleRelation; // get a reference to the handleRelation function
157 var newValidRecs = [];
158 recs.forEach(function(s){
159 var t = handleRelation(s);
160 if(t){
161 newValidRecs.push(t);
162 }
163 });
164 return newValidRecs;
165 }
166 else {
167 return recs;
168 }
169 },
170
171 _calculateEntityRelations: function(){
172 // much checking first:
173 // first need to know there actually is a linkEntityModel, a firstEntityKey, a secondEntityKey and
174 // a firstEntityValueForRelation. If either of these is not present,
175 // there is nothing to filter against, so return an empty array
176
177 // sets both the linkingEntityArrangedObjects as the secondEntityArrangedObjects
178 // it will set the valid relation records in the linkEntityArrangedObjects
179 // it will set either the full list or a filtered list in the secondEntityArrangedObjects
180
181 // In a standard many-to-many the filtered list of second entity objects filters out
182 // the handled records.
183
184 // else filter stuff
185 var lEM = this.linkEntityModel;
186 var fEK = this.firstEntityKey;
187 var sEK = this.secondEntityKey;
188 var fEV = this.get('firstEntityValueForRelation');
189 var sEM = this.secondEntityModel;
190 //debugger;
191
192 if(lEM && fEK && sEK && fEV && sEM){
193 // first get an array of guids of the secondEntityObjects in the link table
194 var validSecondEntityRecordIds = this._getValidSecondEntityRecordIds();
195 var validRecs = this._getValidSecondEntityRecords(validSecondEntityRecordIds);
196 // call handleRelation
197 var handledRecs = this._processHandleRelation(validRecs);
198 //this._secondEntityController.set('content',handledRecs);
199 if(this._secondEntityOrderBy){
200 // possibility of ordering
201 //this._secondEntityController.set('orderBy',this.secondEntityOrderBy);
202 }
203 // either filter the second entity record set or return the full second entity record set
204 if(this.filterSecondEntityArrangedObjects){
205 var allRecIds = SC.Store.findRecords(SC.objectForPropertyPath(sEM)).get("guid");
206 validSecondEntityRecordIds.forEach(function(v){
207 // allRecIds is an array of Numbers, and v is a string
208 allRecIds = allRecIds.without(parseInt(v));
209 });
210 var revCond = {};
211 revCond["guid"] = allRecIds;
212 var allFilteredRecs = SC.Store.findRecords(revCond, SC.objectForPropertyPath(sEM));
213 this._secondEntityController.set('content', allFilteredRecs);
214 }
215 else {
216 this._secondEntityController.set('content', handledRecs);
217 }
218 //
219 this._linkEntityController.set('content', validRecs);
220 }
221 else {
222 this._linkEntityController.set('content', []);
223 this._secondEntityController.set('content', []);
224 }
225 }.observes('firstEntityValueForRelation'),
226
227
228 _firstEntityController: SC.ArrayController.create(),
229
230 _linkEntityController: SC.ArrayController.create(),
231
232 _secondEntityController: SC.ArrayController.create()
233
234});