Code Coverage |
||||||||||
Classes and Traits |
Functions and Methods |
Lines |
||||||||
| Total | |
0.00% |
0 / 1 |
|
0.00% |
0 / 18 |
CRAP | |
0.00% |
0 / 219 |
| PerfilExample | |
0.00% |
0 / 1 |
|
0.00% |
0 / 18 |
7310.00 | |
0.00% |
0 / 219 |
| __construct | |
0.00% |
0 / 1 |
2.00 | |
0.00% |
0 / 7 |
|||
| getFileSystemControllerPath | |
0.00% |
0 / 1 |
2.00 | |
0.00% |
0 / 1 |
|||
| getFileSystemCodePath | |
0.00% |
0 / 1 |
2.00 | |
0.00% |
0 / 1 |
|||
| getControllerURL | |
0.00% |
0 / 1 |
2.00 | |
0.00% |
0 / 1 |
|||
| getCodeURL | |
0.00% |
0 / 1 |
2.00 | |
0.00% |
0 / 1 |
|||
| makeExampleSubDir | |
0.00% |
0 / 1 |
56.00 | |
0.00% |
0 / 7 |
|||
| directoryPath | |
0.00% |
0 / 1 |
2.00 | |
0.00% |
0 / 3 |
|||
| getFileName | |
0.00% |
0 / 1 |
6.00 | |
0.00% |
0 / 3 |
|||
| endingSlash | |
0.00% |
0 / 1 |
6.00 | |
0.00% |
0 / 3 |
|||
| PerfilExample_class | |
0.00% |
0 / 1 |
992.00 | |
0.00% |
0 / 91 |
|||
| callStrings | |
0.00% |
0 / 1 |
30.00 | |
0.00% |
0 / 32 |
|||
| parametersCall | |
0.00% |
0 / 1 |
20.00 | |
0.00% |
0 / 8 |
|||
| parameterValue | |
0.00% |
0 / 1 |
90.00 | |
0.00% |
0 / 17 |
|||
| getControllerCode | |
0.00% |
0 / 1 |
6.00 | |
0.00% |
0 / 5 |
|||
| saveFileIfNotExists | |
0.00% |
0 / 1 |
6.00 | |
0.00% |
0 / 3 |
|||
| testTemplate | |
0.00% |
0 / 1 |
156.00 | |
0.00% |
0 / 26 |
|||
| testMethodTemplate | |
0.00% |
0 / 1 |
6.00 | |
0.00% |
0 / 8 |
|||
| testClassHeader | |
0.00% |
0 / 1 |
2.00 | |
0.00% |
0 / 2 |
|||
| <?php | |
| namespace ia\DocumentIt; | |
| //@EXPAND pre-fill module, functions in file, may be file with no functions nor vars nor defines ie has a class, trait, interface | |
| //@EXPAND a completa xxx_example_code.php nota ver <li id="method_name"> de no estar append it | |
| //@MEJORA cuando un parĂ¡metro tiene un default usar el default o no ponerlo en la llamada | |
| use ReflectionClass; | |
| use ReflectionException; | |
| use ReflectionFunction; | |
| use ReflectionMethod; | |
| class PerfilExample { | |
| private $className; | |
| private $classVariable; | |
| private $examplesDir; | |
| private $examplesHome; | |
| private $exampleControllerFileName; | |
| private $exampleCodeFileName; | |
| private $shortName; | |
| /** | |
| * PerfilExample constructor. | |
| * @param string $className | |
| * @param string $exampleDir | |
| * @param string $exampleHome | |
| */ | |
| public function __construct($className, $exampleDir, $exampleHome) { | |
| $this->className = $className; | |
| $this->examplesDir = $this->endingSlash($exampleDir); | |
| $this->examplesHome = $this->endingSlash($exampleHome); | |
| $this->exampleControllerFileName = $this->getFileName('', $className, '_example.php'); | |
| $this->exampleCodeFileName = $this->getFileName('code/', $className, '_example_code.php'); | |
| $this->makeExampleSubDir(); | |
| } | |
| public function getFileSystemControllerPath() { | |
| return $this->examplesDir . $this->exampleControllerFileName; | |
| } | |
| public function getFileSystemCodePath() { | |
| return $this->examplesDir . $this->exampleCodeFileName; | |
| } | |
| private function getControllerURL() { | |
| return $this->examplesHome . $this->exampleControllerFileName; | |
| } | |
| private function getCodeURL() { | |
| return $this->examplesHome . $this->exampleCodeFileName; | |
| } | |
| private function makeExampleSubDir() { | |
| $controllerSubDir = $this->directoryPath($this->getFileSystemControllerPath()); | |
| if($controllerSubDir !== '' && $controllerSubDir !== '/' && !file_exists($controllerSubDir)) { | |
| mkdir($controllerSubDir, 0755, true); | |
| } | |
| $codeSubDir = $this->directoryPath($this->getFileSystemCodePath()); | |
| if($codeSubDir !== '' && $codeSubDir !== '/' && !file_exists($codeSubDir)) { | |
| mkdir($codeSubDir, 0755, true); | |
| } | |
| } | |
| public function directoryPath($fileName) { | |
| $path = explode('/', $fileName); | |
| array_pop($path); | |
| return implode('/', $path); | |
| } | |
| private function getFileName($prefix, $className, $suffix) { | |
| if(substr($className,0,1) === '/') { | |
| $className = substr($className, 1); | |
| } | |
| return $prefix . str_replace('\\', '/', $className).$suffix; | |
| } | |
| /** | |
| * Ensure path ends with / | |
| * @param string $path | |
| * @return string | |
| */ | |
| private function endingSlash($path) { | |
| if(substr($path, -1) !== '/') { | |
| $path .= '/'; | |
| } | |
| return $path; | |
| } | |
| /** | |
| * @return string | |
| */ | |
| public function PerfilExample_class() { | |
| if(empty($this->className) || $this->className[0] === '/' || $this->className[0] === '\\') { | |
| return "Invalid namespace\\className"; | |
| } | |
| if(stripos($this->className, '/') || stripos($this->className, '.\\')) { | |
| return "Invalid namespace\\className / ./ and .\\ not allowed"; | |
| } | |
| try { | |
| $ref = new ReflectionClass($this->className); | |
| } catch (ReflectionException $e) { | |
| return "\Reflection error, invalid \$className = $this->className"; | |
| } | |
| $this->shortName = $ref->getShortName(); | |
| $this->classVariable = lcFirst($ref->getShortName()); | |
| $namespace = $ref->getNamespaceName(); | |
| if(empty($namespace)) { | |
| $namespace = ''; | |
| } | |
| $controllerCode = $this->getControllerCode(); | |
| $this->saveFileIfNotExists($this->getFileSystemControllerPath(), $controllerCode); | |
| $construct = [ | |
| 'parametersList' => '', | |
| 'callPrototype' => '', | |
| 'callCommentOut' =>'', | |
| 'call' => '', | |
| 'callEcho' => '', | |
| 'returnType' => '', | |
| 'parametersPrototype' => '', | |
| 'parametersValues' => [], | |
| 'createNew' => true, | |
| 'docBlock' => '', | |
| ]; | |
| $ret = "\r\n"; | |
| $instantiateClass = false; | |
| foreach ($ref->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { | |
| $functionDocBlock = $method->getDocComment(); | |
| $callers = $this->callStrings($method, $functionDocBlock); | |
| if($method->getName() === '__construct') { | |
| $construct = $callers; | |
| $construct['docBlock'] = $functionDocBlock; | |
| $instantiateClass = true; | |
| continue; | |
| } | |
| if(!$method->isStatic()) { | |
| $instantiateClass = true; | |
| } | |
| switch($callers['returnType']) { | |
| case 'int': | |
| case 'string': | |
| case 'float': | |
| case 'float|string': | |
| case 'string|float': | |
| case 'int|string': | |
| case 'string|int': | |
| case 'int|float': | |
| case 'float|int': | |
| case 'string|bool': | |
| case 'bool|string': | |
| $example = <<< METHODEXAMPLE | |
| /// display /// | |
| echo <<< DOCUMENT_EXAMPLE | |
| <li>$callers[callEcho] -> | |
| DOCUMENT_EXAMPLE; | |
| /// run /// | |
| $callers[callCommentOut] echo $callers[call]; | |
| METHODEXAMPLE; | |
| break; | |
| case 'bool': | |
| $example = <<< METHODEXAMPLE | |
| /// display /// | |
| echo <<< DOCUMENT_EXAMPLE | |
| <li>$callers[callEcho] -> | |
| DOCUMENT_EXAMPLE; | |
| ///run /// | |
| $callers[callCommentOut] echo ($callers[call] ? 'true' : 'false'); | |
| METHODEXAMPLE; | |
| break; | |
| case 'void': | |
| $example = <<< METHODEXAMPLE | |
| /// display /// | |
| echo <<< DOCUMENT_EXAMPLE | |
| <li>$callers[callEcho]" | |
| DOCUMENT_EXAMPLE; | |
| /// run /// | |
| $callers[callCommentOut] echo $callers[call]; | |
| METHODEXAMPLE; | |
| break; | |
| case 'Generator': | |
| case '\Generator': | |
| $example = <<< METHODEXAMPLE | |
| /// display /// | |
| echo <<< DOCUMENT_EXAMPLE | |
| <li>echo "<ul>"; | |
| foreach($callers[callEcho] as \\\$k => \\\$v) | |
| echo "<li>\\\$k := ". print_r(\\\$v, true)."</li>"; | |
| echo "/<ul>"; | |
| DOCUMENT_EXAMPLE; | |
| /// run /// | |
| echo "<ul>"; foreach($callers[call] as \$k => \$v) echo "<li>\$k := ". print_r(\$v, true)."</li>"; echo "</ul>"; | |
| METHODEXAMPLE; | |
| break; | |
| default: | |
| if(empty($callCommentOut)) { | |
| $example = <<< METHODEXAMPLE | |
| /// display /// | |
| echo <<< DOCUMENT_EXAMPLE | |
| <li>$callers[callEcho] | |
| -> </b><br><pre> | |
| DOCUMENT_EXAMPLE; | |
| /// run /// | |
| print_r( | |
| $callers[call] | |
| ); | |
| echo "</pre>"; | |
| METHODEXAMPLE; | |
| } else { | |
| $example = <<< METHODEXAMPLE | |
| /// display /// | |
| echo <<< DOCUMENT_EXAMPLE | |
| <li>$callers[callEcho]" | |
| -> </b><br><pre> | |
| DOCUMENT_EXAMPLE; | |
| /// run /// | |
| // print_r($callers[call]); | |
| echo "</pre>"; | |
| METHODEXAMPLE; | |
| } | |
| } | |
| $prototype = <<< PROTOTYPEXAMPLE | |
| ///////// $callers[callEcho] ////////////////////////////////////////////////// | |
| echo <<< FUNCTIONDEF | |
| <li id='u_$method->name'><b>$callers[callPrototype]</b> | |
| FUNCTIONDEF; | |
| echo "<pre class='docBlock'>".DocumentIt::methodDocBlockProtected("$this->className", "$method->name")."</pre>"; | |
| echo "<ol class='usage'>"; | |
| PROTOTYPEXAMPLE; | |
| $ret .= "\r\n$prototype\r\n$example\r\n\techo '</ol>';\r\n"; | |
| } | |
| $ret .= "\r\n\r\n/* PerfilExample adds new methods here */\r\n\r\necho '</ul>';"; | |
| $date = date('Y-m'); | |
| $header = " | |
| /** | |
| * Usage examples for $this->className | |
| * @version 1.0 | |
| * @date $date | |
| */\r\n\r\nuse ia\\DocumentIt\\DocumentIt;\r\n"; | |
| $shortName = $ref->getShortName(); | |
| if(!empty($namespace)) { | |
| $header = "use $namespace\\$shortName;\r\n"; | |
| } | |
| $header .= "use ia\DocumentIt\DocumentIt;\r\n"; | |
| $header .= "\r\necho '<h3>Disclaimer: Auto generated file. | |
| Please help us setting parameters to useful values and extending the examples. | |
| </h3>';\r\n\r\ntry {\r\n\r\n"; | |
| if($instantiateClass) { | |
| if (!empty($construct['createNew'])) { | |
| $docBlock = str_replace('$', "\\$", $construct['docBlock']); | |
| $proto = "\\$" . $this->classVariable . " = new $shortName($construct[parametersPrototype]);"; | |
| $parametersValues = empty($construct['parametersValues']) ? '' : implode(', ', $construct['parametersValues']); | |
| $showCreate = "\\$" . $this->classVariable . " = new $shortName($parametersValues);"; | |
| $header .= <<< PROTOTYPE | |
| echo <<< CONSTRUCTOR_PROTOTYPE | |
| <pre> | |
| $docBlock | |
| /* | |
| $proto | |
| */ | |
| $showCreate | |
| </pre> | |
| CONSTRUCTOR_PROTOTYPE; | |
| PROTOTYPE; | |
| $header .= "\r\n" . '$' . $this->classVariable . " = new $shortName($parametersValues);\r\n\r\n"; | |
| } | |
| } | |
| $header .= "\r\necho '<ul class=\"usage\">';\r\n"; | |
| $code = $header . $ret . "\r\n\r\n" . | |
| '} catch(Exception $exception) { echo "<pre class=\'errorBlock\'>$exception</pre>"; }'."\r\n"; | |
| $this->saveFileIfNotExists($this->getFileSystemCodePath(), $code); | |
| return | |
| "<hr><h2 id='controler' class='fileName'>" . $this->getControllerURL() . | |
| "</h2><hr><code style='margin:2em'>" . htmlentities("<?php\r\n".$controllerCode)."</code>" . | |
| "<hr><h2 id='byFunction' class='fileName'>" . $this->getCodeURL() . "</h2><hr><code style='margin:2em'>". | |
| htmlentities($code)."</code>"; | |
| } | |
| /** | |
| * @param ReflectionMethod|ReflectionFunction $method | |
| * @param string $functionDocBlock | |
| * @return array | |
| */ | |
| private function callStrings($method, $functionDocBlock) { | |
| $variables = []; | |
| foreach($method->getParameters() as $p) { | |
| $variables[] = '$'.$p->getName() ; | |
| } | |
| $parametersList = implode(', ', $variables); | |
| $parameters = DocumentIt::parameters($method, $functionDocBlock); | |
| $parametersPrototype = str_replace(['$'], ["\\$"], implode(', ', $parameters) ); | |
| $parametersValues = $this->parametersCall($method, $functionDocBlock); | |
| $returnType = $method->hasReturnType() ? $method->getReturnType() : | |
| DocumentIt::deduceReturnTypeFromDockBlock($functionDocBlock); | |
| if($method->isStatic()) { | |
| $callWithVariables = $call = $callPrototype = $callEcho = "$this->shortName::".$method->name; | |
| $createNew = false; | |
| } else { | |
| $callWithVariables = $call = '$'.$this->classVariable . '->' . $method->name; | |
| $callPrototype = $callEcho = str_replace('$', "\\$", $call); | |
| $createNew = true; | |
| } | |
| $callPrototype .= "($parametersPrototype) <span>: $returnType</span>"; | |
| $call .= "(" . implode(', ', $parametersValues).')'; | |
| $callWithVariables .="($parametersList)"; | |
| $callEcho .= str_replace(['$'], ["\\$"], "(" . implode(', ', $parametersValues).');'); | |
| return [ | |
| 'parameterCount' => count($variables), | |
| 'callWithVariables' => $callWithVariables, | |
| 'parametersList' => $parametersList, | |
| 'callPrototype' => $callPrototype, | |
| 'callCommentOut' => strpos($callPrototype, '&') === false ? '' : '// ', | |
| 'call' => $call, | |
| 'callEcho' => $callEcho, | |
| 'returnType' => $returnType, | |
| 'parametersPrototype' => $parametersPrototype, | |
| 'parametersValues' => $parametersValues, | |
| 'createNew' => $createNew, | |
| 'docBlock' => $functionDocBlock, | |
| 'parameters' => $parameters, | |
| ]; | |
| } | |
| private function parametersCall($method, $functionDocBlock) { | |
| $parametersCall = []; | |
| try { | |
| foreach (DocumentIt::parametersInfo($method, $functionDocBlock) as $p) { | |
| if ($p['isOptional']) { | |
| continue; | |
| } | |
| $parametersCall[] = $this->parameterValue($p['type']); | |
| } | |
| } catch (ReflectionException $e) { | |
| $parametersCall[] = '<span class="error">Parameter ReflectionException</span>'; | |
| } | |
| return $parametersCall; | |
| } | |
| private function parameterValue($p) { | |
| if(stripos($p, 'array') !== false) { | |
| return "['a' => '1', 'b' => '2', 'c' => 3]"; | |
| } | |
| if(stripos($p, 'int') !== false) { | |
| return 3; | |
| } | |
| if(stripos($p, 'float') !== false) { | |
| return 2.7172; | |
| } | |
| if(stripos($p, 'string') !== false) { | |
| return "'palabra'"; | |
| } | |
| if(stripos($p, 'bool') !== false) { | |
| return "true"; | |
| } | |
| if(stripos($p, 'DateTimeImmutable') !== false) { | |
| return "new DateTimeImmutable()"; | |
| } | |
| if(stripos($p, 'DateTime') !== false) { | |
| return "new DateTime()"; | |
| } | |
| if(stripos($p, 'IaMysqli') !== false) { | |
| return "\$gSqlClass"; | |
| } | |
| return "null /* =$p= */"; | |
| } | |
| private function getControllerCode() { | |
| $slashes_number = count(explode('\\',$this->className)); | |
| $includePath = $slashes_number < 2 ? '' : str_repeat('../', $slashes_number - 1 ); | |
| return " | |
| \$ia_example = [ | |
| 'title' => '$this->className', // fully qualified className | |
| 'summary' => '', // class summary | |
| 'full_example' => '', // full usage example, relative path from ia_examples, blank '' not shown. | |
| 'example_file' => '$this->exampleCodeFileName', // method by method example, blank '' not shown. | |
| ]; | |
| include( __DIR__ . '/{$includePath}template/ia_example_class.php'); | |
| "; | |
| } | |
| private function saveFileIfNotExists($filePath, $code) { | |
| if(!file_exists($filePath)) { | |
| file_put_contents($filePath, "<?php\r\n$code"); | |
| } | |
| } | |
| /** test file example */ | |
| public function testTemplate() { | |
| if(empty($this->className) || $this->className[0] === '/' || $this->className[0] === '\\') { | |
| return "Invalid namespace\\className"; | |
| } | |
| if(stripos($this->className, '/') || stripos($this->className, '.\\')) { | |
| return "Invalid namespace\\className / ./ and .\\ not allowed"; | |
| } | |
| try { | |
| $ref = new ReflectionClass($this->className); | |
| } catch (ReflectionException $e) { | |
| return "\Reflection error, invalid \$className = $this->className"; | |
| } | |
| $this->shortName = $ref->getShortName(); | |
| $this->classVariable = lcFirst($ref->getShortName()); | |
| $construct = [ | |
| 'callWithVariables' => '', | |
| 'callPrototype' => '', | |
| 'callCommentOut' =>'', | |
| 'call' => '', | |
| 'callEcho' => '', | |
| 'returnType' => '', | |
| 'parametersPrototype' => '', | |
| 'parametersValues' => [], | |
| 'parameters' => [], | |
| 'parametersList' => '', | |
| 'createNew' => true, | |
| 'docBlock' => '', | |
| ]; | |
| foreach ($ref->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { | |
| $functionDocBlock = $method->getDocComment(); | |
| $callers = $this->callStrings($method, $functionDocBlock); | |
| if($method->getName() === '__construct') { | |
| /** @var array $construct */ | |
| $construct = $callers; | |
| $construct['docBlock'] = $functionDocBlock; | |
| continue; | |
| } | |
| } | |
| $ret = "\r\n"; | |
| foreach ($ref->getMethods(ReflectionMethod::IS_PUBLIC) as $method) { | |
| if($method->getName() === '__construct') { | |
| continue; | |
| } | |
| $functionDocBlock = $method->getDocComment(); | |
| $callers = $this->callStrings($method, $functionDocBlock); | |
| $instantiateClassStatement = $method->isStatic() ? '' : "\$$this->classVariable = new $this->shortName($construct[parametersList]);" ; | |
| $ret .= $this->testMethodTemplate( $method->getName(), $callers, $instantiateClassStatement); | |
| } | |
| /* | |
| if(empty($ref->getNamespaceName())) { | |
| $classFqn = $this->className; | |
| } else { | |
| $classFqn = $ref->getNamespaceName() . '\\' . $this->className; | |
| } | |
| */ | |
| return "<?php\r\n".$this->testClassHeader($this->className, $ref->getShortName()).$ret."\r\n}\r\n"; | |
| } | |
| private function testMethodTemplate( $methodName, $callers, $instanciateClassStatement) { | |
| $testValue = implode(', ', array_fill(0, $callers['parameterCount']+1, "''") ); | |
| $coma = empty($callers['parametersList']) ? '' : ','; | |
| return <<< TESTMETHODTAG | |
| /** | |
| * @dataProvider {$methodName}_Provider | |
| * | |
| */ | |
| public function test_{$methodName}($callers[parametersList] $coma \$expected) { | |
| $instanciateClassStatement | |
| \$this->assertEquals(\$expected, $callers[callWithVariables] ); | |
| } | |
| function {$methodName}_Provider() { | |
| return [ | |
| 'test 1' => [ $testValue ], | |
| ]; | |
| } | |
| TESTMETHODTAG; | |
| } | |
| private function testClassHeader($classFqn, $className) { | |
| return <<< TESTCLASSSTART | |
| use $classFqn; | |
| use PHPUnit\Framework\TestCase; | |
| class {$className}Test extends TestCase { | |
| TESTCLASSSTART; | |
| } | |
| } |