
Aplicación API de librería que usa la operación CRUD de Laravel 8
En este artículo, implementaremos una aplicación de librería Laravel 8 CRUD. Después de leer este artículo, podrá:
- Aprender a crear tablas en la base de datos
MySQLcon relaciones deOne-to-Manyy deMany-to-Many. - Implementar los modelos y las funciones a las que sirven.
- Saber cómo implementar CRUD con Laravel Resouce Controller
- Familiarízate con los métodos
belongsToybelongsToMany
Una definición simple del proyecto.
Cada libro pertenece a una editorial, por lo que podrá asignar su libro a una editorial específica o, si no puede encontrarlo, puede almacenar una nueva editorial en la base de datos.
Además de eso, puede almacenar autores en la tabla de autores e incluir uno de ellos o varios de ellos en su libro como el nombre del autor. Si no desea leer este texto completo, puede omitirlo y encontrar el código completo en el repositorio en el que inserto el enlace al final del artículo.
Echemos un vistazo a cómo está diseñada nuestra base de datos, luego profundizaremos en el código.

Relación uno a muchos
Existe una relación de uno a muchos entre libros y editores. Un elemento de los editores puede estar vinculado a muchos elementos de los libros, pero un miembro de los libros está vinculado a un solo elemento de los editores.
Relación de muchos a muchos
Existe una relación de muchos a muchos entre libros y autores.
Cada libro ha pertenecido a muchos autores y cada autor ha escrito muchos libros. Entonces, en esta situación, usaremos una tabla como tabla dinámica para almacenar relaciones. Nuestra tabla dinámica es book_authors.
Crear tablas en la base de datos
Después de crear el proyecto con el compositor, es hora de crear nuestras tablas y migrarlas a la base de datos. En Laravel, usaremos el siguiente comando para crear la tabla.
php artisan make:migration create_publishers_table
En primer lugar, crearemos la tabla de editores que tendrá la siguiente estructura:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreatePublishersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('publishers', function (Blueprint $table) {
$table->id();
$table->string('identifier')->unique();
$table->string('fname');
$table->string('lname');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('publishers');
}
}
Y aquí está el resto de las tablas que debe crear en orden:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBooksTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->id();
$table->string('isbn')->unique();
$table->string('name');
$table->string('year');
$table->integer('page');
$table->foreignId('publisher_id')->constrained('publishers');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('books');
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateAuthorsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('authors', function (Blueprint $table) {
$table->id();
$table->string('identifier')->uniqu();
$table->string('fname');
$table->string('lname');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('authors');
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateBookAuthorsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('book_authors', function (Blueprint $table) {
$table->id();
$table->foreignId('book_id')->constrained('books');
$table->foreignId('author_id')->constrained('authors');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('book_authors');
}
}
Crear modelos
En esta sección, hablaremos de los modelos y las funciones que cumplen. Primero, crearemos el modelo Publisher con el comando php artisan make:model Publisher y, como puede ver en la estructura de la base de datos, existe una relación de uno a muchos entre libros y editores, y esto se define mediante la definición de un método en el modelo Eloquent.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Publisher extends Model
{
use HasFactory;
/**
* @var array
*/
protected $fillable = [
'identifier',
'fname',
'lname',
];
/**
* publisher's books
*
* @return void
*/
public function books(){
return $this->hasMany(Book::class,'publisher_id');
}
}
Es hora de crear otros modelos y definir la relación de varios a varios entre libros y autores. así que crearemos el modelo BookAuthor como un pivote Eloquent. Para hacer esto, asegúrese de que su modelo se extienda Illuminate\Database\Eloquent\Relations\Pivot
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\Pivot;
class BookAuthor extends Pivot
{
use HasFactory;
protected $table = 'book_authors';
}
Y ahora crearemos el modelo Author, que contendrá la función con el nombre de los libros que usa el método belongsToMany y el modelo BookAuthor como modelo Pivot para obtener la lista de todos los libros del objeto autor.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Author extends Model
{
use HasFactory;
/**
* @var array
*/
protected $fillable = [
'identifier',
'fname',
'lname',
];
/**
* authors's books
*
* @return void
*/
public function books(){
return $this->belongsToMany(Author::class,'book_authors')->using(BookAuthor::class);
}
}
Finalmente, tendremos el modelo de libro que usa el método belongsTo para obtener el editor relacionado en la función con el nombre del editor y utiliza el método belongsToMany y el modelo BookAuthor como modelo dinámico para obtener la lista de todos los autores del objeto libro.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Book extends Model
{
use HasFactory;
/**
* @var array
*/
protected $fillable = [
'isbn',
'name',
'year',
'page',
'publisher_id',
];
/**
* book's publisher
*
* @return void
*/
public function publisher()
{
return $this->belongsTo(Publisher::class)
->withDefault([
'identifier' => 'WITHOUT ID',
'fname' => 'NOT FOUND',
'lname' => 'NOT FOUND',
]);
}
/**
* book's authors
*
* @return void
*/
public function authors()
{
return $this->belongsToMany(Author::class, 'book_authors')
->using(BookAuthor::class);
}
}
Crear controladores
- En este proyecto, cada controlador contendrá las siguientes funciones:
- La función de índice se utilizará para obtener una lista completa de todos los registros.
- En la función de tienda después de validar las solicitudes, se creará el nuevo elemento.
- La función show se usa para obtener el elemento específico pasando ID a la función.
- Pasamos el ID a la función de destrucción y luego detectamos elementos con el ID dado y luego lo borramos.
- La función de actualización se utiliza para actualizar el elemento dado en función de las solicitudes dadas.
<?php
namespace App\Http\Controllers;
use App\Models\Publisher;
use Exception;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
class PublisherController extends Controller
{
/**
* @var Model
*/
protected $model;
/**
* __construct
*
* @param Publisher $publisher
* @return void
*/
public function __construct(Publisher $publisher)
{
$this->model = $publisher;
}
/**
* @return Collection
*/
public function index()
{
$items = $this->model->with('books')->get();
return response(['data' => $items, 'status' => 200]);
}
/**
* @param Request $request
* @return Collection
*/
public function store(Request $request)
{
$request->validate([
'identifier' => 'required|unique:publishers|min:3',
'fname' => 'required',
'lname' => 'required',
]);
$this->model->create($request->all());
return $this->index();
}
/**
* @param mixed $id
* @return Collection
*/
public function destroy($id)
{
try {
$item = $this->model->with('books')->findOrFail($id);
$item->delete();
return $this->index();
} catch (ModelNotFoundException $e) {
return response(['message' => 'Item Not Found!', 'status' => 404]);
}
}
/**
* @param mixed $id
* @return Model
*/
public function show($id)
{
try {
$item = $this->model->with('books')->findOrFail($id);
return response(['data' => $item, 'status' => 200]);
} catch (ModelNotFoundException $e) {
return response(['message' => 'Item Not Found!', 'status' => 404]);
}
}
/**
* @param mixed $id
* @param mixed $request
* @return Collection
*/
public function update($id, Request $request)
{
try {
$item = $this->model->with('books')->findOrFail($id);
$item->update($request->all());
return response(['data' => $item, 'status' => 200]);
} catch (ModelNotFoundException $e) {
return response(['message' => 'Item Not Found!', 'status' => 404]);
}
}
}
En la función de actualización y almacenamiento de BookController, verá el código $item->authors()->sync($requeest->get('authors')). sync se puede utilizar para sincronizar ambos lados de una relación belongsToMany. De forma predeterminada, descarta todas las relaciones y solo mantiene las proporcionadas como argumentos. De manera similar, si desea eliminar una determinada relación de entidad de la tabla dinámica, puede usar el método. Por ejemplo, si desea eliminar a los autores de un libro, puede hacerlo con el código $item->authors()->detach().
<?php
namespace App\Http\Controllers;
use App\Models\Book;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
class BookController extends Controller
{
/**
* @var Model
*/
protected $model;
/**
* @param Model $book
* @return void
*/
public function __construct(Book $book)
{
$this->model = $book;
}
/**
* @return Collection
*/
public function index()
{
$items = $this->model->with('authors', 'publisher')->get();
return response(['data' => $items, 'status' => 200]);
}
/**
* @param Request $request
* @return Collection
*/
public function store(Request $request)
{
$request->validate([
'isbn' => 'required|digits:13|integer|unique:books,isbn',
'name' => 'required|min:3',
'year' => 'required|integer|digits:4',
'page' => 'required|integer',
'publisher_id' => 'exists:publishers,id',
'authors' => 'array',
'authors.*' => 'exists:authors,id'
]);
$item = $this->model->create($request->all());
$authors = $request->get('authors');
$item->authors()->sync($authors);
return $this->index();
}
/**
* @param mixed $id
* @return Collection
*/
public function destroy($id)
{
try {
$item = $this->model->with('authors', 'publisher')->findOrFail($id);
$item->authors()->detach();
$item->delete();
return $this->index();
} catch (ModelNotFoundException $e) {
return response(['message' => 'Item Not Found!', 'status' => 404]);
}
}
/**
* @param mixed $id
* @return Model
*/
public function show($id)
{
try {
$item = $this->model->with('authors', 'publisher')->findOrFail($id);
return response(['data' => $item, 'status' => 200]);
} catch (ModelNotFoundException $e) {
return response(['message' => 'Item Not Found!', 'status' => 404]);
}
}
/**
* @param mixed $id
* @param mixed $request
* @return Collection
*/
public function update($id, Request $request)
{
try {
$item = $this->model->with('authors', 'publisher')->findOrFail($id);
$item->update($request->all());
$authors = $request->get('authors');
$item->authors()->sync($authors);
return response(['data' => $item, 'status' => 200]);
} catch (ModelNotFoundException $e) {
return response(['message' => 'Item Not Found!', 'status' => 404]);
}
}
}
<?php
namespace App\Http\Controllers;
use App\Models\Author;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
class AuthorController extends Controller
{
/**
* @var Model
*/
protected $model;
/**
* @param Model $author
* @return void
*/
public function __construct(Author $author)
{
$this->model = $author;
}
/**
* @return Collection
*/
public function index()
{
$items = $this->model->with('books')->get();
return response(['data' => $items], 200);
}
/**
* @param Request $request
* @return Collection
*/
public function store(Request $request)
{
$request->validate([
'identifier' => 'required|unique:authors|min:3',
'fname' => 'required',
'lname' => 'required',
]);
$this->model->create($request->all());
return $this->index();
}
/**
* @param mixed $id
* @return Collection
*/
public function destroy($id)
{
try {
$item = $this->model->with('books')->findOrFail($id);
$item->books()->detach();
$item->delete();
return $this->index();
} catch (ModelNotFoundException $e) {
return response(['message' => 'Item Not Found!', 'status' => 404]);
}
}
/**
* @param mixed $id
* @return Model
*/
public function show($id)
{
try {
$item = $this->model->with('books')->findOrFail($id);
return response(['data' => $item, 'status' => 200]);
} catch (ModelNotFoundException $e) {
return response(['message' => 'Item Not Found!', 'status' => 404]);
}
}
/**
* @param mixed $id
* @param mixed $request
* @return Collection
*/
public function update($id, Request $request)
{
try {
$item = $this->model->with('books')->findOrFail($id);
$item->update($request->all());
return response(['data' => $item, 'status' => 200]);
} catch (ModelNotFoundException $e) {
return response(['message' => 'Item Not Found!', 'status' => 404]);
}
}
}
Crear rutas
Finalmente, definiremos nuestras rutas en el directorio routes/api.php. Usando Route:apiResource configura algunas rutas predeterminadas. Y puede ver la lista de todas las rutas ejecutando el comandode Artisan route:list.
<?php
use App\Http\Controllers\AuthorController;
use App\Http\Controllers\BookController;
use App\Http\Controllers\PublisherController;
use Illuminate\Support\Facades\Route;
Route::apiResource('authors', AuthorController::class);
Route::apiResource('publishers', PublisherController::class);
Route::apiResource('books',BookController::class);
Ahora tienes una API de librería. El código completo se encuentra en el siguiente repositorio.
https://github.com/hanieas/Tutorial-Book-Store-API
Espero que este curso lo ayude a familiarizarse con el diseño de bases de datos, las relaciones de uno a muchos y las relaciones de muchos-a-muchos en Laravel.




