123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- <?php
- namespace Mpociot\ApiDoc\Generators;
- use ReflectionClass;
- use League\Fractal\Manager;
- use Illuminate\Routing\Route;
- use League\Fractal\Resource\Item;
- use Illuminate\Support\Facades\App;
- use Mpociot\Reflection\DocBlock\Tag;
- use Illuminate\Support\Facades\Request;
- use League\Fractal\Resource\Collection;
- use Illuminate\Foundation\Http\FormRequest;
- class LaravelGenerator extends AbstractGenerator
- {
- /**
- * @param Route $route
- *
- * @return mixed
- */
- public function getDomain($route)
- {
- return $route->domain();
- }
- /**
- * @param Route $route
- *
- * @return mixed
- */
- public function getUri($route)
- {
- if (version_compare(app()->version(), '5.4', '<')) {
- return $route->getUri();
- }
- return $route->uri();
- }
- /**
- * @param Route $route
- *
- * @return mixed
- */
- public function getMethods($route)
- {
- if (version_compare(app()->version(), '5.4', '<')) {
- $methods = $route->getMethods();
- } else {
- $methods = $route->methods();
- }
- return array_diff($methods, ['HEAD']);
- }
- /**
- * @param \Illuminate\Routing\Route $route
- * @param array $bindings
- * @param array $headers
- * @param bool $withResponse
- *
- * @return array
- */
- public function processRoute($route, $bindings = [], $headers = [], $withResponse = true)
- {
- $content = '';
- $routeDomain = $route->domain();
- $routeAction = $route->getAction();
- $routeGroup = $this->getRouteGroup($routeAction['uses']);
- $routeDescription = $this->getRouteDescription($routeAction['uses']);
- $showresponse = null;
- // set correct route domain
- $headers[] = "HTTP_HOST: {$routeDomain}";
- $headers[] = "SERVER_NAME: {$routeDomain}";
- if ($withResponse) {
- $response = null;
- $docblockResponse = $this->getDocblockResponse($routeDescription['tags']);
- if ($docblockResponse) {
- // we have a response from the docblock ( @response )
- $response = $docblockResponse;
- $showresponse = true;
- }
- if (! $response) {
- $transformerResponse = $this->getTransformerResponse($routeDescription['tags']);
- if ($transformerResponse) {
- // we have a transformer response from the docblock ( @transformer || @transformercollection )
- $response = $transformerResponse;
- $showresponse = true;
- }
- }
- if (! $response) {
- $response = $this->getRouteResponse($route, $bindings, $headers);
- }
- if ($response->headers->get('Content-Type') === 'application/json') {
- $content = json_decode($response->getContent(), JSON_PRETTY_PRINT);
- } else {
- $content = $response->getContent();
- }
- }
- return $this->getParameters([
- 'id' => md5($this->getUri($route).':'.implode($this->getMethods($route))),
- 'resource' => $routeGroup,
- 'title' => $routeDescription['short'],
- 'description' => $routeDescription['long'],
- 'methods' => $this->getMethods($route),
- 'uri' => $this->getUri($route),
- 'parameters' => [],
- 'response' => $content,
- 'showresponse' => $showresponse,
- ], $routeAction, $bindings);
- }
- /**
- * Prepares / Disables route middlewares.
- *
- * @param bool $disable
- *
- * @return void
- */
- public function prepareMiddleware($enable = true)
- {
- App::instance('middleware.disable', ! $enable);
- }
- /**
- * Call the given URI and return the Response.
- *
- * @param string $method
- * @param string $uri
- * @param array $parameters
- * @param array $cookies
- * @param array $files
- * @param array $server
- * @param string $content
- *
- * @return \Illuminate\Http\Response
- */
- public function callRoute($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null)
- {
- $server = collect([
- 'CONTENT_TYPE' => 'application/json',
- 'Accept' => 'application/json',
- ])->merge($server)->toArray();
- $request = Request::create(
- $uri, $method, $parameters,
- $cookies, $files, $this->transformHeadersToServerVars($server), $content
- );
- $kernel = App::make('Illuminate\Contracts\Http\Kernel');
- $response = $kernel->handle($request);
- $kernel->terminate($request, $response);
- return $response;
- }
- /**
- * Get a response from the transformer tags.
- *
- * @param array $tags
- *
- * @return mixed
- */
- protected function getTransformerResponse($tags)
- {
- try {
- $transFormerTags = array_filter($tags, function ($tag) {
- if (! ($tag instanceof Tag)) {
- return false;
- }
- return \in_array(\strtolower($tag->getName()), ['transformer', 'transformercollection']);
- });
- if (empty($transFormerTags)) {
- // we didn't have any of the tags so goodbye
- return false;
- }
- $modelTag = array_first(array_filter($tags, function ($tag) {
- if (! ($tag instanceof Tag)) {
- return false;
- }
- return \in_array(\strtolower($tag->getName()), ['transformermodel']);
- }));
- $tag = \array_first($transFormerTags);
- $transformer = $tag->getContent();
- if (! \class_exists($transformer)) {
- // if we can't find the transformer we can't generate a response
- return;
- }
- $demoData = [];
- $reflection = new ReflectionClass($transformer);
- $method = $reflection->getMethod('transform');
- $parameter = \array_first($method->getParameters());
- $type = null;
- if ($modelTag) {
- $type = $modelTag->getContent();
- }
- if (version_compare(PHP_VERSION, '7.0.0') >= 0 && \is_null($type)) {
- // we can only get the type with reflection for PHP 7
- if ($parameter->hasType() &&
- ! $parameter->getType()->isBuiltin() &&
- \class_exists((string) $parameter->getType())) {
- //we have a type
- $type = (string) $parameter->getType();
- }
- }
- if ($type) {
- // we have a class so we try to create an instance
- $demoData = new $type;
- try {
- // try a factory
- $demoData = \factory($type)->make();
- } catch (\Exception $e) {
- if ($demoData instanceof \Illuminate\Database\Eloquent\Model) {
- // we can't use a factory but can try to get one from the database
- try {
- // check if we can find one
- $newDemoData = $type::first();
- if ($newDemoData) {
- $demoData = $newDemoData;
- }
- } catch (\Exception $e) {
- // do nothing
- }
- }
- }
- }
- $fractal = new Manager();
- $resource = [];
- if ($tag->getName() == 'transformer') {
- // just one
- $resource = new Item($demoData, new $transformer);
- }
- if ($tag->getName() == 'transformercollection') {
- // a collection
- $resource = new Collection([$demoData, $demoData], new $transformer);
- }
- return \response($fractal->createData($resource)->toJson());
- } catch (\Exception $e) {
- // it isn't possible to parse the transformer
- return;
- }
- }
- /**
- * @param string $route
- * @param array $bindings
- *
- * @return array
- */
- protected function getRouteRules($route, $bindings)
- {
- list($class, $method) = explode('@', $route);
- $reflection = new ReflectionClass($class);
- $reflectionMethod = $reflection->getMethod($method);
- foreach ($reflectionMethod->getParameters() as $parameter) {
- $parameterType = $parameter->getClass();
- if (! is_null($parameterType) && class_exists($parameterType->name)) {
- $className = $parameterType->name;
- if (is_subclass_of($className, FormRequest::class)) {
- $parameterReflection = new $className;
- $parameterReflection->setContainer(app());
- // Add route parameter bindings
- $parameterReflection->query->add($bindings);
- $parameterReflection->request->add($bindings);
- if (method_exists($parameterReflection, 'validator')) {
- return app()->call([$parameterReflection, 'validator'])
- ->getRules();
- } else {
- return app()->call([$parameterReflection, 'rules']);
- }
- }
- }
- }
- return [];
- }
- }
|