This commit is contained in:
Greyscale 2022-06-18 02:40:26 +02:00
parent c0125706e0
commit 2c9b2b7d4f
No known key found for this signature in database
GPG key ID: 74BAFF55434DA4B2
8 changed files with 98 additions and 21 deletions

View file

@ -21,4 +21,4 @@ clean:
${DC_RUN} test vendor/bin/php-cs-fixer fix ${DC_RUN} test vendor/bin/php-cs-fixer fix
test: clear setup migrate regen clean test: clear setup migrate regen clean
${DC_RUN} test vendor/bin/phpunit ${DC_RUN} test vendor/bin/phpunit --stop-on-error --stop-on-failure

View file

@ -18,6 +18,7 @@ class Entity
protected CaseTransformer $transCamel2Snake; protected CaseTransformer $transCamel2Snake;
protected CaseTransformer $transField2Property; protected CaseTransformer $transField2Property;
protected CaseTransformer $transCamel2ScreamingSnake; protected CaseTransformer $transCamel2ScreamingSnake;
protected CaseTransformer $transStudly2Snake;
private Laminator $Laminator; private Laminator $Laminator;
public function __construct() public function __construct()
@ -31,6 +32,7 @@ class Entity
$this->transSnake2Spinal = new CaseTransformer(new Format\SnakeCase(), new Format\SpinalCase()); $this->transSnake2Spinal = new CaseTransformer(new Format\SnakeCase(), new Format\SpinalCase());
$this->transCamel2Snake = new CaseTransformer(new Format\CamelCase(), new Format\SnakeCase()); $this->transCamel2Snake = new CaseTransformer(new Format\CamelCase(), new Format\SnakeCase());
$this->transCamel2ScreamingSnake = new CaseTransformer(new Format\CamelCase(), new Format\ScreamingSnakeCase()); $this->transCamel2ScreamingSnake = new CaseTransformer(new Format\CamelCase(), new Format\ScreamingSnakeCase());
$this->transStudly2Snake = new CaseTransformer(new Format\StudlyCaps(), new Format\SnakeCase());
$this->transField2Property = $this->transCamel2Camel; $this->transField2Property = $this->transCamel2Camel;
} }

View file

