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: class Mage_Api2_Model_Server
35: {
36: 37: 38:
39: const API_TYPE_REST = 'rest';
40:
41: 42: 43:
44: const HTTP_OK = 200;
45: const HTTP_CREATED = 201;
46: const HTTP_MULTI_STATUS = 207;
47: const HTTP_BAD_REQUEST = 400;
48: const HTTP_UNAUTHORIZED = 401;
49: const HTTP_FORBIDDEN = 403;
50: const HTTP_NOT_FOUND = 404;
51: const HTTP_METHOD_NOT_ALLOWED = 405;
52: const HTTP_NOT_ACCEPTABLE = 406;
53: const HTTP_INTERNAL_ERROR = 500;
54:
55:
56: 57: 58: 59: 60:
61: protected static $_apiTypes = array(self::API_TYPE_REST);
62:
63: 64: 65:
66: protected $_authUser;
67:
68: 69: 70:
71: public function run()
72: {
73:
74: try {
75:
76: $response = Mage::getSingleton('api2/response');
77: } catch (Exception $e) {
78: Mage::logException($e);
79:
80: if (!headers_sent()) {
81: header('HTTP/1.1 ' . self::HTTP_INTERNAL_ERROR);
82: }
83: echo 'Service temporary unavailable';
84: return;
85: }
86:
87: try {
88:
89: $request = Mage::getSingleton('api2/request');
90:
91: $renderer = Mage_Api2_Model_Renderer::factory($request->getAcceptTypes());
92: } catch (Exception $e) {
93: Mage::logException($e);
94:
95: $response->setHttpResponseCode(self::HTTP_INTERNAL_ERROR)
96: ->setBody('Service temporary unavailable')
97: ->sendResponse();
98: return;
99: }
100:
101: try {
102:
103: $apiUser = $this->_authenticate($request);
104:
105: $this->_route($request)
106: ->_allow($request, $apiUser)
107: ->_dispatch($request, $response, $apiUser);
108:
109: if ($response->getHttpResponseCode() == self::HTTP_CREATED) {
110:
111: throw new Mage_Api2_Exception('Resource was partially created', self::HTTP_CREATED);
112: }
113:
114: if ($response->isException()) {
115: throw new Mage_Api2_Exception('Unhandled simple errors.', self::HTTP_INTERNAL_ERROR);
116: }
117: } catch (Exception $e) {
118: Mage::logException($e);
119: $this->_renderException($e, $renderer, $response);
120: }
121:
122: $response->sendResponse();
123: }
124:
125: 126: 127: 128: 129: 130: 131:
132: public function internalCall(Mage_Api2_Model_Request $request, Mage_Api2_Model_Response $response)
133: {
134: $apiUser = $this->_getAuthUser();
135: $this->_route($request)
136: ->_allow($request, $apiUser)
137: ->_dispatch($request, $response, $apiUser);
138: }
139:
140: 141: 142: 143: 144: 145: 146:
147: protected function _authenticate(Mage_Api2_Model_Request $request)
148: {
149:
150: $authManager = Mage::getModel('api2/auth');
151:
152: $this->_setAuthUser($authManager->authenticate($request));
153: return $this->_getAuthUser();
154: }
155:
156: 157: 158: 159: 160: 161: 162:
163: protected function _setAuthUser(Mage_Api2_Model_Auth_User_Abstract $authUser)
164: {
165: $this->_authUser = $authUser;
166: return $this;
167: }
168:
169: 170: 171: 172: 173: 174:
175: protected function _getAuthUser()
176: {
177: if (!$this->_authUser) {
178: throw new Exception("Mage_Api2_Model_Server::internalCall() seems to be executed "
179: . "before Mage_Api2_Model_Server::run()");
180: }
181: return $this->_authUser;
182: }
183:
184: 185: 186: 187: 188: 189: 190:
191: protected function _route(Mage_Api2_Model_Request $request)
192: {
193:
194: $router = Mage::getModel('api2/router');
195:
196: $router->routeApiType($request, true)
197: ->setRoutes($this->_getConfig()->getRoutes($request->getApiType()))
198: ->route($request);
199:
200: return $this;
201: }
202:
203: 204: 205: 206: 207: 208: 209: 210:
211: protected function _allow(Mage_Api2_Model_Request $request, Mage_Api2_Model_Auth_User_Abstract $apiUser)
212: {
213:
214: $globalAcl = Mage::getModel('api2/acl_global');
215:
216: if (!$globalAcl->isAllowed($apiUser, $request->getResourceType(), $request->getOperation())) {
217: throw new Mage_Api2_Exception('Access denied', self::HTTP_FORBIDDEN);
218: }
219: return $this;
220: }
221:
222: 223: 224: 225: 226: 227: 228: 229: 230:
231: protected function _dispatch(
232: Mage_Api2_Model_Request $request,
233: Mage_Api2_Model_Response $response,
234: Mage_Api2_Model_Auth_User_Abstract $apiUser
235: )
236: {
237:
238: $dispatcher = Mage::getModel('api2/dispatcher');
239: $dispatcher->setApiUser($apiUser)->dispatch($request, $response);
240:
241: return $this;
242: }
243:
244: 245: 246: 247: 248:
249: protected function _getConfig()
250: {
251: return Mage::getModel('api2/config');
252: }
253:
254: 255: 256: 257: 258: 259: 260: 261: 262:
263: protected function _renderException(Exception $exception, Mage_Api2_Model_Renderer_Interface $renderer,
264: Mage_Api2_Model_Response $response
265: ) {
266: if ($exception instanceof Mage_Api2_Exception && $exception->getCode()) {
267: $httpCode = $exception->getCode();
268: } else {
269: $httpCode = self::HTTP_INTERNAL_ERROR;
270: }
271: try {
272:
273: $response->setException($exception);
274:
275: $messages = array();
276:
277:
278: foreach ($response->getException() as $exception) {
279: $message = array('code' => $exception->getCode(), 'message' => $exception->getMessage());
280:
281: if (Mage::getIsDeveloperMode()) {
282: $message['trace'] = $exception->getTraceAsString();
283: }
284: $messages['messages']['error'][] = $message;
285: }
286:
287: $response->setBody($renderer->render($messages));
288: $response->setHeader('Content-Type', sprintf(
289: '%s; charset=%s', $renderer->getMimeType(), Mage_Api2_Model_Response::RESPONSE_CHARSET
290: ));
291: } catch (Exception $e) {
292:
293: $httpCode = $e->getCode() == self::HTTP_NOT_ACCEPTABLE
294: ? self::HTTP_NOT_ACCEPTABLE
295: : self::HTTP_INTERNAL_ERROR;
296:
297:
298: $response->setBody($e->getMessage());
299: $response->setHeader('Content-Type', 'text/plain; charset=' . Mage_Api2_Model_Response::RESPONSE_CHARSET);
300: }
301: $response->setHttpResponseCode($httpCode);
302:
303: return $this;
304: }
305:
306: 307: 308: 309: 310:
311: public static function getApiTypes()
312: {
313: return self::$_apiTypes;
314: }
315: }
316: