Skip to content

Dev 2.0 #222

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

Open
wants to merge 3 commits into
base: dev-2.0
Choose a base branch
from
Open
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
136 changes: 135 additions & 1 deletion lib/equal/orm/Entity.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
Licensed under GNU LGPL 3 license <http://www.gnu.org/licenses/>
*/
namespace equal\orm;

use Exception;
use ReflectionClass;
use ReflectionMethod;
use ReflectionException;
class Entity {
/**
* @var string
Expand Down Expand Up @@ -103,4 +106,135 @@ public function getFullFilePath(): string {
}
return $filepath;
}


public function updateMethod(string $methodName, array $newData) {
try {
$class = new ReflectionClass($this->full_name);

if (!$class->hasMethod($methodName)) {
throw new Exception("missing_method", QN_ERROR_UNKNOWN);
}

$method_code = " public static function $methodName() {\n" .
" return " . (empty($newData) ? '[]' : $this->arrayExport($newData, 4, 2, true)) . ";\n" .
" }";

$this->updateMethodCode($class, $methodName, $method_code);
} catch (ReflectionException $e) {
throw new Exception("reflection_error: " . $e->getMessage(), QN_ERROR_UNKNOWN);
}
}

public function updateMethodLine(string $methodName, string $newKey, $defaultValue = []) {
try {
$class = new ReflectionClass($this->full_name);

if (!$class->hasMethod($methodName)) {
throw new Exception("missing_method", QN_ERROR_UNKNOWN);
}

$oldData = call_user_func([$this->full_name, $methodName]);
if (!is_array($oldData)) {
$oldData = [];
}

if (!array_key_exists($newKey, $oldData)) {
$oldData[$newKey] = $defaultValue;
}

$method_code = " public static function $methodName() {\n" .
" return " . $this->arrayExport($oldData, 4, 2, true) . ";\n" .
" }";

$this->updateMethodCode($class, $methodName, $method_code);
} catch (ReflectionException $e) {
throw new Exception("reflection_error: " . $e->getMessage(), QN_ERROR_UNKNOWN);
}
}


private function updateMethodCode(ReflectionClass $class, string $methodName, string $newCode) {
try {
$file = $class->getFileName();
if (!$file || !file_exists($file)) {
throw new Exception("File not found: $file", QN_ERROR_UNKNOWN);
}

$code = file_get_contents($file);
if ($code === false) {
throw new Exception("Failed to read file: $file", QN_ERROR_UNKNOWN);
}

$lines = explode("\n", $code);

try {
$method = new ReflectionMethod($class->getName(), $methodName);
} catch (ReflectionException $e) {
throw new Exception("Method $methodName not found in class " . $class->getName(), QN_ERROR_UNKNOWN);
}

$start_index = $method->getStartLine() - 1;
$end_index = $method->getEndLine() - 1;

if ($start_index < 0 || $end_index < 0 || $end_index < $start_index) {
throw new Exception("Invalid method boundaries for $methodName", QN_ERROR_UNKNOWN);
}

$result = '';
foreach ($lines as $index => $line) {
if ($index < $start_index) {
$result .= $line . "\n";
} elseif ($index == $start_index) {
$result .= $newCode . "\n";
} elseif ($index > $end_index) {
$result .= $line . "\n";
}
}

if (file_put_contents($file, rtrim($result) . "\n") === false) {
throw new Exception("Failed to write to file: $file", QN_ERROR_UNKNOWN);
}
} catch (Exception $e) {
error_log("Error in updateMethodCode: " . $e->getMessage());
throw $e;
}
}




private function arrayExport($array, $indent_spaces = 4, $pad_indents = 0, $ignore_first_indent = false) {
if (!is_array($array)) {
return '';
}

$export = var_export($array, true);

$patterns = [
"/array \(/" => '[',
"/^([ ]*)\)(,?)$/m" => '$1]$2',
"/=>[ ]?\n[ ]+\[/" => '=> [',
"/([ ]*)(\'[^\']+\') => ([\[\'])/" => '$1$2 => $3',
"/[0-9]+ => /" => ''
];

$result = preg_replace(array_keys($patterns), array_values($patterns), $export);
if (empty($result)) {
return '';
}

$lines = explode("\n", $result);
foreach ($lines as $index => $line) {
if (!$ignore_first_indent || $index > 0) {
$code = ltrim($line);
$indents = (strlen($line) - strlen($code)) / 2;
$lines[$index] = str_pad('', $pad_indents * $indent_spaces, ' ') .
str_pad('', $indents * $indent_spaces, ' ') .
$code;
}
}

return implode("\n", $lines);
}
}
73 changes: 73 additions & 0 deletions packages/core/actions/config/create-actions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
/*
This file is part of the eQual framework <http://www.github.com/equalframework/equal>
Some Rights Reserved, eQual framework, 2010-2024
Original author(s): Cédric FRANCOYS
Licensed under GNU LGPL 3 license <http://www.gnu.org/licenses/>
*/

list($params, $providers) = eQual::announce([
'description' => "Add an empty actions to the given class by creating a `getActions()` method (if not defined yet).",
'params' => [
'entity' => [
'description' => 'Full name (including namespace) of the class to look into (e.g. \'core\\User\').',
'type' => 'string',
'required' => true
]
],
'response' => [
'content-type' => 'text',
'charset' => 'utf-8',
'accept-origin' => '*'
],
'access' => [
'visibility' => 'protected',
'groups' => ['admins']
],
'providers' => ['context', 'orm']
]);

/**
* @var \equal\php\Context $context
* @var \equal\orm\ObjectManager $orm
*/
list($context, $orm) = [ $providers['context'], $providers['orm'] ];

// force class autoload
$entity = $orm->getModel($params['entity']);
if(!$entity) {
throw new Exception("unknown_entity", QN_ERROR_INVALID_PARAM);
}

$class = new ReflectionClass($entity::getType());
if($class->getMethod('getActions')->class == $entity::getType()) {
throw new Exception("duplicate_method", QN_ERROR_INVALID_PARAM);
}

$file = $class->getFileName();
$code = file_get_contents($file);

// generate replacement code for the getActions method
$actions_code = ''.
" public static function getActions() {\n".
" return [];\n".
" }\n".
"\n";

// find the closing curly-bracket of the class
$pos = strrpos($code, '}');

if($pos === false) {
throw new Exception('malformed_file', QN_ERROR_UNKNOWN);
}

$result = substr_replace($code, $actions_code, $pos, 0);

// write back the code to the source file
if(file_put_contents($file, rtrim($result)."\n") === false) {
throw new Exception('io_error', QN_ERROR_UNKNOWN);
}

$context->httpResponse()
->status(204)
->send();
73 changes: 73 additions & 0 deletions packages/core/actions/config/create-policies.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
/*
This file is part of the eQual framework <http://www.github.com/equalframework/equal>
Some Rights Reserved, eQual framework, 2010-2024
Original author(s): Cédric FRANCOYS
Licensed under GNU LGPL 3 license <http://www.gnu.org/licenses/>
*/

list($params, $providers) = eQual::announce([
'description' => "Add an empty policies to the given class by creating a `getPolicies()` method (if not defined yet).",
'params' => [
'entity' => [
'description' => 'Full name (including namespace) of the class to look into (e.g. \'core\\User\').',
'type' => 'string',
'required' => true
]
],
'response' => [
'content-type' => 'text',
'charset' => 'utf-8',
'accept-origin' => '*'
],
'access' => [
'visibility' => 'protected',
'groups' => ['admins']
],
'providers' => ['context', 'orm']
]);

/**
* @var \equal\php\Context $context
* @var \equal\orm\ObjectManager $orm
*/
list($context, $orm) = [ $providers['context'], $providers['orm'] ];

// force class autoload
$entity = $orm->getModel($params['entity']);
if(!$entity) {
throw new Exception("unknown_entity", QN_ERROR_INVALID_PARAM);
}

$class = new ReflectionClass($entity::getType());
if($class->getMethod('getPolicies')->class == $entity::getType()) {
throw new Exception("duplicate_method", QN_ERROR_INVALID_PARAM);
}

$file = $class->getFileName();
$code = file_get_contents($file);

// generate replacement code for the getPolicies method
$policies_code = ''.
" public static function getPolicies() {\n".
" return [];\n".
" }\n".
"\n";

// find the closing curly-bracket of the class
$pos = strrpos($code, '}');

if($pos === false) {
throw new Exception('malformed_file', QN_ERROR_UNKNOWN);
}

$result = substr_replace($code, $policies_code, $pos, 0);

// write back the code to the source file
if(file_put_contents($file, rtrim($result)."\n") === false) {
throw new Exception('io_error', QN_ERROR_UNKNOWN);
}

$context->httpResponse()
->status(204)
->send();
58 changes: 58 additions & 0 deletions packages/core/actions/config/create-policy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
use PhpParser\{Node, NodeTraverser, NodeVisitorAbstract, ParserFactory, NodeFinder};
use equal\orm\Entity;
list($params, $providers) = eQual::announce([
'description' => "create a new policy",
'help' => "This controller relies on the PHP binary. Ensure the PHP binary is present in the PATH.",
'params' => [
'entity' => [
'description' => 'Name of the entity (class).',
'type' => 'string',
'required' => true
],
'name' => [
'description' => 'Name of the policy',
'type' => 'string',
'required' => true
]
],
'response' => [
'content-type' => 'text/plain',
'charset' => 'UTF-8',
'accept-origin' => '*'
],
'providers' => ['context', 'orm']
]);

/**
* @var \equal\php\Context $context
* @var \equal\orm\ObjectManager $orm
*/

list($context, $orm) = [$providers['context'], $providers['orm']];


$entity = new Entity($params['entity']);
$new_policy = $params['name'];
// force class autoload
$entityInstance = $orm->getModel($entity->getFullName());
if(!$entityInstance) {
throw new Exception("unknown_entity", QN_ERROR_INVALID_PARAM);
}

$method_name = 'getPolicies' ;
$structure= [
'description' =>'',
'function' => ''
];
$class = new ReflectionClass($entityInstance::getType());
if(!($class->getMethod($method_name)->class == $entityInstance::getType())) {
equal::run('do','core_config_create-policies',['entity' => $entity->getFullName()], true);
}

$entity->updateMethodLine($method_name,$new_policy, $structure);


$context->httpResponse()
->status(204)
->send();
Loading