public function __construct() { $c = get_class($this); if (!isset(self::$_m[$c])) { self::$_m[$c] = \ebi\Annotation::get_class($c, 'var', null, __CLASS__); } if (method_exists($this, '__init__')) { $args = func_get_args(); call_user_func_array([$this, '__init__'], $args); } }
public static function parse($varname, $doc) { $result = []; if (preg_match_all("/@" . $varname . "\\s+([^\\s]+)\\s+\\\$(\\w+)(.*)/", $doc, $m)) { foreach (array_keys($m[2]) as $n) { $summary = $m[3][$n]; $opt = []; if (strpos($summary, '@[') !== false) { list($summary, $anon) = explode('@[', $summary, 2); $opt = \ebi\Annotation::activation('@[' . $anon); } $result[] = new static($m[2][$n], $m[1][$n], $summary, $opt); } } return $result; }
/** * 前処理、入力値のバリデーションやログイン処理を行う * __before__メソッドを定義することで拡張する */ public function before() { list(, $method) = explode('::', $this->get_selected_pattern()['action']); $annon = \ebi\Annotation::get_method(get_class($this), $method, ['http_method', 'request', 'user_role']); if (isset($annon['http_method']['value']) && strtoupper($annon['http_method']['value']) != \ebi\Request::method()) { throw new \ebi\exception\BadMethodCallException('Method Not Allowed'); } if (isset($annon['request'])) { foreach ($annon['request'] as $k => $an) { if (isset($an['type'])) { try { \ebi\Validator::type($k, $this->in_vars($k), $an); } catch (\ebi\exception\InvalidArgumentException $e) { \ebi\Exceptions::add($e, $k); } \ebi\Validator::value($k, $this->in_vars($k), $an); } } } \ebi\Exceptions::throw_over(); if (method_exists($this, '__before__')) { $this->__before__(); } if ($this->has_object_plugin('before_flow_action_request')) { /** * 前処理 * @param \ebi\flow\Request $arg1 */ $this->call_object_plugin_funcs('before_flow_action_request', $this); } if (!$this->is_user_logged_in() && (isset($this->login_anon) || $this->has_object_plugin('login_condition'))) { $this->login_required(); } if ($this->is_user_logged_in() && (isset($annon['user_role']) || isset($this->login_anon['user_role']))) { if (!in_array(\ebi\UserRole::class, \ebi\Util::get_class_traits(get_class($this->user()))) || isset($this->login_anon['user_role']) && !in_array($this->login_anon['user_role'], $this->user()->get_role()) || isset($annon['user_role']['value']) && !in_array($annon['user_role']['value'], $this->user()->get_role())) { throw new \ebi\exception\NotPermittedException(); } } }
private static function automap($url, $class, $name, $idx) { $result = []; try { $r = new \ReflectionClass(str_replace('.', '\\', $class)); $d = substr($r->getFilename(), 0, -4); foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $m) { if (!$m->isStatic() && substr($m->getName(), 0, 1) != '_') { $suffix = ''; $auto_anon = \ebi\Annotation::get_method($r->getName(), $m->getName(), 'automap'); if (is_array($auto_anon)) { $base_name = $m->getName(); if (isset($auto_anon['suffix'])) { $suffix = $auto_anon['suffix']; unset($auto_anon['suffix']); } if (isset($auto_anon['name'])) { $base_name = $auto_anon['name']; unset($auto_anon['name']); } $murl = $url . ($m->getName() == 'index' ? '' : ($url == '' ? '' : '/') . $base_name) . str_repeat('/(.+)', $m->getNumberOfRequiredParameters()); $result[$murl . $suffix] = ['name' => $name . '/' . $base_name, 'action' => $class . '::' . $m->getName(), '@' => $d, 'idx' => $idx]; if (!empty($auto_anon)) { $result[$murl . $suffix] = array_merge($result[$murl . $suffix], $auto_anon); } } } } } catch (\ReflectionException $e) { throw new \ebi\exception\InvalidArgumentException($class . ' not found'); } return $result; }
public function __construct() { call_user_func_array('parent::__construct', func_get_args()); if (func_num_args() == 1) { foreach (func_get_arg(0) as $n => $v) { switch ($n) { case '_has_hierarchy_': case '_class_id_': case '_hierarchy_': $this->{$n} = $v; break; default: } } } $p = get_class($this); if (!isset($this->_class_id_)) { $this->_class_id_ = $p; } if (isset(self::$_dao_[$this->_class_id_])) { foreach (self::$_dao_[$this->_class_id_]->_has_dao_ as $name => $dao) { $this->{$name}($dao); } return; } $annotation = \ebi\Annotation::get_class($p, ['readonly', 'table']); $anon = [null, isset($annotation['table']['name']) ? $annotation['table']['name'] : null, $annotation['readonly'] !== null]; if (empty(self::$_connection_settings_)) { /** * DBの接続情報 * * `````````````````````````````````````````````````````````` * [ * 'ebi.SessionDao'=>[ // ebi.SessionDaoモデルの接続情報となります * 'type'=>'ebi.MysqlConnector', * 'name'=>'ebitest' * ], * '*'=>[ // *を指定した場合は他のパターンにマッチしたなかったもの全てがこの接続になります * 'type'=>'ebi.MysqlConnector', * 'name'=>'ebitest' * ], * ] * `````````````````````````````````````````````````````````` * * @param string{} $connection 接続情報配列 */ self::$_connection_settings_ = \ebi\Conf::gets('connection'); if (empty(self::$_connection_settings_)) { self::$_connection_settings_ = ['*' => ['host' => getcwd()]]; } } // find connection settings $findns = explode('\\', $p); while (!array_key_exists(implode('.', $findns), self::$_connection_settings_) && !empty($findns)) { array_pop($findns); } if (empty($findns) && !isset(self::$_connection_settings_['*'])) { throw new \ebi\exception\ConnectionException('could not find the connection settings `' . $p . '`'); } $anon[0] = empty($findns) ? '*' : implode('.', $findns); if (empty($anon[1])) { $table_class = $p; $parent_class = get_parent_class($p); $ref = new \ReflectionClass($parent_class); while (true) { $ref = new \ReflectionClass($parent_class); if (__CLASS__ == $parent_class || $ref->isAbstract()) { break; } $table_class = $parent_class; $parent_class = get_parent_class($parent_class); } $table_class = preg_replace("/^.*\\\\(.+)\$/", "\\1", $table_class); $anon[1] = strtolower($table_class[0]); for ($i = 1; $i < strlen($table_class); $i++) { $anon[1] .= ctype_lower($table_class[$i]) ? $table_class[$i] : '_' . strtolower($table_class[$i]); } } $db_settings = self::get_db_settings($anon[0], $p); $prefix = isset($db_settings['prefix']) ? $db_settings['prefix'] : ''; $upper = isset($db_settings['upper']) && $db_settings['upper'] === true; $lower = isset($db_settings['lower']) && $db_settings['lower'] === true; self::$_con_[get_called_class()] = self::$_connections_[$anon[0]]->connector(); $set_table_name = function ($name, $class) use($prefix, $upper, $lower) { $name = $prefix . $name; if ($upper) { $name = strtoupper($name); } else { if ($lower) { $name = strtolower($name); } } return $name; }; self::$_co_anon_[$p] = $anon; self::$_co_anon_[$p][1] = $set_table_name(self::$_co_anon_[$p][1], $p); $has_hierarchy = isset($this->_hierarchy_) ? $this->_hierarchy_ - 1 : $this->_has_hierarchy_; $root_table_alias = 't' . self::$_cnt_++; $_self_columns_ = $_where_columns_ = $_conds_ = $_join_conds_ = $_alias_ = $_has_many_conds_ = $_has_dao_ = []; $prop = $last_cond_column = []; $ref = new \ReflectionClass($this); foreach ($ref->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $prop) { if ($prop->getName()[0] != '_' && $this->prop_anon($prop->getName(), 'extra') !== true) { $props[] = $prop->getName(); } } while (!empty($props)) { $name = array_shift($props); $anon_cond = $this->prop_anon($name, 'cond'); $column_type = $this->prop_anon($name, 'type'); if (empty($column_type)) { if ($name == 'id') { $this->prop_anon($name, 'type', 'serial', true); } else { if ($name == 'created_at' || $name == 'create_date' || $name == 'created') { $this->prop_anon($name, 'type', 'timestamp', true); $this->prop_anon($name, 'auto_now_add', true, true); } else { if ($name == 'updated_at' || $name == 'update_date' || $name == 'modified') { $this->prop_anon($name, 'type', 'timestamp', true); $this->prop_anon($name, 'auto_now', true, true); } else { if ($name == 'code') { $this->prop_anon($name, 'type', 'string', true); $this->prop_anon($name, 'auto_code_add', true, true); } } } } $column_type = $this->prop_anon($name, 'type', 'string'); } if ($this->prop_anon($name, 'type') == 'serial') { $this->prop_anon($name, 'primary', true, true); } $column = new \ebi\Column(); $column->name($name); $column->column($this->prop_anon($name, 'column', $name)); $column->column_alias('c' . self::$_cnt_++); if ($anon_cond === null) { if (ctype_upper($column_type[0]) && class_exists($column_type) && is_subclass_of($column_type, __CLASS__)) { throw new \ebi\exception\InvalidQueryException('undef ' . $name . ' annotation `cond`'); } $column->table($this->table()); $column->table_alias($root_table_alias); $column->primary($this->prop_anon($name, 'primary', false) || $column_type === 'serial'); $column->auto($column_type === 'serial'); $_alias_[$column->column_alias()] = $name; $_self_columns_[$name] = $column; } else { if (false !== strpos($anon_cond, '(')) { $is_has = class_exists($column_type) && is_subclass_of($column_type, __CLASS__); $is_has_many = $is_has && $this->prop_anon($name, 'attr') === 'a'; if ((!$is_has || $has_hierarchy > 0) && preg_match("/^(.+)\\((.*)\\)(.*)\$/", $anon_cond, $match)) { list(, $self_var, $conds_string, $has_var) = $match; $conds = []; $ref_table = $ref_table_alias = null; if (!empty($conds_string)) { foreach (explode(',', $conds_string) as $cond) { $tcc = explode('.', $cond, 3); switch (sizeof($tcc)) { case 1: $conds[] = \ebi\Column::cond_instance($tcc[0], 'c' . self::$_cnt_++, $this->table(), $root_table_alias); break; case 2: list($t, $c1) = $tcc; $ref_table = $set_table_name($t, $p); $ref_table_alias = 't' . self::$_cnt_++; $conds[] = \ebi\Column::cond_instance($c1, 'c' . self::$_cnt_++, $ref_table, $ref_table_alias); break; case 3: list($t, $c1, $c2) = $tcc; $ref_table = $set_table_name($t, $p); $ref_table_alias = 't' . self::$_cnt_++; $conds[] = \ebi\Column::cond_instance($c1, 'c' . self::$_cnt_++, $ref_table, $ref_table_alias); $conds[] = \ebi\Column::cond_instance($c2, 'c' . self::$_cnt_++, $ref_table, $ref_table_alias); break; default: throw new \ebi\exception\InvalidAnnotationException('annotation error : `' . $name . '`'); } } } if ($is_has_many) { if (empty($has_var)) { throw new \ebi\exception\InvalidAnnotationException('annotation error : `' . $name . '`'); } $dao = new $column_type(['_class_id_' => $p . '___' . self::$_cnt_++]); $_has_many_conds_[$name] = [$dao, $has_var, $self_var]; } else { if ($is_has) { if (empty($has_var)) { throw new \ebi\exception\InvalidAnnotationException('annotation error : `' . $name . '`'); } $dao = new $column_type(['_class_id_' => $p . '___' . self::$_cnt_++, '_hierarchy_' => $has_hierarchy]); $this->{$name}($dao); $_has_many_conds_[$name] = [$dao, $has_var, $self_var]; } else { if ($self_var[0] == '@') { $cond_var = null; $cond_name = substr($self_var, 1); if (strpos($cond_name, '.') !== false) { list($cond_name, $cond_var) = explode('.', $cond_name); } if (!isset($last_cond_column[$cond_name]) && in_array($cond_name, $props)) { $props[] = $name; continue; } $cond_column = clone $last_cond_column[$cond_name]; if (isset($cond_var)) { $cond_column->column($cond_var); $cond_column->column_alias('c' . self::$_cnt_++); } array_unshift($conds, $cond_column); } else { array_unshift($conds, \ebi\Column::cond_instance($self_var, 'c' . self::$_cnt_++, $this->table(), $root_table_alias)); } $column->table($ref_table); $column->table_alias($ref_table_alias); $_alias_[$column->column_alias()] = $name; if (sizeof($conds) % 2 != 0) { throw new \ebi\exception\InvalidQueryException($name . '[' . $column_type . '] is illegal condition'); } if ($this->prop_anon($name, 'join', false)) { $this->prop_anon($name, 'get', false, true); $this->prop_anon($name, 'set', false, true); for ($i = 0; $i < sizeof($conds); $i += 2) { $_join_conds_[$name][] = [$conds[$i], $conds[$i + 1]]; } } else { for ($i = 0; $i < sizeof($conds); $i += 2) { $_conds_[] = [$conds[$i], $conds[$i + 1]]; } } $_where_columns_[$name] = $column; } } if (!empty($conds)) { $cond_column = clone $conds[sizeof($conds) - 1]; $cond_column->column($column->column()); $cond_column->column_alias('c' . self::$_cnt_++); $last_cond_column[$name] = $cond_column; } } } else { if ($anon_cond[0] === '@') { $cond_name = substr($anon_cond, 1); if (in_array($cond_name, $props)) { $props[] = $name; continue; } if (isset($_self_columns_[$cond_name])) { $column->table($_self_columns_[$cond_name]->table()); $column->table_alias($_self_columns_[$cond_name]->table_alias()); } else { if (isset($_where_columns_[$cond_name])) { $column->table($_where_columns_[$cond_name]->table()); $column->table_alias($_where_columns_[$cond_name]->table_alias()); } else { throw new \ebi\exception\InvalidQueryException('undef var `' . $name . '`'); } } $_alias_[$column->column_alias()] = $name; $_where_columns_[$name] = $column; } } } } self::$_dao_[$this->_class_id_] = (object) ['_self_columns_' => $_self_columns_, '_where_columns_' => $_where_columns_, '_conds_' => $_conds_, '_join_conds_' => $_join_conds_, '_alias_' => $_alias_, '_has_dao_' => $_has_dao_, '_has_many_conds_' => $_has_many_conds_]; }
/** * クラスのドキュメント * @param string $class */ public static function class_info($class) { $info = new \ebi\Dt\DocInfo(); $r = new \ReflectionClass(self::get_class_name($class)); if ($r->getFilename() === false || !is_file($r->getFileName())) { throw new \ebi\exception\InvalidArgumentException('`' . $class . '` file not found.'); } $src = self::get_reflection_source($r); $document = self::trim_doc($r->getDocComment()); $info->name($r->getName()); $info->document(trim(preg_replace('/@.+/', '', $document))); $info->set_opt('filename', $r->getFileName()); $info->set_opt('extends', $r->getParentClass() === false ? null : $r->getParentClass()->getName()); $info->set_opt('abstract', $r->isAbstract()); $see = []; if (preg_match_all("/@see\\s+([\\w\\.\\:\\\\]+)/", $document, $m)) { foreach ($m[1] as $v) { $v = trim($v); if (strpos($v, '://') !== false) { $see[$v] = ['type' => 'url', 'url' => $v]; } else { if (strpos($v, '::') !== false) { list($class, $method) = explode('::', 2); $see[$v] = ['type' => 'method', 'class' => $class, 'method' => $method]; } else { if (substr($v, -1) != ':') { $see[$v] = ['type' => 'class', 'class' => $class]; } } } } } $methods = []; foreach ($r->getMethods() as $method) { if (substr($method->getName(), 0, 1) != '_' && $method->isPublic() && !$method->isStatic()) { $ignore = ['getIterator']; if (!in_array($method->getName(), $ignore)) { $method_document = self::get_method_document($method); list($desc) = explode(PHP_EOL, trim(preg_replace('/@.+/', '', $method_document))); $method_info = new \ebi\Dt\DocInfo(); $method_info->name($method->getName()); $method_info->document($desc); $methods[] = $method_info; } } } $info->set_opt('methods', $methods); $properties = []; $anon = \ebi\Annotation::get_class(self::get_class_name($class), 'var', 'summary'); $is_obj = $r->isSubclassOf(\ebi\Object::class); foreach ($r->getProperties() as $prop) { if ($prop->isPublic() || $is_obj && $prop->isProtected()) { $name = $prop->getName(); if ($name[0] != '_' && !$prop->isStatic()) { $properties[$name] = new \ebi\Dt\DocParam($name, isset($anon[$name]['type']) ? $anon[$name]['type'] : 'mixed', isset($anon[$name]['summary']) ? $anon[$name]['summary'] : null, ['hash' => $prop->isPublic() || !(isset($anon[$name]['hash']) && $anon[$name]['hash'] === false)]); } } } $info->set_opt('properties', $properties); $config_list = []; foreach (["/Conf::gets\\(([\"\\'])(.+?)\\1/" => 'mixed[]', "/Conf::get\\(([\"\\'])(.+?)\\1/" => 'mixed', "/self::get_self_conf_get\\(([\"\\'])(.+?)\\1/" => 'mixed'] as $preg => $default_type) { if (preg_match_all($preg, $src, $m, PREG_OFFSET_CAPTURE)) { foreach ($m[2] as $k => $v) { // 呼び出しが重複したら先にドキュメントがあった方 if (!array_key_exists($v[0], $config_list) || !$config_list[$v[0]]->has_params()) { $conf_info = \ebi\Dt\DocInfo::parse($v[0], $src, $m[0][$k][1]); $conf_info->set_opt('def', \ebi\Conf::exists($r->getName(), $v[0])); if (!$conf_info->has_params()) { $conf_info->add_params(new \ebi\Dt\DocParam('val', $default_type)); } $config_list[$v[0]] = $conf_info; } } } } ksort($config_list); $info->set_opt('config_list', $config_list); $call_plugins = []; foreach (["/->get_object_plugin_funcs\\(([\"\\'])(.+?)\\1/", "/->call_object_plugin_funcs\\(([\"\\'])(.+?)\\1/", "/::call_class_plugin_funcs\\(([\"\\'])(.+?)\\1/", "/->call_object_plugin_func\\(([\"\\'])(.+?)\\1/", "/::call_class_plugin_func\\(([\"\\'])(.+?)\\1/"] as $preg) { if (preg_match_all($preg, $src, $m, PREG_OFFSET_CAPTURE)) { foreach ($m[2] as $k => $v) { $call_plugins[$v[0]] = \ebi\Dt\DocInfo::parse($v[0], $src, $m[0][$k][1]); $call_plugins[$v[0]]->set_opt('added', []); } } } $traits = []; $parent = new \ReflectionClass($r->getName()); do { $traits = array_merge($traits, $parent->getTraitNames()); if (($parent = $parent->getParentClass()) === false) { break; } } while (true); if (in_array('ebi\\Plugin', $traits)) { foreach (\ebi\Conf::get_class_plugin($r->getName()) as $o) { $pr = new \ReflectionClass(is_object($o) ? get_class($o) : $o); foreach ($pr->getMethods(\ReflectionMethod::IS_PUBLIC) as $m) { foreach (array_keys($call_plugins) as $method_name) { if ($m->getName() == $method_name) { $added = $call_plugins[$method_name]->opt('added'); $added[] = $pr->getName(); $call_plugins[$method_name]->set_opt('added', $added); } } } } } $info->set_opt('plugins', $call_plugins); return $info; }