diff --git a/src/core/Model.php b/src/core/Model.php index 55eb0f6..dc4c410 100644 --- a/src/core/Model.php +++ b/src/core/Model.php @@ -2,10 +2,11 @@ namespace MyApp\Core; -use PDOException; use ReflectionClass; use ReflectionProperty; use PDO; +use PDOException; +use Exception; class Model { @@ -23,8 +24,10 @@ class Model global $app; $this->app = $app; - if ( ! is_array($tableMap)) { + if (!is_array($tableMap)) { $this->setInternalTableMap(); + } else { + $this->internalTableMap = $tableMap; } if ('db' === $this->getModelType()) { @@ -32,27 +35,27 @@ class Model } } + /** + * Create PDO Object. + * + * @throws PDOException + */ private function initDb(): void { if (is_null($this->app->db)) { - try { - $this->app->db = new PDO( - 'mysql:host=mysql;dbname=' - . $this->app->config->getDbName() - . ';port=' - . $this->app->config->getDbPort(), - $this->app->config->getDbUser(), - $this->app->config->getDbPassword(), - array( - PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8', - PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, - PDO::ATTR_ERRMODE => true, - PDO::ATTR_PERSISTENT => true, - )); - } catch (PDOException $e) { - echo 'Подключение не удалось: ' . $e->getMessage(); - } - + $this->app->db = new PDO( + 'mysql:host=mysql;dbname=' + .$this->app->config->getDbName() + .';port=' + .$this->app->config->getDbPort(), + $this->app->config->getDbUser(), + $this->app->config->getDbPassword(), + array( + PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8', + PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, + PDO::ATTR_ERRMODE => true, + PDO::ATTR_PERSISTENT => true, + )); } } @@ -64,7 +67,7 @@ class Model $tableMap = ['type' => 'db']; $refClass = new ReflectionClass(get_called_class()); - $tags = $app->parseTagsFromComment($refClass->getDocComment(), + $tags = $app->parseTagsFromComment($refClass->getDocComment(), 'TableName'); if ($tags) { if (array_key_exists('TableName', $tags)) { @@ -93,17 +96,136 @@ class Model $this->internalTableMap = array_key_exists('id', $tableMap) ? $tableMap : ['type' => 'other']; } - if ( ! is_array($this->internalTableMap)) { + if (!is_array($this->internalTableMap)) { $this->internalTableMap = ['type' => 'other']; } } - public static function find() - { - } + /** + * Find records from table. + * + * @param int[]|null $records An array of records to search + * @param string|null $column Column name for search. Default ColumnOption 'id' + * @param string|null $where Selecting results from the table + * by condition. Use property name of object + * Example "{groups} = :groups_id AND {groups} IS NULL" + * @param array $bind Array of a values for bindParam. Work if + * $where not null. + * Example [ ":groups_id" => 0 ] + * @param string $order + * @param string $limit + * @param string $mode Mode of select records. 'in' or 'like'. + * Default is 'in'. + * + * @return array|null + * + * @throws Exception + */ + public static function find( + array $records = null, + string $column = null, + string $where = null, + array $bind = [], + string $order = '', + string $limit = '', + string $mode = 'in' + ): ?array { + $model_name = get_called_class(); + /* @var Model $model */ + $model = new $model_name(); - public static function findOne() - { + $internal_table_map = $model->internalTableMap; + if ('db' === $internal_table_map['type']) { + $select_fields = '`'.implode('`,`', + array_values($internal_table_map['fields'])).'`'; + + $order_sql = ''; + if (!empty($order)) { + $order_sql = "ORDER BY $order"; + } + + $limit_sql = ''; + if (!empty($limit)) { + $limit_sql = "LIMIT $limit "; + } + + $where_sql = ''; + $mode_sql = ''; + if (is_null($where)) { + if (is_null($records) || !count($records)) { + throw new Exception('$records unspecified.'); + } + + if (is_null($column)) { + $column_name = "`{$internal_table_map['id']}`"; + } else { + if (!array_key_exists($column, + $internal_table_map['fields'])) { + throw new Exception('$column not find in model'); + } + $column_name = "`{$internal_table_map['fields'][$column]}`"; + } + + if ('in' === $mode) { + $mode_sql = $column_name.' IN (:mode_param_'.implode(',:mode_param_', + array_keys($records)).') '; + } + if ('like' === $mode) { + $mode_sql = "{$column_name} LIKE :mode_param_".implode(" OR {$column_name} LIKE :mode_param_", + array_keys($records)); + } + + if (empty($mode_sql)) { + throw new Exception('Bad $mode'); + } + $query = $model->app->db->prepare("SELECT $select_fields FROM `{$internal_table_map['name']}` WHERE $mode_sql $order_sql $limit_sql;"); + } else { + $query = $model->app->db->prepare("SELECT $select_fields FROM `{$internal_table_map['name']}` ;"); + } + + $num = 0; + $params = []; + + if (!empty($mode_sql) && 'in' === $mode) { + foreach ($records as $key => $variable) { + $params[$num] = $variable; + $query->bindParam(':mode_param_'.$key, $params[$num]); + ++$num; + } + } + + if (!empty($mode_sql) && 'like' === $mode) { + foreach ($records as $key => $variable) { + $params[$num] = "%{$variable}%"; + $query->bindParam(':mode_param_'.$key, $params[$num]); + ++$num; + } + } + + $query->execute(); + + $data = $query->fetchAll(PDO::FETCH_ASSOC); + if (!empty($data)) { + $out = []; + foreach ($data as $data_single) { + $out_model = new $model_name($internal_table_map); + (function () use ($data_single, $internal_table_map) { + foreach ($internal_table_map['fields'] as $name => $db_field) { + $this->{$name} = $data_single[$db_field]; + } + })->call($out_model); + $out[] = $out_model; + } + + unset($model); + + return $out; + } + } + + unset($model); + + return null; } /**