1 |
<?php |
2 |
|
3 |
require_once("YakkaXml.php"); |
4 |
require_once("YakkaFileReader.php"); |
5 |
require_once("YakkaArguments.php"); |
6 |
require_once("YakkaTextProcessor.php"); |
7 |
require_once("YakkaXslProcessor.php"); |
8 |
require_once("YakkaTemplateCommandProcessor.php"); |
9 |
|
10 |
define("YAKKA_NAMESPACE", "http://www.ilker.de/yakka/yakka-xml/0.1"); |
11 |
|
12 |
define("YAKKA_GLOBAL_SINGLETON", "YakkaGlobalSingleton"); |
13 |
|
14 |
class YakkaEngine { |
15 |
var $session; |
16 |
|
17 |
var $settingsXml; |
18 |
|
19 |
var $pageStorage; |
20 |
var $userStorage; |
21 |
var $permissionStorage; |
22 |
|
23 |
var $arguments; |
24 |
|
25 |
var $runtime; |
26 |
|
27 |
function YakkaEngine($settingsXmlFile, &$session) { |
28 |
/* get the singleton object */ |
29 |
$$singleton = YAKKA_GLOBAL_SINGLETON; |
30 |
global $singleton; |
31 |
|
32 |
/* enable runtime and session to be referenced */ |
33 |
$this->runtime = &new StdClass(); |
34 |
$this->session = &$session; |
35 |
|
36 |
/* read settings */ |
37 |
$this->initializeSettings($settingsXmlFile); |
38 |
|
39 |
/* obtain location of storage-providers */ |
40 |
$storageProviderLocation = $this->settingsXml->selectNodeValue("/y:settings/y:filesystem/y:location[@of='storage-providers']/text()"); |
41 |
|
42 |
/* create storage instances */ |
43 |
$this->initializeStorage($storageProviderLocation); |
44 |
|
45 |
/* push globally required storages and session to singleton */ |
46 |
$singleton->pageStorage = &$this->pageStorage; |
47 |
$singleton->userStorage = &$this->userStorage; |
48 |
$singleton->permissionStorage = &$this->permissionStorage; |
49 |
$singleton->session = &$this->session; |
50 |
|
51 |
/* get runtime arguments we require */ |
52 |
$this->initializeArguments(); |
53 |
|
54 |
/* initialize template values */ |
55 |
$this->initializeTemplates(); |
56 |
|
57 |
/* initialize processors */ |
58 |
$this->initializeProcessors(); |
59 |
|
60 |
/* initialize objects from session */ |
61 |
$this->initializeSession(); |
62 |
} |
63 |
|
64 |
function initializeSettings($settingsXmlFile) { |
65 |
global $HTTP_SERVER_VARS; |
66 |
|
67 |
/* read settings file */ |
68 |
$this->settingsXml = new YakkaXml(new YakkaFileReader($settingsXmlFile)); |
69 |
$this->settingsXml->declareNamespace("y", YAKKA_NAMESPACE); |
70 |
|
71 |
/* update settings with runtime values (baseurl and filepath) */ |
72 |
$this->runtime->baseUrl = $HTTP_SERVER_VARS["URL"]; |
73 |
$this->runtime->filePath = dirname($HTTP_SERVER_VARS["PATH_TRANSLATED"]); |
74 |
|
75 |
$this->settingsXml->setAttributeOfElement("baseurl", $this->runtime->baseUrl, "/y:settings/y:filesystem"); |
76 |
$this->settingsXml->setAttributeOfElement("filepath", $this->runtime->filePath, "/y:settings/y:filesystem"); |
77 |
} |
78 |
|
79 |
function initializeStorage($storageProviderLocation) { |
80 |
/* get the adapter implementation of storage-provider for pages */ |
81 |
$storageImplementationForPage = $this->settingsXml->selectNodeValue("/y:settings/y:storage/y:storage-provider[@implements='YakkaPageStorage']/@adapter"); |
82 |
|
83 |
/* now obtain all parameters for this provider */ |
84 |
$storageProviderParameterElements = $this->settingsXml->selectNodes("/y:settings/y:storage/y:storage-provider[@implements='YakkaPageStorage']/*"); |
85 |
|
86 |
/* prepare parameters */ |
87 |
$storageProviderParameters = array(); |
88 |
while(list(,$parameterElement) = each($storageProviderParameterElements)) |
89 |
$storageProviderParameters[$parameterElement->node_name()] = $parameterElement->get_content(); |
90 |
|
91 |
/* finally call provider */ |
92 |
require_once($storageProviderLocation."/".$storageImplementationForPage.".php"); |
93 |
$this->pageStorage = new $storageImplementationForPage($storageProviderParameters); |
94 |
|
95 |
/* do the same thing for user storage */ |
96 |
$storageImplementationForUser = $this->settingsXml->selectNodeValue("/y:settings/y:storage/y:storage-provider[@implements='YakkaUserStorage']/@adapter"); |
97 |
$storageProviderParameterElements = $this->settingsXml->selectNodes("/y:settings/y:storage/y:storage-provider[@implements='YakkaUserStorage']/*"); |
98 |
|
99 |
$storageProviderParameters = array(); |
100 |
while(list(,$parameterElement) = each($storageProviderParameterElements)) |
101 |
$storageProviderParameters[$parameterElement->node_name()] = $parameterElement->get_content(); |
102 |
|
103 |
require_once($storageProviderLocation."/".$storageImplementationForUser.".php"); |
104 |
$this->userStorage = new $storageImplementationForUser($storageProviderParameters); |
105 |
|
106 |
/* and again for permission storage */ |
107 |
$storageImplementationForPermission = $this->settingsXml->selectNodeValue("/y:settings/y:storage/y:storage-provider[@implements='YakkaPermissionStorage']/@adapter"); |
108 |
$storageProviderParameterElements = $this->settingsXml->selectNodes("/y:settings/y:storage/y:storage-provider[@implements='YakkaPermissionStorage']/*"); |
109 |
|
110 |
$storageProviderParameters = array(); |
111 |
while(list(,$parameterElement) = each($storageProviderParameterElements)) |
112 |
$storageProviderParameters[$parameterElement->node_name()] = $parameterElement->get_content(); |
113 |
|
114 |
require_once($storageProviderLocation."/".$storageImplementationForPermission.".php"); |
115 |
$this->permissionStorage = new $storageImplementationForPermission($storageProviderParameters); |
116 |
} |
117 |
|
118 |
function initializeArguments() { |
119 |
/* read argument definitions */ |
120 |
$argumentNameElements = $this->settingsXml->selectNodes("/y:settings/y:arguments/y:argument-name"); |
121 |
|
122 |
/* prepare argument name mapping table */ |
123 |
$argumentNames = array(); |
124 |
while(list(,$nameElement) = each($argumentNameElements)) |
125 |
$argumentNames[$nameElement->get_attribute("of")] = $nameElement->get_content(); |
126 |
|
127 |
/* create yakka's argument handler with mapping table */ |
128 |
$this->arguments = new YakkaArguments($argumentNames); |
129 |
} |
130 |
|
131 |
function initializeTemplates() { |
132 |
/* read setting if we should use template processor */ |
133 |
if (!$this->runtime->processTemplate = $this->settingsXml->selectNodeValue("/y:settings/y:engine/@process-template")) |
134 |
$this->runtime->processTemplate = "false"; |
135 |
|
136 |
/* read template directory */ |
137 |
$this->runtime->templateLocation = $this->settingsXml->selectNodeValue("/y:settings/y:filesystem/y:location[@of='templates']/text()"); |
138 |
|
139 |
/* get template setting */ |
140 |
$this->runtime->templateId = $this->settingsXml->selectNodeValue("/y:settings/y:engine/y:default-template/text()"); |
141 |
} |
142 |
|
143 |
function initializeProcessors() { |
144 |
/* the text processor has power to access and invoke everything, so we pass him ourselves */ |
145 |
$this->textProcessor = new YakkaTextProcessor($this); |
146 |
|
147 |
/* yakka chooses xsl for templating (xml -> html transformation) */ |
148 |
$this->templateProcessor = new YakkaXslProcessor(); |
149 |
|
150 |
/* yakka has some specific transformation commands calling the core text processor */ |
151 |
$this->templateCommandProcessor = new YakkaTemplateCommandProcessor($this->textProcessor); |
152 |
} |
153 |
|
154 |
function initializeSession() { |
155 |
/* take default user from settings */ |
156 |
$this->runtime->user = new YakkaUser($this->settingsXml->selectNodeValue("/y:settings/y:engine/y:default-user/@id")); |
157 |
|
158 |
/* a user already stored in session ? if yes, take him */ |
159 |
if ($this->session->user) |
160 |
$this->runtime->user->fromString($this->session->user); |
161 |
else |
162 |
$this->session->user = $this->runtime->user->toString(); |
163 |
} |
164 |
|
165 |
function parseCommand() { |
166 |
/* get page/method argument and strip leading slash */ |
167 |
$commandString = preg_replace("/^\//", "", $this->arguments->getArgument("page/method")); |
168 |
|
169 |
/* set default page and method values */ |
170 |
$command["page-id"] = $this->settingsXml->selectNodeValue("/y:settings/y:engine/y:default-page/text()"); |
171 |
$command["method-id"] = $this->settingsXml->selectNodeValue("/y:settings/y:engine/y:default-method/text()"); |
172 |
|
173 |
/* get optional revision argument */ |
174 |
$command["page-revision"] = $this->arguments->getArgument("revision"); |
175 |
|
176 |
/* parse page and method from argument */ |
177 |
if (preg_match("#^(.+?)/(.*)$#", $commandString, $matches)) |
178 |
list(, $command["page-id"], $command["method-id"]) = $matches; |
179 |
else if (preg_match("#^(.+)$#", $commandString, $matches)) |
180 |
list(, $command["page-id"]) = $matches; |
181 |
|
182 |
/* modify method-id to get it into the pseudo yakka-namespace of the code (prefix "YakkaMethod") */ |
183 |
$command["method-id"] = "YakkaMethod".$command["method-id"]; |
184 |
|
185 |
return $command; |
186 |
} |
187 |
|
188 |
function buildCommand($pageId, $methodId = null, $arguments = null) { |
189 |
return $this->runtime->baseUrl."?".$this->arguments->getArgumentName("page/method")."=".$pageId.($methodId ? "/".$methodId : "").($arguments ? $arguments : ""); |
190 |
} |
191 |
|
192 |
function run() { |
193 |
/* get command */ |
194 |
$this->runtime->command = $this->parseCommand(); |
195 |
|
196 |
/* try to load the page */ |
197 |
$this->runtime->page = new YakkaPage($this->runtime->command["page-id"], $this->runtime->command["page-revision"]); |
198 |
|
199 |
/* run method, regardless if page exists or not */ |
200 |
$methodXml = new YakkaXml($this->runMethod($this->runtime->command["method-id"])); |
201 |
$methodResponse = $methodXml->ToXmlElement(); |
202 |
|
203 |
/* save method as active now */ |
204 |
$this->session->activeMethodId = $this->runtime->command["method-id"]; |
205 |
|
206 |
/* is method requiring access-control ? */ |
207 |
if ($accessPrivilege = $methodXml->selectNodeValue("//method/@access-privilege")) { |
208 |
$run = $this->runtime->page->allows($this->runtime->user, $accessPrivilege); |
209 |
} else { |
210 |
/* no access-control, we allow everything */ |
211 |
$run = true; |
212 |
} |
213 |
|
214 |
/* check if page access is granted */ |
215 |
if ($run) { |
216 |
/* set this as active page */ |
217 |
$this->session->activePageId = $this->runtime->page->getId(); |
218 |
|
219 |
/* call engine to process template and page */ |
220 |
$responseXml = $this->runEngine($methodResponse); |
221 |
|
222 |
/* read mime settings */ |
223 |
if (!$mimeType = $this->settingsXml->selectNodeValue("/y:settings/y:engine/@use-mime-type")) |
224 |
$mimeType = "text/html"; |
225 |
|
226 |
/* write headers if desired */ |
227 |
if ($this->settingsXml->selectNodeValue("/y:settings/y:engine/@write-http-headers") == "true") |
228 |
header("Content-Type: $mimeType"); |
229 |
|
230 |
if ($mimeType == "text/html") |
231 |
return $responseXml->toHtml(); |
232 |
else if ($mimeType == "text/xml") |
233 |
return $responseXml->toXml(); |
234 |
else |
235 |
return $responseXml; |
236 |
|
237 |
//} else { |
238 |
/* no access rights, discard page */ |
239 |
// $this->runtime->page = null; |
240 |
} |
241 |
|
242 |
return null; |
243 |
} |
244 |
|
245 |
function runMethod($methodId) { |
246 |
/* obtain location of method */ |
247 |
$methodLocation = $this->settingsXml->selectNodeValue("/y:settings/y:filesystem/y:location[@of='methods']/text()"); |
248 |
|
249 |
/* call method */ |
250 |
require_once($methodLocation."/".$methodId.".php"); |
251 |
$this->methodInstance = new $methodId($this); |
252 |
return $this->methodInstance->run(); |
253 |
} |
254 |
|
255 |
function runAction($actionId, $actionParameters = null) { |
256 |
/* obtain location of action */ |
257 |
$actionLocation = $this->settingsXml->selectNodeValue("/y:settings/y:filesystem/y:location[@of='actions']/text()"); |
258 |
|
259 |
/* modify action-id to get it into the pseudo yakka-namespace of the code (prefix "YakkaAction") */ |
260 |
$actionId = "YakkaAction".$actionId; |
261 |
|
262 |
/* call action */ |
263 |
require_once($actionLocation."/".$actionId.".php"); |
264 |
$this->actionInstance = new $actionId($this); |
265 |
|
266 |
/* get xml result */ |
267 |
$actionResponse = "<action id='".$actionId."'>"; |
268 |
$actionResponse .= $this->actionInstance->run(); |
269 |
$actionResponse .= "</action>"; |
270 |
$actionXml = new YakkaXml($this->buildXml($actionResponse)); |
271 |
|
272 |
/* ask action for template */ |
273 |
if ($this->runtime->processTemplate == "true") { |
274 |
/* read our xsl-template */ |
275 |
$templateXml = new YakkaXml(new YakkaFileReader($this->runtime->templateLocation."/".$this->runtime->templateId."/".$actionId.".xsl")); |
276 |
|
277 |
/* call template prcocessor */ |
278 |
$resultXml = $this->templateProcessor->process($actionXml, $templateXml); |
279 |
|
280 |
/* TODO: check for mimetype */ |
281 |
return $resultXml->toXmlElement(); |
282 |
} |
283 |
|
284 |
return $actionResponse; |
285 |
} |
286 |
|
287 |
function runEngine($additionalData) { |
288 |
/* get our resulting xml from engine */ |
289 |
$engineXml = new YakkaXml($this->buildXml($additionalData)); |
290 |
|
291 |
/* yes, please use templates */ |
292 |
if ($this->runtime->processTemplate == "true") { |
293 |
/* read our xsl-template */ |
294 |
$templateXml = new YakkaXml(new YakkaFileReader($this->runtime->templateLocation."/".$this->runtime->templateId."/".$this->runtime->command["method-id"].".xsl")); |
295 |
|
296 |
/* before processing xsl, we call our own pre-processor */ |
297 |
$this->templateCommandProcessor->preProcess($templateXml, $this->runtime->templateLocation, $this->runtime->templateId, $this->runtime->filePath); |
298 |
|
299 |
/* call template processor */ |
300 |
$resultXml = $this->templateProcessor->process($engineXml, $templateXml, $this->runtime->filePath."/".$this->runtime->templateLocation."/".$this->runtime->templateId."/"); |
301 |
|
302 |
/* after having processed xsl, we call our own post-processor */ |
303 |
$this->templateCommandProcessor->postProcess($resultXml); |
304 |
|
305 |
return $resultXml; |
306 |
} |
307 |
|
308 |
return $engineXml; |
309 |
} |
310 |
|
311 |
function buildXml($additionalData = null) { |
312 |
/* read character encoding setting */ |
313 |
if (!$encoding = $this->settingsXml->selectNodeValue("/y:settings/y:engine/@use-encoding")) |
314 |
$encoding = "iso-8859-1"; |
315 |
|
316 |
$xml = "<?xml version='1.0' encoding='$encoding'?>"; |
317 |
$xml .= "<yakka version='0.1' xmlns='".YAKKA_NAMESPACE."'>"; |
318 |
$xml .= $this->settingsXml->toXmlElement(); |
319 |
$xml .= "<session>"; |
320 |
|
321 |
if ($this->runtime->user) |
322 |
$xml .= $this->runtime->user->toXml(); |
323 |
|
324 |
$xml .= "</session>"; |
325 |
$xml .= "<runtime>"; |
326 |
$xml .= $this->runtime->page->toXml(); |
327 |
|
328 |
if ($additionalData) |
329 |
$xml .= $additionalData; |
330 |
|
331 |
$xml .= "</runtime>"; |
332 |
$xml .= "</yakka>"; |
333 |
|
334 |
return $xml; |
335 |
} |
336 |
} |
337 |
|
338 |
?> |