public function testClassHook() { foreach (array("beforeSave", "afterSave", "beforeUpdate", "afterUpdate", "beforeDelete", "afterDelete") as $hookName) { $count = 42; call_user_func(array("LeanCloud\\Engine\\Cloud", $hookName), "TestObject", function ($obj, $user) use(&$count) { $count += 1; }); Cloud::runHook("TestObject", $hookName, null, null); $this->assertEquals(43, $count); } }
/** * Dispatch class hook and render result * * @param string $className * @param string $hookName * @param array $body JSON decoded body params */ private function dispatchHook($className, $hookName, $body) { $json = $body["object"]; $json["__type"] = "Object"; $json["className"] = $className; $obj = LeanClient::decode($json, null); // set hook marks to prevent infinite loop. For example if user // invokes `$obj->save` in an afterSave hook, API will not again // invoke afterSave if we set hook marks. foreach (array("__before", "__after", "__after_update") as $key) { if (isset($json[$key])) { $obj->set($key, $json[$key]); } } // in beforeUpdate hook, attach updatedKeys to object so user // can detect changed keys in hook. if (isset($json["_updatedKeys"])) { $obj->updatedKeys = $json["_updatedKeys"]; } $meta["remoteAddress"] = $this->env["REMOTE_ADDR"]; try { $result = Cloud::runHook($className, $hookName, $obj, LeanUser::getCurrentUser(), $meta); } catch (FunctionError $err) { $this->renderError($err->getMessage(), $err->getCode()); } if ($hookName == "beforeDelete") { $this->renderJSON(array()); } else { if (strpos($hookName, "after") === 0) { $this->renderJSON(array("result" => "ok")); } else { $outObj = $result; // Encode result object to type-less literal JSON $this->renderJSON($outObj->toJSON()); } } }
/** * Dispatch class hook and render result * * @param string $className * @param string $hookName * @param array $body JSON decoded body params */ private function dispatchHook($className, $hookName, $body) { $verified = false; if (strpos($hookName, "before") === 0) { $verified = Client::verifyHookSign("__before_for_{$className}", $body["object"]["__before"]); } else { $verified = Client::verifyHookSign("__after_for_{$className}", $body["object"]["__after"]); } if (!$verified) { error_log("Invalid hook sign for {$hookName} {$className}" . " from {$this->env['REMOTE_ADDR']}"); $this->renderError("Unauthorized.", 401, 401); } $json = $body["object"]; $json["__type"] = "Object"; $json["className"] = $className; $obj = Client::decode($json, null); // set hook marks to prevent infinite loop. For example if user // invokes `$obj->save` in an afterSave hook, API will not again // invoke afterSave if we set hook marks. if (strpos($hookName, "before") === 0) { if (isset($json["__before"])) { $obj->set("__before", $json["__before"]); } else { $obj->disableBeforeHook(); } } else { if (isset($json["__after"])) { $obj->set("__after", $json["__after"]); } else { $obj->disableAfterHook(); } } // in beforeUpdate hook, attach updatedKeys to object so user // can detect changed keys in hook. if (isset($json["_updatedKeys"])) { $obj->updatedKeys = $json["_updatedKeys"]; } $meta["remoteAddress"] = $this->env["REMOTE_ADDR"]; try { $result = Cloud::runHook($className, $hookName, $obj, User::getCurrentUser(), $meta); } catch (FunctionError $err) { $this->renderError($err->getMessage(), $err->getCode()); } if ($hookName == "beforeDelete") { $this->renderJSON(array()); } else { if (strpos($hookName, "after") === 0) { $this->renderJSON(array("result" => "ok")); } else { $outObj = $result; // Encode result object to type-less literal JSON $this->renderJSON($outObj->toJSON()); } } }