@ -128,6 +128,11 @@ class Model extends Entity
return $this->transStudly2Studly->transform($this->getTableSanitised()); return $this->transStudly2Studly->transform($this->getTableSanitised());
} }
public function getEndpointName(): string
{
return $this->transStudly2Snake->transform($this->getClassName());
}
/** /**
* Get the table name, sanitised by removing any prefixes as per Laminator.yml. * Get the table name, sanitised by removing any prefixes as per Laminator.yml.
* *
@ -343,6 +348,7 @@ class Model extends Entity
'app_core' => $this->getLaminator()->getBenzineConfig()->getCore(), 'app_core' => $this->getLaminator()->getBenzineConfig()->getCore(),
//'app_container' => $this->getLaminator()->getBenzineConfig()->getAppContainer(), //'app_container' => $this->getLaminator()->getBenzineConfig()->getAppContainer(),
'class_name' => $this->getClassName(), 'class_name' => $this->getClassName(),
'endpoint_name' => $this->getEndpointName(),
'variable_name' => $this->transStudly2Camel->transform($this->getClassName()), 'variable_name' => $this->transStudly2Camel->transform($this->getClassName()),
'name' => $this->getClassName(), 'name' => $this->getClassName(),
'object_name_plural' => Inflect::pluralize($this->getClassName()), 'object_name_plural' => Inflect::pluralize($this->getClassName()),

View file

@ -16,6 +16,7 @@ class Database
private string $password; private string $password;
private string $database; private string $database;
private string $charset = 'utf8mb4'; private string $charset = 'utf8mb4';
private array $ignoredTables = [];
/** @var callable[] */ /** @var callable[] */
private array $onConnect; private array $onConnect;
@ -45,6 +46,9 @@ class Database
if (isset($config['charset'])) { if (isset($config['charset'])) {
$this->setCharset($config['charset']); $this->setCharset($config['charset']);
} }
if (isset($config['skip_tables'])){
$this->setIgnoredTables($config['skip_tables']);
}
} }
public function onConnect(callable $function): self public function onConnect(callable $function): self
@ -155,6 +159,25 @@ class Database
return new Metadata($this->getAdapter()); return new Metadata($this->getAdapter());
} }
/**
* @return array
*/
public function getIgnoredTables(): array
{
return $this->ignoredTables;
}
/**
* @param array $ignoredTables
* @return Database
*/
public function setIgnoredTables(array $ignoredTables): Database
{
$this->ignoredTables = $ignoredTables;
return $this;
}
public function getArray(): array public function getArray(): array
{ {
return [ return [

View file

@ -5,7 +5,7 @@ namespace {{ namespace }}\Test\Api\Generated;
use {{ app_core }} as App; use {{ app_core }} as App;
use {{ namespace }}\Models\{{ class_name }}Model; use {{ namespace }}\Models\{{ class_name }}Model;
use {{ namespace }}\Services\{{ class_name }}Service; use {{ namespace }}\Services\{{ class_name }}Service;
use Benzine\Tests\RoutesTestCase; use Benzine\Tests\AbstractRoutesTestCase;
/** /**
* @covers \{{ namespace }}\Controllers\{{ class_name }}Controller * @covers \{{ namespace }}\Controllers\{{ class_name }}Controller
@ -15,7 +15,7 @@ use Benzine\Tests\RoutesTestCase;
* @group api * @group api
* @internal * @internal
*/ */
class {{ class_name }}EndpointTest extends RoutesTestCase class {{ class_name }}EndpointTest extends AbstractRoutesTestCase
{ {
public const MODEL_NAME = '{{ class_name }}'; public const MODEL_NAME = '{{ class_name }}';
@ -34,7 +34,7 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
$new{{ class_name }}Array = $new{{ class_name }}->__toArray(); $new{{ class_name }}Array = $new{{ class_name }}->__toArray();
$method = 'PUT'; $method = 'PUT';
$uri = '/v1/{{ controller_route}}'; $uri = '/api/crud/{{ controller_route}}';
$response = $this->request( $response = $this->request(
$method, $method,
@ -84,7 +84,7 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
'Okay', 'Okay',
$responseJson['Status'], $responseJson['Status'],
sprintf( sprintf(
"Verify that request to PUT /v1/{{ controller_route }} returns an \"Status: Okay\" response.\n This failed because %s", "Verify that request to PUT /api/crud/{{ controller_route }} returns an \"Status: Okay\" response.\n This failed because %s",
isset($responseJson['Reason']) ? 'Reason: '.$responseJson['Reason'] : 'No Reason Given' isset($responseJson['Reason']) ? 'Reason: '.$responseJson['Reason'] : 'No Reason Given'
) )
); );
@ -110,7 +110,7 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
'{{ column.field }}' => null, '{{ column.field }}' => null,
{% endfor %} {% endfor %}
]; ];
$response = $this->request('PUT', '/v1/{{ controller_route}}', $new{{ class_name }}); $response = $this->request('PUT', '/api/crud/{{ controller_route}}', $new{{ class_name }});
$this->waypoint('API PUT REST REQUEST'); $this->waypoint('API PUT REST REQUEST');
$body = (string) $response->getBody(); $body = (string) $response->getBody();
$this->assertTrue( $this->assertTrue(
@ -145,8 +145,11 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
*/ */
public function test{{ class_name }}Get($id) public function test{{ class_name }}Get($id)
{ {
$method = "GET";
$uri = "/api/crud/{{ controller_route}}/{$id}";
$this->waypoint('Begin'); $this->waypoint('Begin');
$response = $this->request('GET', '/v1/{{ controller_route}}/{$id}'); $response = $this->request($method, $uri);
$this->waypoint('API GET REST REQUEST'); $this->waypoint('API GET REST REQUEST');
$body = (string) $response->getBody(); $body = (string) $response->getBody();
$this->assertTrue( $this->assertTrue(
@ -159,6 +162,7 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
true true
), ),
"Response was not expected 200 or 400.\n". "Response was not expected 200 or 400.\n".
"Request: {$method} => {$uri}\n".
"Response body is: \n". "Response body is: \n".
" ******************************\n{$body}\n ******************************\n" " ******************************\n{$body}\n ******************************\n"
); );
@ -169,7 +173,7 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
$responseJson = json_decode((string) $body, true); $responseJson = json_decode((string) $body, true);
$this->waypoint('JSON DECODE'); $this->waypoint('JSON DECODE');
$this->assertArrayHasKey('Status', $responseJson); $this->assertArrayHasKey('Status', $responseJson);
$this->assertEquals('Okay', $responseJson['Status'], 'Verify that request to GET /v1/{{ controller_route }}/{$id} returns an "Status: Okay" response. This failed. '.(isset($responseJson['Reason']) ? 'Reason: '.$responseJson['Reason'] : 'No Reason Given')); $this->assertEquals('Okay', $responseJson['Status'], 'Verify that request to GET /api/crud/{{ controller_route }}/{$id} returns an "Status: Okay" response. This failed. '.(isset($responseJson['Reason']) ? 'Reason: '.$responseJson['Reason'] : 'No Reason Given'));
$this->assertArrayHasKey('{{ object_name_singular }}', $responseJson); $this->assertArrayHasKey('{{ object_name_singular }}', $responseJson);
$this->waypoint('Some assertions'); $this->waypoint('Some assertions');
@ -182,8 +186,11 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
*/ */
public function test{{ class_name }}List() public function test{{ class_name }}List()
{ {
$method = "GET";
$uri = "/api/crud/{{ controller_route}}";
$this->waypoint('Begin'); $this->waypoint('Begin');
$response = $this->request('GET', '/v1/{{ controller_route}}'); $response = $this->request($method, $uri);
$this->waypoint('API REST REQUEST'); $this->waypoint('API REST REQUEST');
$body = (string) $response->getBody(); $body = (string) $response->getBody();
$this->assertTrue( $this->assertTrue(
@ -196,6 +203,7 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
true true
), ),
"Response was not expected 200 or 400.\n". "Response was not expected 200 or 400.\n".
"Request: {$method} => {$uri}\n".
"Response body is: \n". "Response body is: \n".
" ******************************\n{$body}\n ******************************\n" " ******************************\n{$body}\n ******************************\n"
); );
@ -206,7 +214,7 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
$responseJson = json_decode((string) $body, true); $responseJson = json_decode((string) $body, true);
$this->waypoint('JSON DECODE'); $this->waypoint('JSON DECODE');
$this->assertArrayHasKey('Status', $responseJson); $this->assertArrayHasKey('Status', $responseJson);
$this->assertEquals('Okay', $responseJson['Status'], 'Verify that request to GET /v1/{{ controller_route }} returns an "Status: Okay" response. This failed. '.(isset($responseJson['Reason']) ? 'Reason: '.$responseJson['Reason'] : 'No Reason Given')); $this->assertEquals('Okay', $responseJson['Status'], 'Verify that request to GET /api/crud/{{ controller_route }} returns an "Status: Okay" response. This failed. '.(isset($responseJson['Reason']) ? 'Reason: '.$responseJson['Reason'] : 'No Reason Given'));
$this->assertArrayHasKey('{{ object_name_plural }}', $responseJson); $this->assertArrayHasKey('{{ object_name_plural }}', $responseJson);
$this->waypoint('Some assertions'); $this->waypoint('Some assertions');
$this->validate{{ class_name }}Object(reset($responseJson['{{ object_name_plural }}'])); $this->validate{{ class_name }}Object(reset($responseJson['{{ object_name_plural }}']));
@ -222,7 +230,10 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
*/ */
public function test{{ class_name }}Delete($id) public function test{{ class_name }}Delete($id)
{ {
$response = $this->request('DELETE', '/v1/{{ controller_route}}/{$id}'); $method = "DELETE";
$uri = "/api/crud/{{ controller_route}}/{$id}";
$response = $this->request($method, $uri);
$body = (string) $response->getBody(); $body = (string) $response->getBody();
$this->assertTrue( $this->assertTrue(
in_array( in_array(
@ -234,12 +245,13 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
true true
), ),
"Response was not expected 200 or 400.\n". "Response was not expected 200 or 400.\n".
"Request: {$method} => {$uri}\n".
"Response body is: \n". "Response body is: \n".
" ******************************\n{$body}\n ******************************\n" " ******************************\n{$body}\n ******************************\n"
); );
$responseJson = json_decode((string) $body, true); $responseJson = json_decode((string) $body, true);
$this->assertArrayHasKey('Status', $responseJson); $this->assertArrayHasKey('Status', $responseJson);
$this->assertEquals('Okay', $responseJson['Status'], 'Verify that request to DELETE /v1/{{ controller_route }}/{$id} returns an "Status: Okay" response. This failed. '.(isset($responseJson['Reason']) ? 'Reason: '.$responseJson['Reason'] : 'No Reason Given')); $this->assertEquals('Okay', $responseJson['Status'], 'Verify that request to DELETE /api/crud/{{ controller_route }}/{$id} returns an "Status: Okay" response. This failed. '.(isset($responseJson['Reason']) ? 'Reason: '.$responseJson['Reason'] : 'No Reason Given'));
$this->assertEquals('DELETE', $responseJson['Action']); $this->assertEquals('DELETE', $responseJson['Action']);
$this->assertArrayHasKey('{{ object_name_singular }}', $responseJson); $this->assertArrayHasKey('{{ object_name_singular }}', $responseJson);
$this->validate{{ class_name }}Object($responseJson['{{ class_name }}']); $this->validate{{ class_name }}Object($responseJson['{{ class_name }}']);
@ -254,7 +266,7 @@ class {{ class_name }}EndpointTest extends RoutesTestCase
*/ */
public function test{{ class_name }}DeleteVerify($id) public function test{{ class_name }}DeleteVerify($id)
{ {
$response = $this->request('GET', "/v1/{{ controller_route}}/{$id}"); $response = $this->request('GET', "/api/crud/{{ controller_route}}/{$id}");
$body = (string) $response->getBody(); $body = (string) $response->getBody();
$this->assertNotNull( $this->assertNotNull(
json_decode((string) $body), json_decode((string) $body),

View file

@ -4,6 +4,9 @@ namespace {{ namespace }}\Controllers\Base;
use {{ namespace }}\Services; use {{ namespace }}\Services;
use Benzine\Controllers\AbstractCrudController; use Benzine\Controllers\AbstractCrudController;
use Slim\Psr7\Request;
use Slim\Psr7\Response;
use Benzine\Annotations\Route;
{% include '_overwrite_warning.twig' %} {% include '_overwrite_warning.twig' %}
@ -19,4 +22,38 @@ abstract class AbstractBase{{ class_name }}Controller extends AbstractCrudContro
{ {
return $this->service; return $this->service;
} }
/**
* @Route(methods={"GET"},path="/api/crud/{{ endpoint_name }}")
*/
public function listRequest(Request $request, Response $response): Response
{
return parent::listRequest($request,$response);
}
/**
* @Route(methods={"GET"},path="/api/crud/{{ endpoint_name }}/{id}")
*/
public function getRequest(Request $request, Response $response, $args): Response
{
return parent::getRequest($request, $response, $args);
}
/**
* @Route(methods={"PUT"},path="/api/crud/{{ endpoint_name }}")
* @Route(methods={"PUT"},path="/api/crud/{{ endpoint_name }}/{id}")
*/
public function createRequest(Request $request, Response $response, $args): Response
{
return parent::createRequest($request, $response, $args);
}
/**
* @Route(methods={"DELETE"},path="/api/crud/{{ endpoint_name }}/{id}")
*/
public function deleteRequest(Request $request, Response $response, $args): Response
{
return parent::deleteRequest($request, $response, $args);
}
} }

View file

@ -455,7 +455,7 @@ abstract class AbstractBase{{ class_name }}Model extends AbstractModel implement
{% if column.getDbType in ['datetime', 'timestamp'] %} {% if column.getDbType in ['datetime', 'timestamp'] %}
$this->{{ column.getFieldSanitised }} = $this->{{ column.getFieldSanitised }} =
${{ column.getDbField() }} !== null ${{ column.getDbField() }} !== null
? DateTime::createFromFormat("Y-m-d H:i:s", ${{ column.getDbField() }}) ? new DateTime(${{ column.getDbField() }})
: null ; : null ;
{% else %} {% else %}
$this->{{ column.getFieldSanitised }} = ${{ column.getDbField() }}; $this->{{ column.getFieldSanitised }} = ${{ column.getDbField() }};

View file

@ -47,7 +47,6 @@ class Laminator
private TwigFileSystemLoader $loader; private TwigFileSystemLoader $loader;
private TwigEnvironment $twig; private TwigEnvironment $twig;
private Databases $databases; private Databases $databases;
private array $ignoredTables = [];
private \SimpleXMLElement $coverageReport; private \SimpleXMLElement $coverageReport;
private bool $waitForKeypressEnabled = true; private bool $waitForKeypressEnabled = true;
@ -104,11 +103,6 @@ class Laminator
$fct = new \Twig\TwigFunction('var_export', 'var_export'); $fct = new \Twig\TwigFunction('var_export', 'var_export');
$this->twig->addFunction($fct); $this->twig->addFunction($fct);
// Skip tables specified in configuration.
if (isset($this->config['database'], $this->config['database']['skip_tables'])) {
$this->ignoredTables = $this->config['database']['skip_tables'];
}
$this->transSnake2Studly = new CaseTransformer(new Format\SnakeCase(), new Format\StudlyCaps()); $this->transSnake2Studly = new CaseTransformer(new Format\SnakeCase(), new Format\StudlyCaps());
$this->transStudly2Camel = new CaseTransformer(new Format\StudlyCaps(), new Format\CamelCase()); $this->transStudly2Camel = new CaseTransformer(new Format\StudlyCaps(), new Format\CamelCase());
$this->transStudly2Studly = new CaseTransformer(new Format\StudlyCaps(), new Format\StudlyCaps()); $this->transStudly2Studly = new CaseTransformer(new Format\StudlyCaps(), new Format\StudlyCaps());
@ -298,7 +292,7 @@ class Laminator
echo 'Collecting '.count($tables)." entities data.\n"; echo 'Collecting '.count($tables)." entities data.\n";
foreach ($tables as $table) { foreach ($tables as $table) {
if (in_array($table->getName(), $this->ignoredTables, true)) { if (in_array($table->getName(), $database->getIgnoredTables(), true)) {
continue; continue;
} }
$oModel = Components\Model::Factory($this) $oModel = Components\Model::Factory($this)
@ -321,6 +315,9 @@ class Laminator
/** @var Database $database */ /** @var Database $database */
$tables = $database->getMetadata()->getTables(); $tables = $database->getMetadata()->getTables();
foreach ($tables as $table) { foreach ($tables as $table) {
if (in_array($table->getName(), $database->getIgnoredTables(), true)) {
continue;
}
$key = $keys[$database->getAdapter()->getCurrentSchema().'::'.$table->getName()]; $key = $keys[$database->getAdapter()->getCurrentSchema().'::'.$table->getName()];
$models[$key] $models[$key]
->computeColumns($table->getColumns()) ->computeColumns($table->getColumns())