# Documentación Marvel API Puntos principales: ## IndexController: ```php= <?php namespace App\Http\Controllers; use Illuminate\Http\Request; class IndexController extends Controller { /* Alojamos los datos de la conexión fuera de las funciones.*/ var $url = 'https://gateway.marvel.com:443/v1/public/'; public function index($offset=0) { $url = $this->url .'characters?offset='. $offset.'&'; $result = json_decode($this->makeRequest($url)); if(!isset($result->data)) { abort(404); } $total = $result->data->total; $result = $result->data->results; return view('index', ['result'=>$result, 'offset'=>$offset, 'total'=>$total]); } Credenciales de acceso a la API de marvel public function generateURL($url) { $public_key = 'ec8a1fb650d39076b1e3ce57e88fe2a9'; $private_key = 'fe05b324befc6b4d39b5611424a45581295269d6'; $ts= time(); $hash = md5($ts.$private_key.$public_key); return $url . 'apikey='. $public_key. '&ts='.$ts.'&hash='.$hash; } Request a la api de marvel public function makeRequest($url) { $curl = curl_init(); $data_url = $this->generateURL($url); curl_setopt_array($curl, [ CURLOPT_RETURNTRANSFER => 1, CURLOPT_URL => $data_url ]); $response = curl_exec($curl); curl_close($curl); return $response; } /*Función que muestra un personaje individual*/ public function show($id) { $url = $this->url . 'characters/' . $id . '?'; // URL para obtener detalles de un personaje específico $characterData = json_decode($this->makeRequest($url)); // Verifica si se obtuvo la información del personaje if (!isset($characterData->data) || !isset($characterData->data->results[0])) { return redirect()->route('index')->with('error', 'Detalles del personaje no encontrados'); } $character = $characterData->data->results[0]; return view('show', compact('character')); } /*Función que se encarga de la búsqueda y filtrado de personajes*/ public function filterCharacters(Request $request) { $nameFilter = $request->input('name'); $letterFilter = $request->input('filter'); $url = $this->url . 'characters?'; if ($nameFilter) { $url .= 'nameStartsWith=' . $nameFilter . '&'; } if ($letterFilter) { $url .= 'nameStartsWith=' . $letterFilter . '&'; } $result = json_decode($this->makeRequest($url)); if (!isset($result->data)) { abort(404); } $characters = $result->data->results; return view('filtered-characters', compact('characters')); } } ``` ## Plantilla del header ```php= <!DOCTYPE html> <html lang="en"> <style> .header-container { background-color: rgba(255, 255, 255, 0.5); } </style> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <link href="https://fonts.googleapis.com/css2?family=Rajdhani&display=swap" rel="stylesheet"> <link rel="stylesheet" href="{{asset('css/index.css')}}"> <title>ChupiMarvel</title> </head> <body> <div class="container header-container"> <div class="show"> <a href="{{route('index')}}"> <img src="https://designconceitual.com.br/wp-content/uploads/2016/07/Marvel_Studios_logo.svg_.png" style="width: 250px;margin:0 auto;padding: 10px 10px 10px 10px" alt=""> </a> </div> ``` ## Index (página principal) ```php= @include('layouts.header') <style> body { /* La imagen del background viene dada por una URL porque soy un mal programador.*/ background-image: url('https://external-preview.redd.it/x_BaPYAxk2f_G9g52hcWIThT0hoanye9zcjJJweFZkg.jpg?width=640&crop=smart&auto=webp&s=849263ee6ecbc498e87da055cad359206cc77190'); background-size: cover; background-repeat: no-repeat; background-attachment: fixed; color: #fff; margin: 0; padding: 0; box-sizing: border-box; } .main-container { margin: 2%; } .card { background-color: rgba(0, 0, 0, 0.7); color: #fff; margin-bottom: 15px; } form { color:black; } </style> <div class="main-container"> <div class="show"> <h1 style="color:black;"> LISTA DE PERSONAJES </h1> /* El form es la parte con más chicha del index, ya que se encarga de la búsqueda de personajes haciendo consultas a la Api porque, de nuevo, soy mal programador.*/ </div> <form action="{{ route('filterCharacters') }}" method="GET" class="form-group" style="width: 80%; margin: 0 auto;"> <label for="name">Buscar por nombre:</label> <input type="text" name="name" class="form-control" style="width: 80%;" placeholder="Busca tu personaje..." value="{{ request('name') }}"> <label for="filter">Filtrar por letra:</label> <select name="filter" class="form-control"> <option value="" {{ request('filter') === '' ? 'selected' : '' }}>Sin filtro</option> @foreach(range('A', 'Z') as $letter) <option value="{{ $letter }}" {{ request('filter') === $letter ? 'selected' : '' }}>{{ $letter }}</option> @endforeach </select> ¿Sabes por qué he puesto el botón de búsqueda y filtrado en el mismo? Exacto. <button type="submit" class="btn btn-light btn-sm" style="margin: 5px;">Filtrar y buscar</button> </form> <div class="show"> <div class="row"> @foreach ($result as $r) <div class='col-md-3'> <div class='card d-flex flex-column'> <img src="{{ $r->thumbnail->path.'.'.$r->thumbnail->extension }}" class="card-img-top" alt="{{ $r->name }}"> <div class='card-body'> <h4 class='card-title'>{{ $r->name }}</h4> <a href="{{ route('character.show', $r->id) }}" class="btn btn-danger btn-sm">Ver más</a> </div> </div> </div> @endforeach </div> </div> Botones de paginación. No funcionan muy bien, no sé si por el código en sí o porque la API no me da suficiente recursos para paginar. Avisado estás. <div class="buttons"> @if($offset != 0) <a href="{{ route('index', $offset - 20) }}" class="btn btn-light">Anterior</a> @endif @if($total >= $offset + 20) <a href="{{ route('index', $offset + 20) }}" class="btn btn-light" style="margin:2%;">Próximo</a> @endif </div> </div> </body> </html> ``` ## Show (página de personajes individuales) ```php= @include('layouts.header') <style> body { margin: 2%; position: relative; } .background-container::before { content: ""; background: url('https://external-preview.redd.it/x_BaPYAxk2f_G9g52hcWIThT0hoanye9zcjJJweFZkg.jpg?width=640&crop=smart&auto=webp&s=849263ee6ecbc498e87da055cad359206cc77190') center center; background-size: cover; position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: -1; opacity: 0.5; } .main-container { height: 100vh; /* Ajustar la altura al 100% de la ventana */ display: flex; justify-content: center; align-items: center; } .show { color: #fff; margin-bottom: 2%; } .card { background-color: rgba(0, 0, 0, 0.7); color: #fff; height: 100%; /* Ocupar el 100% de la altura del contenedor */ display: flex; flex-direction: column; justify-content: space-between; /* Ajustar el espacio entre elementos */ } .comic-list { list-style-type: none; padding: 0; } </style> <div class="background-container"> <div class="main-container"> <div class='col-md-6'> <div class='card'> <img src="{{ $character->thumbnail->path.'.'.$character->thumbnail->extension }}" class="card-img-top" alt="{{ $character->name }}"> <div class='card-body'> <h4 class='card-title'>{{ $character->name }}</h4> /* Simplemente consultamos los datos de la API. */ <p class="card-text">{{ $character->description }}</p> <p class="card-text"><strong>Número de cómics:</strong> {{ $character->comics->available }}</p> <strong>Cómics:</strong> <ul class="comic-list"> @foreach ($character->comics->items as $comic) <li>{{ $comic->name }}</li> @endforeach </ul> <a href="{{ route('index') }}" class="btn btn-danger btn-sm">Volver a la Lista</a> </div> </div> </div> </div> </div> </body> </html> ``` ## Vista de filtrado: ```php= @include('layouts.header') <style> body { background-image: url('https://external-preview.redd.it/x_BaPYAxk2f_G9g52hcWIThT0hoanye9zcjJJweFZkg.jpg?width=640&crop=smart&auto=webp&s=849263ee6ecbc498e87da055cad359206cc77190'); background-size: cover; background-repeat: no-repeat; background-attachment: fixed; color: #fff; margin: 0; padding: 0; box-sizing: border-box; } .main-container { margin: 2%; } .card { background-color: rgba(0, 0, 0, 0.7); color: #fff; height: 100%; display: flex; flex-direction: column; justify-content: space-between; margin-bottom: 15px; padding: 15px; } .filtered-cards-container { display: flex; flex-wrap: wrap; justify-content: space-between; } .filtered-card-wrapper { width: 23%; margin-bottom: 20px; } .btn-ver-mas { margin-top: 10px; } </style> <div class="background-container"> <div class="main-container"> <h1 class="show">Resultados del Filtro</h1> <div class="filtered-cards-container"> @foreach ($characters as $character) <div class='filtered-card-wrapper'> <div class='card'> <img src="{{ $character->thumbnail->path.'.'.$character->thumbnail->extension }}" class="card-img-top" alt="{{ $character->name }}"> <div class='card-body'> <h4 class='card-title'>{{ $character->name }}</h4> </div> <a href="{{ route('character.show', $character->id) }}" class="btn btn-danger btn-sm btn-ver-mas">Ver más</a> </div> </div> @endforeach </div> </div> </div> </body> </html> ``` ## WEB (rutas) ```php= <?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\IndexController; /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider and all of them will | be assigned to the "web" middleware group. Make something great! | */ /* Solo hay 3 rutas, la del index, la del show y la de filtrado. */ Route::get('/index', [IndexController::class, 'index'])->name('index'); Route::get('/filter-characters', [IndexController::class, 'filterCharacters'])->name('filterCharacters'); Route::get('/personajes/{id}', [IndexController::class, 'show'])->name('character.show'); ```