]> err.no Git - sope/blob - sope-appserver/NGObjWeb/DynamicElements/WOCopyValue.m
started TAL element builder
[sope] / sope-appserver / NGObjWeb / DynamicElements / WOCopyValue.m
1 /*
2   Copyright (C) 2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include <NGObjWeb/WODynamicElement.h>
23
24 /*
25   WOCopyValue / <var:copy-value/>
26   
27   Usage:
28     SetupContext: WOCopyValue {
29       currentDate = "currentItem.date";
30       copyValues = {
31         "displayGroup.queryMin.lastModified" = "currentItem.date";
32         "displayGroup.queryMax.lastModified" = "currentItem.date";
33       };
34       finishValues = {
35         "displayGroup.queryMin.lastModified" = nil;
36         "displayGroup.queryMax.lastModified" = nil;
37       };
38       resetValues = NO;
39     }
40
41   Bindings:
42     copyValues
43     finishValues
44     resetValues
45     <extra>: are used as 'prepare' values
46   
47   The element has a template and can be used in a certain scope,
48 */
49
50 @interface WOCopyValue : WODynamicElement // TODO: should be WOElement?
51 {
52   WOAssociation **targets;
53   WOAssociation **sources;
54   unsigned      count;
55   WOElement     *template;
56   WOAssociation *copyValues;
57   WOAssociation *finishValues;
58   WOAssociation *resetValues;
59 }
60
61 @end
62
63 #include <NGObjWeb/WOAssociation.h>
64 #include <NGObjWeb/WOContext.h>
65 #include "common.h"
66
67 @implementation WOCopyValue
68
69 // TODO: cache NSString class, cache constant objects
70
71 static inline id valueForConstString(NSString *v) {
72   unsigned len;
73   unichar  c0;
74   id vr;
75
76   len = [v length];
77   c0  = len > 6 ? [v characterAtIndex:6] : 0;
78           
79   if ((len == 9  && c0 == 'n' && [v isEqualToString:@"const:nil"]) ||
80       (len == 10 && c0 == 'n' && [v isEqualToString:@"const:null"])) {
81     vr = [NSNull null];
82   }
83   else if ((len == 9  && c0 == 'y' && [v isEqualToString:@"const:yes"]) ||
84            (len == 10 && c0 == 't' && [v isEqualToString:@"const:true"])) {
85     vr = [NSNumber numberWithBool:NO];
86   }
87   else if ((len == 8  && c0 == 'n' && [v isEqualToString:@"const:no"]) ||
88            (len == 11 && c0 == 'f' && [v isEqualToString:@"const:false"])) {
89     vr = [NSNumber numberWithBool:NO];
90   }
91   else if (isdigit(c0) || (c0 == '-' && len > 7)) {
92     vr = [v substringFromIndex:6];
93     vr = ([vr rangeOfString:@"."].length > 0)
94       ? [NSNumber numberWithDouble:[vr doubleValue]]
95       : [NSNumber numberWithDouble:[vr intValue]];
96   }
97   else
98     vr = [v substringFromIndex:6];
99
100   return vr;
101 }
102
103 - (id)initWithName:(NSString *)_name
104   associations:(NSDictionary *)_config
105   template:(WOElement *)_c
106 {
107   if ((self = [super initWithName:_name associations:_config template:_c])) {
108     NSDictionary *statVals;
109     
110     self->template = [_c retain];
111     self->copyValues   = OWGetProperty(_config, @"copyValues");
112     self->finishValues = OWGetProperty(_config, @"finishValues");
113     self->resetValues  = OWGetProperty(_config, @"resetValues");
114
115     /* fill static value array */
116     
117     if ([self->copyValues isValueConstant]) {
118       statVals = [[self->copyValues valueInContext:nil] retain];
119       [self->copyValues release];
120       self->copyValues = nil;
121     }
122     
123     if ((self->count = ([statVals count] + [_config count])) > 0) {
124       NSEnumerator *e;
125       NSString *key;
126       unsigned i;
127       
128       self->targets = calloc(self->count + 2, sizeof(id));
129       self->sources = calloc(self->count + 2, sizeof(id));
130       i = 0;
131       
132       /* extra keys first (key is a string, value is an assoc) */
133
134       e = [_config keyEnumerator];
135       while ((key = [e nextObject]) != nil) {
136         self->targets[i] = [[WOAssociation associationWithKeyPath:key] retain];
137         self->sources[i] = [[_config objectForKey:key] retain];
138         i++;
139       }
140       
141       /* then static keys (key and value are strings) */
142       
143       e = [statVals keyEnumerator];
144       while ((key = [e nextObject]) != nil) {
145         NSString *v;
146         
147         v = [statVals objectForKey:key];
148         self->targets[i] = [[WOAssociation associationWithKeyPath:key] retain];
149         
150         if ([v hasPrefix:@"const:"]) {
151           self->sources[i] =
152             [[WOAssociation associationWithValue:valueForConstString(v)]
153                             retain];
154         }
155         else {
156           self->sources[i] =
157             [[WOAssociation associationWithKeyPath:v] retain];
158         }
159         i++;
160       }
161     }
162     
163     [statVals release]; statVals = nil;
164   }
165   return self;
166 }
167
168 - (void)dealloc {
169   unsigned i;
170   
171   [self->finishValues release];
172   [self->resetValues  release];
173   
174   for (i = 0; i < self->count; i++) {
175     [self->targets[i] release];
176     [self->sources[i] release];
177   }
178   if (self->targets != NULL) free(self->targets);
179   if (self->sources != NULL) free(self->sources);
180   
181   [self->template release];
182   [super dealloc];
183 }
184
185 /* accessors */
186
187 - (id)template {
188   return self->template;
189 }
190
191 /* copy */
192
193 - (void)copyValuesInDictionary:(NSDictionary *)_d inContext:(WOContext *)_ctx {
194   NSEnumerator *e;
195   NSString *key;
196   id setCursor, getCursor;
197   
198   setCursor = [_ctx component];
199   getCursor = setCursor;
200   
201   e = [_d keyEnumerator];
202   while ((key = [e nextObject]) != nil) {
203     id value;
204     
205     value = [_d objectForKey:key];
206     if ([value isKindOfClass:[NSString class]]) {
207       value = [value hasPrefix:@"const:"]
208         ? valueForConstString(value)
209         : [getCursor valueForKeyPath:value];
210     }
211     
212     [setCursor takeValue:value forKeyPath:key];
213   }
214 }
215
216 - (void)copyValuesInContext:(WOContext *)_ctx {
217   unsigned i;
218   
219   /* copy constant mappings */
220   for (i = 0; i < self->count; i++) {
221     [self->targets[i] setValue:[self->sources[i] valueInContext:_ctx]
222                       inContext:_ctx];
223   }
224   
225   /* copy dynamic mappings */
226   if (self->copyValues != nil) {
227     [self copyValuesInDictionary:[self->copyValues valueInContext:_ctx]
228           inContext:_ctx];
229   }
230 }
231
232 - (void)resetValuesInContext:(WOContext *)_ctx {
233   if (self->resetValues == nil && self->finishValues == nil)
234     return;
235   
236   /* reset values to nil */
237   
238   if ([self->resetValues boolValueInContext:_ctx]) {
239     unsigned i;
240     
241     for (i = 0; i < self->count; i++)
242       [self->targets[i] setValue:nil inContext:_ctx];
243   }
244   
245   /* apply post value copy */
246   if (self->finishValues != nil) {
247     [self copyValuesInDictionary:[self->finishValues valueInContext:_ctx]
248           inContext:_ctx];
249   }
250 }
251
252 /* handling requests */
253
254 - (void)takeValuesFromRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
255   [self copyValuesInContext:_ctx];
256   [self->template takeValuesFromRequest:_rq inContext:_ctx];
257   [self resetValuesInContext:_ctx];
258 }
259
260 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
261   id result;
262   
263   [self copyValuesInContext:_ctx];
264   result = [[self->template invokeActionForRequest:_rq inContext:_ctx] retain];
265   [self resetValuesInContext:_ctx];
266   
267   return [result autorelease];
268 }
269
270 /* generating response */
271
272 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
273   [self copyValuesInContext:_ctx];
274   [self->template appendToResponse:_response inContext:_ctx];
275   [self resetValuesInContext:_ctx];
276 }
277
278 @end /* WOCopyValue */