Skip to content

Update to the new base library (5.0 and PHP 8.x) / Fix Break Compatibility #12

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

Merged
merged 15 commits into from
Mar 19, 2025
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
10 changes: 5 additions & 5 deletions .github/workflows/build-app-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,18 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3

# Login against a Docker registry to pull the GHCR image
# https://github.com/docker/login-action
- name: Log into registry
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
Expand All @@ -85,7 +85,7 @@ jobs:
# Build image locally to enable to run the test
# https://github.com/docker/build-push-action
- name: Build Docker image
uses: docker/build-push-action@v4
uses: docker/build-push-action@v5
with:
context: .
file: docker/Dockerfile
Expand Down
12 changes: 6 additions & 6 deletions builder/BaseScripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

class BaseScripts
{
protected $workdir;
protected string|false $workdir;
protected string $systemOs;

public function __construct()
Expand Down Expand Up @@ -47,9 +47,9 @@ public function fixDir($command)
/**
* Execute the given command by displaying console output live to the user.
*
* @param string|array $cmd : command to be executed
* @return array exit_status : exit status of the executed command
* output : console output of the executed command
* @param array|string $cmd : command to be executed
* @return array|null exit_status : exit status of the executed command
* output : console output of the executed command
* @throws ConfigException
* @throws ConfigNotFoundException
* @throws DependencyInjectionException
Expand All @@ -58,7 +58,7 @@ public function fixDir($command)
* @throws KeyNotFoundException
* @throws ReflectionException
*/
protected function liveExecuteCommand($cmd): ?array
protected function liveExecuteCommand(array|string $cmd): ?array
{
// while (@ ob_end_flush()); // end all output buffers if any

Expand Down Expand Up @@ -122,7 +122,7 @@ protected function replaceVariables($variableValue)
foreach ($args[0] as $arg) {
$variableValue = str_replace(
$arg,
Psr11::container()->get(substr($arg,1, -1)),
Psr11::get(substr($arg,1, -1)),
$variableValue
);
}
Expand Down
78 changes: 65 additions & 13 deletions builder/PostCreateScript.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@

namespace Builder;

use ByJG\Util\JwtWrapper;
use ByJG\AnyDataset\Db\Factory;
use ByJG\JwtWrapper\JwtWrapper;
use ByJG\Util\Uri;
use Composer\Script\Event;
use Exception;
use RecursiveCallbackFilterIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

class PostCreateScript
{
public function execute($workdir, $namespace, $composerName, $phpVersion, $mysqlConnection, $timezone)
public function execute($workdir, $namespace, $composerName, $phpVersion, $mysqlConnection, $timezone): void
{
// ------------------------------------------------
// Defining function to interatively walking through the directories
// Defining function to interactively walking through the directories
$directory = new RecursiveDirectoryIterator($workdir);
$filter = new RecursiveCallbackFilterIterator($directory, function ($current/*, $key, $iterator*/) {
// Skip hidden files and directories.
Expand Down Expand Up @@ -50,8 +52,8 @@ public function execute($workdir, $namespace, $composerName, $phpVersion, $mysql
foreach ($files as $file) {
$contents = file_get_contents("$workdir/$file");
$contents = str_replace('ENV TZ=UTC', "ENV TZ=$timezone", $contents);
$contents = str_replace('php:8.1-fpm', "php:$phpVersion-fpm", $contents);
$contents = str_replace('php81', "php$phpVersionMSimple", $contents);
$contents = str_replace('php:8.3-fpm', "php:$phpVersion-fpm", $contents);
$contents = str_replace('php83', "php$phpVersionMSimple", $contents);
file_put_contents(
"$workdir/$file",
$contents
Expand All @@ -66,7 +68,6 @@ public function execute($workdir, $namespace, $composerName, $phpVersion, $mysql
'config/config-prod.php',
'config/config-test.php',
'docker-compose-dev.yml',
'docker-compose-image.yml'
];
$uri = new Uri($mysqlConnection);
foreach ($files as $file) {
Expand All @@ -87,12 +88,12 @@ public function execute($workdir, $namespace, $composerName, $phpVersion, $mysql
$objects = new RecursiveIteratorIterator($filter);
foreach ($objects as $name => $object) {
$contents = file_get_contents($name);
if (strpos($contents, 'RestReferenceArchitecture') !== false) {
if (str_contains($contents, 'RestReferenceArchitecture')) {
echo "$name\n";

// Replace inside Quotes
$contents = preg_replace(
"/([\'\"])RestReferenceArchitecture(.*?[\'\"])/",
"/(['\"])RestReferenceArchitecture(.*?['\"])/",
'$1' . str_replace('\\', '\\\\\\\\', $namespace) . '$2',
$contents
);
Expand All @@ -114,26 +115,77 @@ public function execute($workdir, $namespace, $composerName, $phpVersion, $mysql
);
}
}

shell_exec("composer update");
shell_exec("git init");
shell_exec("git branch -m main");
shell_exec("git add .");
shell_exec("git commit -m 'Initial commit'");
}

/**
* @param Event $event
* @return void
* @throws Exception
*/
public static function run(Event $event)
{
$workdir = realpath(__DIR__ . '/..');
$stdIo = $event->getIO();

$currentPhpVersion = PHP_MAJOR_VERSION . "." .PHP_MINOR_VERSION;

$validatePHPVersion = function ($arg) {
$validPHPVersions = ['8.1', '8.2', '8.3'];
if (in_array($arg, $validPHPVersions)) {
return $arg;
}
throw new Exception('Only the PHP versions ' . implode(', ', $validPHPVersions) . ' are supported');
};

$validateNamespace = function ($arg) {
if (empty($arg) || !preg_match('/^[A-Z][a-zA-Z0-9]*$/', $arg)) {
throw new Exception('Namespace must be one word in CamelCase');
}
return $arg;
};

$validateComposer = function ($arg) {
if (empty($arg) || !preg_match('/^[a-z0-9-]+\/[a-z0-9-]+$/', $arg)) {
throw new Exception('Invalid Composer name');
}
return $arg;
};

$validateURI = function ($arg) {
$uri = new Uri($arg);
if (empty($uri->getScheme())) {
throw new Exception('Invalid URI');
}
Factory::getRegisteredDrivers($uri->getScheme());
return $arg;
};

$validateTimeZone = function ($arg) {
if (empty($arg) || !in_array($arg, timezone_identifiers_list())) {
throw new Exception('Invalid Timezone');
}
return $arg;
};

$maxRetries = 5;

$stdIo->write("========================================================");
$stdIo->write(" Setup Project");
$stdIo->write(" Answer the questions below");
$stdIo->write("========================================================");
$stdIo->write("");
$stdIo->write("Project Directory: " . $workdir);
$phpVersion = $stdIo->ask("PHP Version [$currentPhpVersion]: ", $currentPhpVersion);
$namespace = $stdIo->ask('Project namespace [MyRest]: ', 'MyRest');
$composerName = $stdIo->ask('Composer name [me/myrest]: ', 'me/myrest');
$mysqlConnection = $stdIo->ask('MySQL connection DEV [mysql://root:mysqlp455w0rd@mysql-container/mydb]: ', 'mysql://root:mysqlp455w0rd@mysql-container/mydb');
$timezone = $stdIo->ask('Timezone [UTC]: ', 'UTC');
$phpVersion = $stdIo->askAndValidate("PHP Version [$currentPhpVersion]: ", $validatePHPVersion, $maxRetries, $currentPhpVersion);
$namespace = $stdIo->askAndValidate('Project namespace [MyRest]: ', $validateNamespace, $maxRetries, 'MyRest');
$composerName = $stdIo->askAndValidate('Composer name [me/myrest]: ', $validateComposer, $maxRetries, 'me/myrest');
$mysqlConnection = $stdIo->askAndValidate('MySQL connection DEV [mysql://root:mysqlp455w0rd@mysql-container/mydb]: ', $validateURI, $maxRetries, 'mysql://root:mysqlp455w0rd@mysql-container/mydb');
$timezone = $stdIo->askAndValidate('Timezone [UTC]: ', $validateTimeZone, $maxRetries, 'UTC');
$stdIo->ask('Press <ENTER> to continue');

$script = new PostCreateScript();
Expand Down
36 changes: 24 additions & 12 deletions builder/Scripts.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use ByJG\DbMigration\Database\MySqlDatabase;
use ByJG\DbMigration\Exception\InvalidMigrationFile;
use ByJG\DbMigration\Migration;
use ByJG\JinjaPhp\Exception\TemplateParseException;
use ByJG\JinjaPhp\Loader\FileSystemLoader;
use ByJG\Util\Uri;
use Composer\Script\Event;
Expand Down Expand Up @@ -39,7 +40,7 @@ public function __construct()
* @throws KeyNotFoundException
* @throws ReflectionException
*/
public static function migrate(Event $event)
public static function migrate(Event $event): void
{
$migrate = new Scripts();
$migrate->runMigrate($event->getArguments());
Expand All @@ -53,7 +54,7 @@ public static function migrate(Event $event)
* @throws KeyNotFoundException
* @throws ReflectionException
*/
public static function genOpenApiDocs(Event $event)
public static function genOpenApiDocs(Event $event): void
{
$build = new Scripts();
$build->runGenOpenApiDocs($event->getArguments());
Expand All @@ -62,14 +63,16 @@ public static function genOpenApiDocs(Event $event)
/**
* @param Event $event
* @return void
* @throws ConfigException
* @throws ConfigNotFoundException
* @throws DependencyInjectionException
* @throws InvalidArgumentException
* @throws InvalidDateException
* @throws KeyNotFoundException
* @throws ReflectionException
* @throws \ByJG\Serializer\Exception\InvalidArgumentException
* @throws TemplateParseException
*/
public static function codeGenerator(Event $event)
public static function codeGenerator(Event $event): void
{
$build = new Scripts();
$build->runCodeGenerator($event->getArguments());
Expand All @@ -86,8 +89,9 @@ public static function codeGenerator(Event $event)
* @throws ReflectionException
* @throws ConfigException
* @throws InvalidDateException
* @throws Exception
*/
public function runMigrate($arguments)
public function runMigrate($arguments): void
{
$argumentList = $this->extractArguments($arguments);
if (isset($argumentList["command"])) {
Expand Down Expand Up @@ -160,7 +164,7 @@ protected function extractArguments(array $arguments, bool $hasCmd = true): arra
* @param array $arguments
* @return void
*/
public function runGenOpenApiDocs(array $arguments)
public function runGenOpenApiDocs(array $arguments): void
{
$docPath = $this->workdir . '/public/docs/';

Expand All @@ -179,15 +183,17 @@ public function runGenOpenApiDocs(array $arguments)
/**
* @param array $arguments
* @return void
* @throws ConfigException
* @throws ConfigNotFoundException
* @throws DependencyInjectionException
* @throws InvalidArgumentException
* @throws InvalidDateException
* @throws KeyNotFoundException
* @throws ReflectionException
* @throws \ByJG\Serializer\Exception\InvalidArgumentException
* @throws TemplateParseException
* @throws Exception
*/
public function runCodeGenerator(array $arguments)
public function runCodeGenerator(array $arguments): void
{
// Get Table Name
$table = null;
Expand Down Expand Up @@ -217,10 +223,11 @@ public function runCodeGenerator(array $arguments)
$save = in_array("--save", $arguments);

/** @var DbDriverInterface $dbDriver */
$dbDriver = Psr11::container()->get(DbDriverInterface::class);
$dbDriver = Psr11::get(DbDriverInterface::class);

$tableDefinition = $dbDriver->getIterator("EXPLAIN " . strtolower($table))->toArray();
$tableIndexes = $dbDriver->getIterator("SHOW INDEX FROM " . strtolower($table))->toArray();
$autoIncrement = false;

// Convert DB Types to PHP Types
foreach ($tableDefinition as $key => $field) {
Expand All @@ -230,6 +237,10 @@ public function runCodeGenerator(array $arguments)
return strtoupper($matches[1]);
}, $field['field']);

if ($field['extra'] == 'auto_increment') {
$autoIncrement = true;
}

switch ($type) {
case 'int':
case 'tinyint':
Expand Down Expand Up @@ -292,15 +303,15 @@ public function runCodeGenerator(array $arguments)
}
}

// Create an array with non nullable fields but primary keys
// Create an array with non-nullable fields but primary keys
$nonNullableFields = [];
foreach ($tableDefinition as $field) {
if ($field['null'] == 'NO' && $field['key'] != 'PRI') {
$nonNullableFields[] = $field["property"];
}
}

// Create an array with non nullable fields but primary keys
// Create an array with non-nullable fields but primary keys
foreach ($tableIndexes as $key => $field) {
$tableIndexes[$key]['camelColumnName'] = preg_replace_callback('/_(.?)/', function($match) {
return strtoupper($match[1]);
Expand All @@ -309,6 +320,7 @@ public function runCodeGenerator(array $arguments)

$data = [
'namespace' => 'RestReferenceArchitecture',
'autoIncrement' => $autoIncrement ? 'yes' : 'no',
'restTag' => ucwords(explode('_', strtolower($table))[0]),
'restPath' => str_replace('_', '/', strtolower($table)),
'className' => preg_replace_callback('/(?:^|_)(.?)/', function($match) {
Expand Down Expand Up @@ -373,7 +385,7 @@ public function runCodeGenerator(array $arguments)
echo "Processing Test for table $table...\n";
$template = $loader->getTemplate('test.php');
if ($save) {
$file = __DIR__ . '/../tests/Functional/Rest/' . $data['className'] . 'Test.php';
$file = __DIR__ . '/../tests/Rest/' . $data['className'] . 'Test.php';
file_put_contents($file, $template->render($data));
echo "File saved in $file\n";
} else {
Expand Down
Loading