diff --git a/src/Extracting/ParamHelpers.php b/src/Extracting/ParamHelpers.php
index 55467f28..9256291c 100644
--- a/src/Extracting/ParamHelpers.php
+++ b/src/Extracting/ParamHelpers.php
@@ -3,7 +3,11 @@
namespace Knuckles\Scribe\Extracting;
use Faker\Factory;
+use Faker\Provider\pt_BR\Address;
+use Faker\Provider\pt_BR\Payment;
+use Faker\Provider\pt_BR\PhoneNumber;
use Illuminate\Http\UploadedFile;
+use JansenFelipe\FakerBR\FakerBR;
use stdClass;
use Knuckles\Scribe\Tools\WritingUtils as w;
@@ -12,7 +16,11 @@ trait ParamHelpers
protected function getFaker()
{
- $faker = Factory::create();
+ $faker = Factory::create('pt_BR');
+ $faker->addProvider(new FakerBR($faker));
+ $faker->addProvider(new PhoneNumber($faker));
+ $faker->addProvider(new Address($faker));
+ $faker->addProvider(new Payment($faker));
if ($this->config->get('faker_seed')) {
$faker->seed($this->config->get('faker_seed'));
}
diff --git a/src/Extracting/Strategies/BodyParameters/GetFromFormRequest.php b/src/Extracting/Strategies/BodyParameters/GetFromFormRequest.php
index 778dab0e..cfe89f07 100644
--- a/src/Extracting/Strategies/BodyParameters/GetFromFormRequest.php
+++ b/src/Extracting/Strategies/BodyParameters/GetFromFormRequest.php
@@ -140,6 +140,7 @@ public function getBodyParametersFromValidationRules(array $validationRules, arr
// Let's have our sentences end with full stops, like civilized people.đŸ™‚
$parameterData['description'] = $fullDescription ? rtrim($fullDescription, '.') . '.' : $fullDescription;
+ $parameterData['description'] = str_replace(':attribute','',$parameterData['description']);
// Set default values for type
if (is_null($parameterData['type'])) {
$parameterData['type'] = 'string';
@@ -210,6 +211,13 @@ protected function normaliseRules(array $rules)
})->toArray();
}
+
+ public function changeDescription(&$parameterData, $concat)
+ {
+
+ $parameterData['description'] .= (!$parameterData['description'] ? '':'
').$concat;
+ }
+
protected function parseRule($rule, &$parameterData)
{
$parsedRule = $this->parseStringRuleIntoRuleAndArguments($rule);
@@ -257,13 +265,19 @@ protected function parseRule($rule, &$parameterData)
break;
case 'array':
$parameterData['setter'] = function () {
- return [$this->generateDummyValue('string')];
+ return [];
+ };
+ $parameterData['type'] = $rule;
+ break;
+ case 'uuid':
+ $parameterData['setter'] = function () {
+ return $this->generateDummyValue('uuid');
};
$parameterData['type'] = $rule;
break;
case 'file':
$parameterData['type'] = 'file';
- $parameterData['description'] .= 'O valor precisa ser um arquivo';
+ $this->changeDescription($parameterData,'O valor precisa ser um arquivo') ;
$parameterData['setter'] = function () {
return $this->generateDummyValue('file');
};
@@ -273,14 +287,13 @@ protected function parseRule($rule, &$parameterData)
* Special string types
*/
case 'timezone':
- // Laravel's message merely says "The value must be a valid zone"
- $parameterData['description'] .= "The value must be a valid time zone, such as Africa/Accra
. ";
+ $this->changeDescription($parameterData,"The value must be a valid time zone, such as Africa/Accra
. ");
$parameterData['setter'] = function () {
return $this->getFaker()->timezone;
};
break;
case 'email':
- $parameterData['description'] .= d::getDescription($rule) . ' ';
+ $this->changeDescription($parameterData,d::getDescription($rule) . ' ');
$parameterData['setter'] = function () {
return $this->getFaker()->safeEmail;
};
@@ -291,34 +304,39 @@ protected function parseRule($rule, &$parameterData)
return $this->getFaker()->url;
};
$parameterData['type'] = 'string';
- // Laravel's message is "The value format is invalid". Ugh.đŸ¤®
- $parameterData['description'] .= "O valor precisa ser uma URL vĂ¡lida";
+ $this->changeDescription($parameterData,$this->changeDescription($parameterData,"O valor precisa ser uma URL vĂ¡lida"));
break;
case 'ip':
- $parameterData['description'] .= d::getDescription($rule) . ' ';
+ $this->changeDescription($parameterData,d::getDescription($rule) . ' ');
$parameterData['type'] = 'string';
$parameterData['setter'] = function () {
return $this->getFaker()->ipv4;
};
break;
+ case 'cpf':
+ $this->changeDescription($parameterData,d::getDescription($rule) . ' ');
+ $parameterData['type'] = 'string';
+ $parameterData['setter'] = function () {
+ return $this->getFaker()->cpf;
+ };
+ break;
case 'json':
$parameterData['type'] = 'string';
- $parameterData['description'] .= d::getDescription($rule) . ' ';
+ $this->changeDescription($parameterData,d::getDescription($rule) . ' ');
$parameterData['setter'] = function () {
return json_encode([$this->getFaker()->word, $this->getFaker()->word,]);
};
break;
case 'date':
$parameterData['type'] = 'string';
- $parameterData['description'] .= d::getDescription($rule) . ' ';
+ $this->changeDescription($parameterData,d::getDescription($rule) . ' ');
$parameterData['setter'] = function () {
return date(\DateTime::ISO8601, time());
};
break;
case 'date_format':
$parameterData['type'] = 'string';
- // Laravel description here is "The value must match the format Y-m-d". Not descriptive enough.
- $parameterData['description'] .= "O valor precisa ser uma data vĂ¡lida no formato {$arguments[0]} ";
+ $this->changeDescription($parameterData,"O valor precisa ser uma data vĂ¡lida no formato {$arguments[0]} ");
$parameterData['setter'] = function () use ($arguments) {
return date($arguments[0], time());
};
@@ -345,12 +363,33 @@ protected function parseRule($rule, &$parameterData)
$parameterData['setter'] = function () { return $this->getFaker()->numberBetween($arguments[0], $arguments[1]); };
break;*/
+ case 'unique':
+ $this->changeDescription($parameterData,'SerĂ¡ validado se jĂ¡ existe um registro com esse valor cadastrado. ');
+ break;
+ case 'min_words':
+ $parameterData['type'] = $parameterData['type'] ?: 'number';
+ $parameterData['description'] .= "*O campo precisa conter no minimo {$arguments[0]} ".plural('palavra.','palavras.',$arguments[0]).' ';
+ break;
+ case 'digits':
+ $parameterData['type'] = $parameterData['type'] ?: 'number';
+ $this->changeDescription($parameterData,d::getDescription($rule, [':digits' => $arguments[0]]).' ');
+ break;
+
+ case 'between':
+ $parameterData['type'] = $parameterData['type'] ?: 'number';
+ $this->changeDescription($parameterData,d::getDescription($rule, [':min' => $arguments[0], ':max' => $arguments[1]], $parameterData['type'] == 'string' ? 'string':'numeric').' ');
+ $parameterData['setter'] = function () use ($arguments) { return $this->getFaker()->numberBetween($arguments[0], $arguments[1]); };
+ break;
+ case 'digits_between':
+ $parameterData['type'] = $parameterData['type'] ?: 'number';
+ $this->changeDescription($parameterData,d::getDescription($rule, [':min' => $arguments[0], ':max' => $arguments[1]]).' ');
+ break;
/**
* Special file types.
*/
case 'image':
$parameterData['type'] = 'file';
- $parameterData['description'] .= d::getDescription($rule) . ' ';
+ $this->changeDescription($parameterData,d::getDescription($rule) . ' ');
$parameterData['setter'] = function () {
// This is fine because the file example generator generates an image
return $this->generateDummyValue('file');
@@ -363,7 +402,7 @@ protected function parseRule($rule, &$parameterData)
case 'in':
// Not using the rule description here because it only says "The attribute is invalid"
$description = 'O valor precisa ser um dos seguintes:' . w::getListOfValuesAsFriendlyHtmlString($arguments);
- $parameterData['description'] .= $description . ' ';
+ $this->changeDescription($parameterData,$description . ' ');
$parameterData['setter'] = function () use ($arguments) {
return Arr::random($arguments);
};
diff --git a/src/Extracting/Strategies/Responses/ResponseCalls.php b/src/Extracting/Strategies/Responses/ResponseCalls.php
index db5d4665..eb495d4c 100644
--- a/src/Extracting/Strategies/Responses/ResponseCalls.php
+++ b/src/Extracting/Strategies/Responses/ResponseCalls.php
@@ -19,6 +19,8 @@
use Knuckles\Scribe\Tools\Utils;
use ReflectionClass;
use ReflectionFunctionAbstract;
+use Knuckles\Scribe\Tools\Utils as u;
+use ReflectionParameter;
/**
* Make a call to the route and retrieve its response.
@@ -121,10 +123,33 @@ private function configureEnvironment(array $rulesToApply)
* @param array $headers
*
* @return Request
+ * @throws \ReflectionException
*/
protected function prepareRequest(Route $route, array $rulesToApply, array $urlParams, array $bodyParams, array $queryParams, array $fileParameters, array $headers)
{
- $uri = Utils::getFullUrl($route, $urlParams);
+
+ [$controllerName, $methodName] = u::getRouteClassAndMethodNames($route);
+ $controller = new ReflectionClass($controllerName);
+ $method = u::getReflectedRouteMethod([$controllerName, $methodName]);
+
+ $parameters = $method->getParameters();
+
+ $replaceParameters = [];
+ foreach($parameters as $key=> $parameter){
+ /**@var ReflectionParameter $parameter * */
+ $class = $parameter->getClass();
+ if(!empty($class) and $class->isSubclassOf(\Illuminate\Database\Eloquent\Model::class)){
+ $className = $class->getName();
+ if(class_exists($className)) {
+ $class_instance = app($className);
+ if( $class_instance and !empty($model = $class_instance->first())){
+ $replaceParameters[$parameter->getName()] = $model->id;
+ }
+ }
+ }
+ }
+
+ $uri = Utils::getFullUrl($route, $urlParams,$replaceParameters);
$routeMethods = $this->getMethods($route);
$method = array_shift($routeMethods);
$cookies = isset($rulesToApply['cookies']) ? $rulesToApply['cookies'] : [];
@@ -323,7 +348,6 @@ protected function makeApiCall(Request $request, Route $route)
*/
protected function callLaravelOrLumenRoute(Request $request): \Symfony\Component\HttpFoundation\Response
{
- ini_set('xdebug.max_nesting_level', 1200);
// Confirm we're running in Laravel, not Lumen
if (app()->bound(Kernel::class)) {
$kernel = app(Kernel::class);
diff --git a/src/Extracting/Strategies/Responses/UseApiResourceTags.php b/src/Extracting/Strategies/Responses/UseApiResourceTags.php
index d7658507..6c305cef 100644
--- a/src/Extracting/Strategies/Responses/UseApiResourceTags.php
+++ b/src/Extracting/Strategies/Responses/UseApiResourceTags.php
@@ -62,6 +62,7 @@ public function __invoke(Route $route, ReflectionClass $controller, ReflectionFu
* @param Tag[] $tags
*
* @return array|null
+ * @throws Exception
*/
public function getApiResourceResponse(array $tags)
{
@@ -70,9 +71,10 @@ public function getApiResourceResponse(array $tags)
}
[$statusCode, $apiResourceClass] = $this->getStatusCodeAndApiResourceClass($apiResourceTag);
- [$model, $factoryStates, $relations, $pagination] = $this->getClassToBeTransformedAndAttributes($tags);
- $modelInstance = $this->instantiateApiResourceModel($model, $factoryStates, $relations);
+ [$model, $factoryStates, $relations, $pagination, $useFactory] = $this->getClassToBeTransformedAndAttributes($tags);
+ $this->startDbTransaction();
+ $modelInstance = $this->instantiateApiResourceModel($model, $factoryStates, $relations,$useFactory);
try {
$resource = new $apiResourceClass($modelInstance);
} catch (Exception $e) {
@@ -84,7 +86,7 @@ public function getApiResourceResponse(array $tags)
// Collections can either use the regular JsonResource class (via `::collection()`,
// or a ResourceCollection (via `new`)
// See https://laravel.com/docs/5.8/eloquent-resources
- $models = [$modelInstance, $this->instantiateApiResourceModel($model, $factoryStates, $relations)];
+ $models = [$modelInstance, $this->instantiateApiResourceModel($model, $factoryStates, $relations,$useFactory)];
// Pagination can be in two forms:
// [15] : means ::paginate(15)
// [15, 'simple'] : means ::simplePaginate(15)
@@ -113,6 +115,7 @@ public function getApiResourceResponse(array $tags)
/** @var Response $response */
$response = $resource->toResponse(app(Request::class));
+ $this->endDbTransaction();
return [
[
'status' => $statusCode ?: 200,
@@ -143,13 +146,18 @@ private function getClassToBeTransformedAndAttributes(array $tags): array
}));
$type = null;
+ $useFactory = false;
$states = [];
$relations = [];
$pagination = [];
if ($modelTag) {
- ['content' => $type, 'attributes' => $attributes] = a::parseIntoContentAndAttributes($modelTag->getContent(), ['states', 'with', 'paginate']);
+ ['content' => $type, 'attributes' => $attributes] = a::parseIntoContentAndAttributes($modelTag->getContent(), ['states', 'with', 'paginate','relations','useFactory']);
$states = $attributes['states'] ? explode(',', $attributes['states']) : [];
+ $useFactory = !!$attributes['useFactory'];
$relations = $attributes['with'] ? explode(',', $attributes['with']) : [];
+ if(empty($relations)){
+ $relations = $attributes['relations'] ? explode(',', $attributes['relations']) : [];
+ }
$pagination = $attributes['paginate'] ? explode(',', $attributes['paginate']) : [];
}
@@ -157,23 +165,26 @@ private function getClassToBeTransformedAndAttributes(array $tags): array
throw new Exception("Couldn't detect an Eloquent API resource model from your docblock. Did you remember to specify a model using @apiResourceModel?");
}
- return [$type, $states, $relations, $pagination];
+ return [$type, $states, $relations, $pagination, $useFactory];
}
/**
* @param string $type
*
- * @param array $relations
* @param array $factoryStates
*
+ * @param array $relations
+ * @param bool $useFactory
* @return Model|object
*/
- protected function instantiateApiResourceModel(string $type, array $factoryStates = [], array $relations = [])
+ protected function instantiateApiResourceModel(string $type, array $factoryStates = [], array $relations = [], $useFactory=false)
{
- $this->startDbTransaction();
+// $this->startDbTransaction();
try {
// Try Eloquent model factory
-
+ if(!$useFactory){
+ throw new Exception('');
+ }
// Factories are usually defined without the leading \ in the class name,
// but the user might write it that way in a comment. Let's be safe.
$type = ltrim($type, '\\');
@@ -183,22 +194,27 @@ protected function instantiateApiResourceModel(string $type, array $factoryState
$factory->states($factoryStates);
}
try {
- return $factory->create();
+ $result = $factory->create();
+ if(!empty($relations)){
+ $result->load($relations);
+ }
+ return $result;
} catch (Exception $e) {
// If there was no working database, it would fail.
return $factory->make();
}
} catch (Exception $e) {
- c::debug("Eloquent model factory failed to instantiate {$type}; trying to fetch from database.");
- e::dumpExceptionIfVerbose($e);
+// c::debug("Eloquent model factory failed to instantiate {$type}; trying to fetch from database.");
+// e::dumpExceptionIfVerbose($e);
$instance = new $type();
if ($instance instanceof \Illuminate\Database\Eloquent\Model) {
try {
// we can't use a factory but can try to get one from the database
- $firstInstance = $type::with($relations)->first();
- if ($firstInstance) {
- return $firstInstance;
+ $lastInstance = $type::latest()->first();
+// $lastInstance = $type::with($relations)->latest()->first();
+ if ($lastInstance) {
+ return $lastInstance;
}
} catch (Exception $e) {
// okay, we'll stick with `new`
@@ -207,7 +223,7 @@ protected function instantiateApiResourceModel(string $type, array $factoryState
}
}
} finally {
- $this->endDbTransaction();
+// $this->endDbTransaction();
}
return $instance;