1: <?php
2: /**
3: * Represents a JSON action that is defined as a controller method.
4: *
5: * This subclass enforces the at-most-one-parameter-with-type-hinting actions.
6: *
7: * @since 1.0
8: * @package Components
9: * @author Konstantinos Filios <konfilios@gmail.com>
10: */
11: class CBJsonInlineAction extends CInlineAction
12: {
13: /**
14: * Decode json input.
15: *
16: * @param string $jsonInput
17: * @return mixed
18: * @throws CHttpException
19: */
20: protected function decodeJsonParam($jsonInput, $paramName)
21: {
22: // Object is optional
23: if (empty($jsonInput)) {
24: // Input string is empty, nothing to json-decode
25: return null;
26: }
27:
28: // Decode the object into an array
29: $objectOutput = json_decode($jsonInput, true);
30:
31: if (($objectOutput === null) && ($jsonInput !== 'null')) {
32: // Json_decode failed
33: throw new CHttpException(400, 'Could not JSON-decode parameter "'.$paramName.'"');
34: }
35:
36: return $objectOutput;
37: }
38:
39: /**
40: * Executes a method of an object with the supplied named parameters.
41: *
42: * This method is internally used and implements all Restful logic.
43: *
44: * @param mixed $object the object whose method is to be executed
45: * @param ReflectionMethod $method the method reflection
46: * @param array $paramValues the named parameters
47: * @return mixed whether the named parameters are valid
48: */
49: protected function runWithParamsInternal($object, $method, $paramValues)
50: {
51: $methodParams = $method->getParameters();
52:
53: // $methodParamsCount = count($methodParams);
54: // if ($methodParamsCount != 1) {
55: // throw new CHttpException(500, 'Restful action '
56: // .$method->class.'::'.$method->name.' expects '.$methodParamsCount
57: // .' parameters instead of 1');
58: // }
59:
60: if (isset($paramValues['jsin'])) {
61: $firstMethodParam = $methodParams[0];
62: /* @var $firstMethodParam ReflectionParameter */
63:
64: $paramValues[$firstMethodParam->name] = $paramValues['jsin'];
65: unset($paramValues['jsin']);
66: }
67:
68: // Extract invocation params
69: $invokeParams = array();
70: foreach ($methodParams as $methodParam) {
71: /* @var $methodParam ReflectionParameter */
72: $paramName = $methodParam->name;
73:
74: if (isset($paramValues[$paramName])) {
75: // A value exists, let's parse it
76: try {
77: $paramValue = CBJson::decodeAssoc($paramValues[$paramName]);
78: } catch (Exception $e) {
79: $paramValue = $paramValues[$paramName];
80: }
81: $methodParamClass = $methodParam->getClass();
82: /* @var $methodParamClass ReflectionClass */
83:
84: if (!empty($methodParamClass)) {
85: //
86: // Expecting a value of given class
87: //
88: $methodParamClassName = $methodParamClass->name;
89:
90: if ($paramValue === null) {
91: $paramObject = null;
92: } else {
93: $paramObject = new $methodParamClassName();
94:
95: if (!is_a($paramObject, 'CBJsonModel')) {
96: throw new CHttpException(500, $method->class.'::'.$method->name
97: .': Parameter "'.$paramName.'" is of class '
98: .$methodParamClassName.' which is not a subtype of CBJsonModel.');
99: }
100: $paramObject->copyFrom($paramValue);
101: }
102:
103: $invokeParams[] = $paramObject;
104:
105: } else if ($methodParam->isArray()) {
106: //
107: // Expecting array
108: //
109: $invokeParams[] = is_array($paramValue) ? $paramValue : array($paramValue);
110:
111: } else if (!is_array($paramValue)) {
112: //
113: // Expecting scalar
114: //
115: $invokeParams[] = $paramValue;
116:
117: } else {
118: //
119: // Bad parameter
120: //
121: throw new CHttpException(400, $method->class.'::'.$method->name
122: .': Invalid argument passed for scalar parameter "'.$paramName.'"');
123: }
124: } else if ($methodParam->isDefaultValueAvailable()) {
125: //
126: // No value found, but param is optional, so use default
127: //
128: $invokeParams[] = $methodParam->getDefaultValue();
129: } else {
130: //
131: // No value found and param is mandatory, die
132: //
133: throw new CHttpException(400, $method->class.'::'.$method->name
134: .': No argument passed for mandatory parameter "'.$paramName.'"');
135: }
136: }
137:
138: // Invoke
139: return $method->invokeArgs($object, $invokeParams);
140: }
141: }
142: