1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27: 28: 29: 30: 31: 32: 33:
34: abstract class Mage_Api_Model_Server_Handler_Abstract
35: {
36: protected $_resourceSuffix = null;
37:
38: public function __construct()
39: {
40: set_error_handler(array($this, 'handlePhpError'), E_ALL);
41: Mage::app()->loadAreaPart(Mage_Core_Model_App_Area::AREA_ADMINHTML, Mage_Core_Model_App_Area::PART_EVENTS);
42: }
43:
44: public function handlePhpError($errorCode, $errorMessage, $errorFile)
45: {
46: Mage::log($errorMessage . $errorFile);
47: if (in_array($errorCode, array(E_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR))) {
48: $this->_fault('internal');
49: }
50: return true;
51: }
52:
53:
54: 55: 56: 57: 58:
59: protected function _getSession()
60: {
61: return Mage::getSingleton('api/session');
62: }
63:
64: 65: 66: 67: 68:
69: protected function _getConfig()
70: {
71: return Mage::getSingleton('api/config');
72: }
73:
74: 75: 76: 77: 78:
79: protected function _getServer()
80: {
81: return Mage::getSingleton('api/server');
82: }
83:
84: 85: 86: 87: 88: 89:
90: protected function _startSession($sessionId=null)
91: {
92: $this->_getSession()->setSessionId($sessionId);
93: $this->_getSession()->init('api', 'api');
94: return $this;
95: }
96:
97: 98: 99: 100: 101: 102: 103: 104:
105: protected function _isAllowed($resource, $privilege=null)
106: {
107: return $this->_getSession()->isAllowed($resource, $privilege);
108: }
109:
110: 111: 112: 113: 114:
115: protected function _isSessionExpired ()
116: {
117: return $this->_getSession()->isSessionExpired();
118: }
119:
120: 121: 122: 123: 124: 125: 126:
127: protected function _fault($faultName, $resourceName=null, $customMessage=null)
128: {
129: $faults = $this->_getConfig()->getFaults($resourceName);
130: if (!isset($faults[$faultName]) && !is_null($resourceName)) {
131: $this->_fault($faultName);
132: return;
133: } elseif (!isset($faults[$faultName])) {
134: $this->_fault('unknown');
135: return;
136: }
137: $this->_getServer()->getAdapter()->fault(
138: $faults[$faultName]['code'],
139: (is_null($customMessage) ? $faults[$faultName]['message'] : $customMessage)
140: );
141: }
142:
143: 144: 145: 146: 147: 148: 149: 150:
151: protected function _faultAsArray($faultName, $resourceName=null, $customMessage=null)
152: {
153: $faults = $this->_getConfig()->getFaults($resourceName);
154: if (!isset($faults[$faultName]) && !is_null($resourceName)) {
155: return $this->_faultAsArray($faultName);
156: } elseif (!isset($faults[$faultName])) {
157: return $this->_faultAsArray('unknown');
158: }
159:
160: return array(
161: 'isFault' => true,
162: 'faultCode' => $faults[$faultName]['code'],
163: 'faultMessage' => (is_null($customMessage) ? $faults[$faultName]['message'] : $customMessage)
164: );
165: }
166:
167: 168: 169: 170: 171:
172: public function startSession()
173: {
174: $this->_startSession();
175: return $this->_getSession()->getSessionId();
176: }
177:
178:
179: 180: 181: 182: 183: 184:
185: public function endSession($sessionId)
186: {
187: $this->_startSession($sessionId);
188: $this->_getSession()->clear();
189: return true;
190: }
191:
192: 193: 194: 195: 196: 197:
198: protected function _prepareResourceModelName($resource)
199: {
200: if (null !== $this->_resourceSuffix) {
201: return $resource . $this->_resourceSuffix;
202: }
203: return $resource;
204: }
205:
206: 207: 208: 209: 210: 211: 212:
213: public function login($username, $apiKey = null)
214: {
215: if (empty($username) || empty($apiKey)) {
216: return $this->_fault('invalid_request_param');
217: }
218:
219: try {
220: $this->_startSession();
221: $this->_getSession()->login($username, $apiKey);
222: } catch (Exception $e) {
223: return $this->_fault('access_denied');
224: }
225: return $this->_getSession()->getSessionId();
226: }
227:
228: 229: 230: 231: 232: 233: 234: 235:
236: public function call($sessionId, $apiPath, $args = array())
237: {
238: $this->_startSession($sessionId);
239:
240: if (!$this->_getSession()->isLoggedIn($sessionId)) {
241: return $this->_fault('session_expired');
242: }
243:
244: list($resourceName, $methodName) = explode('.', $apiPath);
245:
246: if (empty($resourceName) || empty($methodName)) {
247: return $this->_fault('resource_path_invalid');
248: }
249:
250: $resourcesAlias = $this->_getConfig()->getResourcesAlias();
251: $resources = $this->_getConfig()->getResources();
252: if (isset($resourcesAlias->$resourceName)) {
253: $resourceName = (string) $resourcesAlias->$resourceName;
254: }
255:
256: if (!isset($resources->$resourceName)
257: || !isset($resources->$resourceName->methods->$methodName)) {
258: return $this->_fault('resource_path_invalid');
259: }
260:
261: if (!isset($resources->$resourceName->public)
262: && isset($resources->$resourceName->acl)
263: && !$this->_isAllowed((string)$resources->$resourceName->acl)) {
264: return $this->_fault('access_denied');
265:
266: }
267:
268:
269: if (!isset($resources->$resourceName->methods->$methodName->public)
270: && isset($resources->$resourceName->methods->$methodName->acl)
271: && !$this->_isAllowed((string)$resources->$resourceName->methods->$methodName->acl)) {
272: return $this->_fault('access_denied');
273: }
274:
275: $methodInfo = $resources->$resourceName->methods->$methodName;
276:
277: try {
278: $method = (isset($methodInfo->method) ? (string) $methodInfo->method : $methodName);
279:
280: $modelName = $this->_prepareResourceModelName((string) $resources->$resourceName->model);
281: try {
282: $model = Mage::getModel($modelName);
283: if ($model instanceof Mage_Api_Model_Resource_Abstract) {
284: $model->setResourceConfig($resources->$resourceName);
285: }
286: } catch (Exception $e) {
287: throw new Mage_Api_Exception('resource_path_not_callable');
288: }
289:
290: if (is_callable(array(&$model, $method))) {
291: if (isset($methodInfo->arguments) && ((string)$methodInfo->arguments) == 'array') {
292: return $model->$method((is_array($args) ? $args : array($args)));
293: } elseif (!is_array($args)) {
294: return $model->$method($args);
295: } else {
296: return call_user_func_array(array(&$model, $method), $args);
297: }
298: } else {
299: throw new Mage_Api_Exception('resource_path_not_callable');
300: }
301: } catch (Mage_Api_Exception $e) {
302: return $this->_fault($e->getMessage(), $resourceName, $e->getCustomMessage());
303: } catch (Exception $e) {
304: Mage::logException($e);
305: return $this->_fault('internal', null, $e->getMessage());
306: }
307: }
308:
309: 310: 311: 312: 313: 314: 315: 316:
317: public function multiCall($sessionId, array $calls = array(), $options = array())
318: {
319: $this->_startSession($sessionId);
320:
321: if (!$this->_getSession()->isLoggedIn($sessionId)) {
322: return $this->_fault('session_expired');
323: }
324:
325: $result = array();
326:
327: $resourcesAlias = $this->_getConfig()->getResourcesAlias();
328: $resources = $this->_getConfig()->getResources();
329:
330: foreach ($calls as $call) {
331: if (!isset($call[0])) {
332: $result[] = $this->_faultAsArray('resource_path_invalid');
333: if (isset($options['break']) && $options['break']==1) {
334: break;
335: } else {
336: continue;
337: }
338: }
339:
340: $apiPath = $call[0];
341: $args = (isset($call[1]) ? $call[1] : array());
342:
343: list($resourceName, $methodName) = explode('.', $apiPath);
344:
345: if (empty($resourceName) || empty($methodName)) {
346: $result[] = $this->_faultAsArray('resource_path_invalid');
347: if (isset($options['break']) && $options['break']==1) {
348: break;
349: } else {
350: continue;
351: }
352: }
353:
354: if (isset($resourcesAlias->$resourceName)) {
355: $resourceName = (string) $resourcesAlias->$resourceName;
356: }
357:
358: if (!isset($resources->$resourceName)
359: || !isset($resources->$resourceName->methods->$methodName)) {
360: $result[] = $this->_faultAsArray('resource_path_invalid');
361: if (isset($options['break']) && $options['break']==1) {
362: break;
363: } else {
364: continue;
365: }
366: }
367:
368: if (!isset($resources->$resourceName->public)
369: && isset($resources->$resourceName->acl)
370: && !$this->_isAllowed((string)$resources->$resourceName->acl)) {
371: $result[] = $this->_faultAsArray('access_denied');
372: if (isset($options['break']) && $options['break']==1) {
373: break;
374: } else {
375: continue;
376: }
377: }
378:
379:
380: if (!isset($resources->$resourceName->methods->$methodName->public)
381: && isset($resources->$resourceName->methods->$methodName->acl)
382: && !$this->_isAllowed((string)$resources->$resourceName->methods->$methodName->acl)) {
383: $result[] = $this->_faultAsArray('access_denied');
384: if (isset($options['break']) && $options['break']==1) {
385: break;
386: } else {
387: continue;
388: }
389: }
390:
391: $methodInfo = $resources->$resourceName->methods->$methodName;
392:
393: try {
394: $method = (isset($methodInfo->method) ? (string) $methodInfo->method : $methodName);
395:
396: $modelName = $this->_prepareResourceModelName((string) $resources->$resourceName->model);
397: try {
398: $model = Mage::getModel($modelName);
399: } catch (Exception $e) {
400: throw new Mage_Api_Exception('resource_path_not_callable');
401: }
402:
403: if (is_callable(array(&$model, $method))) {
404: if (isset($methodInfo->arguments) && ((string)$methodInfo->arguments) == 'array') {
405: $result[] = $model->$method((is_array($args) ? $args : array($args)));
406: } elseif (!is_array($args)) {
407: $result[] = $model->$method($args);
408: } else {
409: $result[] = call_user_func_array(array(&$model, $method), $args);
410: }
411: } else {
412: throw new Mage_Api_Exception('resource_path_not_callable');
413: }
414: } catch (Mage_Api_Exception $e) {
415: $result[] = $this->_faultAsArray($e->getMessage(), $resourceName, $e->getCustomMessage());
416: if (isset($options['break']) && $options['break']==1) {
417: break;
418: } else {
419: continue;
420: }
421: } catch (Exception $e) {
422: Mage::logException($e);
423: $result[] = $this->_faultAsArray('internal');
424: if (isset($options['break']) && $options['break']==1) {
425: break;
426: } else {
427: continue;
428: }
429: }
430: }
431:
432: return $result;
433: }
434:
435: 436: 437: 438: 439: 440:
441: public function resources($sessionId)
442: {
443: $this->_startSession($sessionId);
444:
445: if (!$this->_getSession()->isLoggedIn($sessionId)) {
446: return $this->_fault('session_expired');
447: }
448:
449: $resources = array();
450:
451: $resourcesAlias = array();
452: foreach ($this->_getConfig()->getResourcesAlias() as $alias => $resourceName) {
453: $resourcesAlias[(string) $resourceName][] = $alias;
454: }
455:
456:
457: foreach ($this->_getConfig()->getResources() as $resourceName => $resource) {
458: if (isset($resource->acl) && !$this->_isAllowed((string) $resource->acl)) {
459: continue;
460: }
461:
462: $methods = array();
463: foreach ($resource->methods->children() as $methodName => $method) {
464: if (isset($method->acl) && !$this->_isAllowed((string) $method->acl)) {
465: continue;
466: }
467: $methodAliases = array();
468: if (isset($resourcesAlias[$resourceName])) {
469: foreach ($resourcesAlias[$resourceName] as $alias) {
470: $methodAliases[] = $alias . '.' . $methodName;
471: }
472: }
473:
474: $methods[] = array(
475: 'title' => (string) $method->title,
476: 'description' => (isset($method->description) ? (string)$method->description : null),
477: 'path' => $resourceName . '.' . $methodName,
478: 'name' => $methodName,
479: 'aliases' => $methodAliases
480: );
481: }
482:
483: if (count($methods) == 0) {
484: continue;
485: }
486:
487: $resources[] = array(
488: 'title' => (string) $resource->title,
489: 'description' => (isset($resource->description) ? (string)$resource->description : null),
490: 'name' => $resourceName,
491: 'aliases' => (isset($resourcesAlias[$resourceName]) ? $resourcesAlias[$resourceName] : array()),
492: 'methods' => $methods
493: );
494: }
495:
496: return $resources;
497: }
498:
499: 500: 501: 502: 503: 504: 505:
506: public function resourceFaults($sessionId, $resourceName)
507: {
508: $this->_startSession($sessionId);
509:
510: if (!$this->_getSession()->isLoggedIn($sessionId)) {
511: return $this->_fault('session_expired');
512: }
513:
514: $resourcesAlias = $this->_getConfig()->getResourcesAlias();
515: $resources = $this->_getConfig()->getResources();
516:
517: if (isset($resourcesAlias->$resourceName)) {
518: $resourceName = (string) $resourcesAlias->$resourceName;
519: }
520:
521:
522: if (empty($resourceName)
523: || !isset($resources->$resourceName)) {
524: return $this->_fault('resource_path_invalid');
525: }
526:
527: if (isset($resources->$resourceName->acl)
528: && !$this->_isAllowed((string)$resources->$resourceName->acl)) {
529: return $this->_fault('access_denied');
530: }
531:
532: return array_values($this->_getConfig()->getFaults($resourceName));
533: }
534:
535: 536: 537: 538: 539: 540:
541: public function globalFaults($sessionId)
542: {
543: $this->_startSession($sessionId);
544: return array_values($this->_getConfig()->getFaults());
545: }
546: }
547: