Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic bin script for generating value objects and mappers from tables #4

Merged
merged 5 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# DealNews Datbase Library


## Factory

The factory creates PDO objects using \DealNews\GetConfigto
Expand Down
252 changes: 252 additions & 0 deletions bin/create_objects.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
#!/usr/bin/env php
<?php

if(file_exists(__DIR__ . '/../vendor/autoload.php')) {
require __DIR__ . '/../vendor/autoload.php';
} elseif (file_exists(__DIR__ . '/../../../autoload.php')) {
require __DIR__ . '/../../../autoload.php';
}

$opts = getopt('', [
'db:',
'schema:',
'table:',
'dir:',
'ini-file:',
'namespace:',
'base-class:',
]);

if(!empty($opts['ini-file'])) {
putenv('DN_INI_FILE=' . $opts['ini-file']);
}

$db = \DealNews\DB\CRUD::factory($opts['db']);

$driver = $db->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);

$sql = "select
table_catalog as table_catalog,
table_schema as table_schema,
table_name as table_name,
column_name as column_name,
ordinal_position as ordinal_position,
column_default as column_default,
is_nullable as is_nullable,
data_type as data_type,
character_maximum_length as character_maximum_length,
character_octet_length as character_octet_length,
numeric_precision as numeric_precision,
numeric_scale as numeric_scale,
datetime_precision as datetime_precision,
character_set_name as character_set_name,
collation_name as collation_name
from
information_schema.columns
where
table_schema='{$opts["schema"]}' and
table_name='{$opts["table"]}'";

$schema = $db->runFetch($sql);

$sql = "select
constraint_name as constraint_name,
column_name as column_name
from
information_schema.key_column_usage
where
table_schema='{$opts["schema"]}' and
table_name='{$opts["table"]}'
order by
constraint_name,
ordinal_position";

$keys = $db->runFetch($sql);

$primary_key = '';

foreach($keys as $key) {
if ($driver === 'mysql' && $key['constraint_name'] == 'PRIMARY') {
$primary_key = $key['column_name'];
break;
} elseif ($driver === 'pgsql' && preg_match('/_pkey$/', $key['constraint_name'])) {
$primary_key = $key['column_name'];
break;
}
}

$properties = [];

foreach($schema as $column) {

switch ($column['data_type']) {

case 'int':
case 'integer':
case 'smallint':
case 'bigint':
case 'tinyint':
case 'year':
$type = 'int';
$def_default = 0;
break;

case 'boolean':
$type = 'bool';
$def_default = true;
break;

case 'float':
case 'double precision':
case 'real':
case 'decimal':
case 'double':
$type = 'float';
$def_default = 0.00;
break;

default:
$type = 'string';
$def_default = '';
}

if (strtoupper($column['is_nullable']) === 'YES') {
$type = "?$type";
$default = null;
} else {
$default = $def_default;
}


if (!empty($column['column_default'])) {
switch ($driver) {
case 'pgsql':
if (preg_match('/^\'(.*?)\'::/', $column['column_default'], $match)) {
$default = $match[1];
}
break;
case 'mysql':
if (strpos($column['column_default'], 'CURRENT_TIMESTAMP') !== 0) {
$default = $column['column_default'];
}
}
}

$properties[$column['column_name']] = [
'type' => $type,
'default' => $default,
];
}

$object_name = rtrim(str_replace(' ', '', ucwords(str_replace('_', ' ', $opts['table']))), 's');



create_value_object($properties, $opts['namespace'], $object_name, $opts['base-class'], $opts['schema'], $opts['table'], $opts['dir']);
create_mapper($properties, $opts['namespace'], $object_name, $opts['base-class'], $opts['schema'], $opts['table'], $opts['dir'], $primary_key);

function create_value_object($properties, $namespace, $object_name, $base_class, $schema, $table, $dir) {

if (!empty($base_class)) {
$base_class = " extends $base_class";
}

$file = "<?php\n\n";

$file .= "namespace $namespace\\Data;\n\n";

$file .= "/**\n";
$file .= " * Value object for $schema.$table\n";
$file .= " *\n";
$file .= " * @package $namespace\n";
$file .= " */\n";

$file .= "class $object_name{$base_class} {\n\n";

$has_datetime = false;

foreach ($properties as $name => $settings) {

if ($settings['default'] === null) {
$default = 'null';
} elseif ($settings['type'] === 'string' || $settings['type'] === '?string') {
$default = "'{$settings["default"]}'";
} else {
$default = $settings["default"];
}

$file .= " /**\n";
$file .= " * @var {$settings['type']}\n";
$file .= " */\n";
if (strpos($settings['type'], 'DateTime') !== false) {
$has_datetime = true;
$file .= " public {$settings['type']} \$$name;\n\n";
} else {
$file .= " public {$settings['type']} \$$name = $default;\n\n";
}
}

if ($has_datetime) {

$file .= " /**\n";
$file .= " * Initialize properties that are objects\n";
$file .= " */\n";
$file .= " public function __construct() {\n";
foreach ($properties as $name => $settings) {
if (strpos($settings['type'], 'DateTime') !== false) {
$file .= " \$this->$name = new \\DateTime();\n";
}
}
$file .= " }\n";

}

$file .= "}\n";

if (!file_exists("$dir/Data")) {
mkdir("$dir/Data", recursive: true);
}

file_put_contents("$dir/Data/$object_name.php", $file);
}

function create_mapper($properties, $namespace, $object_name, $base_class, $schema, $table, $dir, $primary_key) {

$file = "<?php\n";
$file .= "\n";
$file .= "namespace $namespace\\Mapper;\n";
$file .= "\n";
$file .= "class $object_name extends \DealNews\DB\AbstractMapper {\n";
$file .= "\n";
$file .= " /**\n";
$file .= " * Table name\n";
$file .= " */\n";
$file .= " public const TABLE = '$table';\n";
$file .= "\n";
$file .= " /**\n";
$file .= " * Table primary key column name\n";
$file .= " */\n";
$file .= " public const PRIMARY_KEY = '$primary_key';\n";
$file .= "\n";
$file .= " /**\n";
$file .= " * Name of the class the mapper is mapping\n";
$file .= " */\n";
$file .= " public const MAPPED_CLASS = \\$namespace\\Data\\$object_name::class;\n";
$file .= "\n";
$file .= " /**\n";
$file .= " * Defines the properties that are mapped and any\n";
$file .= " * additional information needed to map them.\n";
$file .= " */\n";
$file .= " protected const MAPPING = [\n";
foreach (array_keys($properties) as $name) {
$file .= " '$name' => [],\n";
}
$file .= " ];\n";
$file .= "}\n";

if (!file_exists("$dir/Mapper")) {
mkdir("$dir/Mapper", recursive: true);
}

file_put_contents("$dir/Mapper/$object_name.php", $file);
}
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"discard-changes": true,
"sort-packages": true
},
"bin": [
"bin/create_objects.php"
],
"require": {
"php": "^8.0",
"dealnews/data-mapper": "^3.1.1",
Expand Down Expand Up @@ -43,4 +46,4 @@
"php-cs-fixer fix --config .php-cs-fixer.dist.php src tests"
]
}
}
}
2 changes: 1 addition & 1 deletion src/AbstractMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ abstract class AbstractMapper extends \DealNews\DataMapper\AbstractMapper {
*
* @param \DealNews\DB\CRUD|null $crud Optional CRUD object
*/
public function __construct(CRUD $crud = null) {
public function __construct(?CRUD $crud = null) {
if ($crud !== null) {
$this->crud = $crud;
} elseif (!empty($this::DATABASE_NAME)) {
Expand Down
6 changes: 3 additions & 3 deletions src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Factory {
* @throws \PDOException
* @throws \LogicException
*/
public static function init(string $db, array $options = null, string $type = null): PDO {
public static function init(string $db, ?array $options = null, ?string $type = null): PDO {
static $objs = [];

if (!empty($type)) {
Expand Down Expand Up @@ -91,7 +91,7 @@ public static function build(array $config): PDO {
* @throws \LogicException
* @throws \UnexpectedValueException
*/
public static function loadConfig(array $config, array $options = null, string $type = null): array {
public static function loadConfig(array $config, ?array $options = null, ?string $type = null): array {
if (empty($config['server']) && empty($config['dsn'])) {
throw new \LogicException('Either `server` or `dsn` is required', 3);
} elseif (!empty($config['server'])) {
Expand Down Expand Up @@ -157,7 +157,7 @@ public static function loadConfig(array $config, array $options = null, string $
* @return array
* @throws \LogicException
*/
public static function getConfig(string $db, GetConfig $cfg = null): array {
public static function getConfig(string $db, ?GetConfig $cfg = null): array {
if (empty($cfg)) {
$cfg = new GetConfig();
}
Expand Down
Loading