Cómo insertar nuevos registros

12/17

Lectura

Ya tenemos nuestro controlador principal para operar sobre la tabla de proyectos, ahora aprenderemos a insertar nuevos registros en la tabla projects.

Creamos una nueva función en nuestro ProjectController, la llamaremos insertProject y aquí haremos la magia:

$project = new Project;
$project->name = 'Nombre del proyecto';
$project->save();

Este bloque de código nos agregaría un nuevo proyecto con solo un valor en su campo name.

Lo primero que hacemos es crear una instancia del modelo Project y lo almacenamos en una variable, de ahí tomamos esa misma variable e indicamos cada campo de la tabla y le asignamos el valor que va a guardar. Finalmente, le indicamos la acción, que en este caso será save() para guardar.

En el caso de agregar un registro completo para nuestra tabla projects, la función que acabamos de crear quedaría así:

public function insertProject() {
    $project = new Project;
    $project->city_id = 1;
    $project->company_id = 1;
    $project->user_id = 1;
    $project->name = 'Nombre del proyecto';
    $project->execution_date = '2020-04-30';
    $project->is_active = 1;
    $project->save();

    return "Guardado";
}

Ahora te preguntarás por qué no hemos agregado los campos created_at y updated_at para asignarles valores, lo que sucede es que el método save() ya se encarga de asignarles la fecha/hora actual de manera automática, si deseas asignar una valor diferente se lo puedes dar como los demás campos, pero recuerda que estos campos son de tiempo datetime.

Recuerda que no siempre vamos a guardar los registros de esta forma estática y, por lo general, vendrán de algún formulario o una fuente que nos dirá cuáles serán los valores de los registros, en ese caso, tendríamos que asignar $request pero la estructura se mantendría exactamente igual:

public function insertProject(Request $request) {
    $project = new Project;
    $project->city_id = $request->cityId;
    $project->company_id = $request->companyId;
    $project->user_id = $request->userId;
    $project->name = $request->name;
    $project->execution_date = $request->executionDate;
    $project->is_active = $request->isActive;
    $project->save();
}

Ahora probemos esta nueva función de insertar un nuevo proyecto en la tabla projects, haremos el mismo procedimiento de agregar una ruta que apunte a esta función.

Vuelve al archivo web.php y agrega esta ruta:

Route::get('insertNewProject', '[email protected]');

Limpiemos caché desde la consola:

php artisan cache:clear

Iniciamos el servidor nuevamente:

php artisan serve

Vamos al navegador y escribimos en la barra de direcciones:

http://localhost:8000/insertNewProject

Y nos debe salir solo un mensaje que diga “Guardado”, pues es lo que le indicamos en la función que mostraría en el return. Si esto sucede, nuestro registro ha sido guardado, podemos verificarlo entrando a nuestra base de datos desde la consola de MySQL o ejecutando la ruta anterior que nos trae todos los registros de la tabla projects.

Reto 🏁

Ya sabes cómo insertar un registro en nuestra base de datos usando el modelo Project, ya estás listo para este reto: inserta 30 registros en la tabla projects y agrega registros también a las tablas que tenemos aún vacías: cities, companies y users.

En la siguiente clase aprenderás a actualizar registros que están previamente creados en la base de datos y lo haremos utilizando Modelos de Eloquent. ¡Vamos 🏃🏻‍♀️!

Aportes 20

Preguntas 1

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Creación de datos por defecto utilizando factoties:

  1. Configuración de factories para cada modelo: se establece con que datos se van a llenar los campos de las tablas.

Cities:

$factory->define(City::class, function (Faker $faker) {
    return [
        'name' => $faker->city
    ];
});

Companies:

$factory->define(Company::class, function (Faker $faker) {
    return [
        'name' => $faker->company
    ];
});

Users:

$factory->define(User::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'email_verified_at' => now(),
        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
        'remember_token' => Str::random(10),
    ];
});

Projects:

$factory->define(Project::class, function (Faker $faker) {
    return [
        'city_id' => rand(1, 80),
        'company_id' => rand(1, 20),
        'user_id' => rand(1, 3),
        'budget' => rand(15000, 90000),
        'name' => $faker->sentence(),
        'execution_date' => $faker->date(),
        'is_active' => $faker->boolean()
    ];
});
  1. Configuracion de cargue de datos por defecto utilizando Faker en /database/seeds/DataBaseSeeder.php
    public function run()
    {
        factory(App\City::class, 80)->create();
        factory(App\Company::class, 20)->create();

        // Creacion 1 un User con datos establecidos
        App\User::create([
            'name'      => 'Dany Pascual Gómez Sánchez',
            'email'     => '[email protected]',
            'password'  =>  bcrypt('123456')
        ]);

        // Creacion de 2 users mas genericos
        factory(App\User::class, 2)->create();

        factory(App\Project::class, 10)->create();
    }
  1. Ejecucion de la configuracion realizada desde ventada de comandos:
php artisan migrate:refresh --seed + Enter
  1. DATOS CARGADOS A BD

Existe otra alternativa para crear los registros en la base de datos y es usando la función create del modelo.
Se puede pasar el array o incluso el request completo, sólo que se debe tener en cuenta los campos que son fillable (esto se define en el modelo con la propiedad $fillable), además también hay que tener en cuenta que cuando usamos formularios, se debe definir dentro del formulario un csrf token para poder actualizar la información.

Primero se debe ajsutar el modelo para permitir almacenar los campos:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Project extends Model
{
    protected $fillable = [
        'name',
        'company_id',
        'city_id',
        'user_id',
        'execution_date',
        'is_active',
    ];
}

Segundo, se puede hacer el registro usando el create del modelo:

    public function insertProject()
    {
        return Project::create([
            'city_id' => 1,
            'company_id' => 1,
            'user_id' => 1,
            'name' => 'Nombre del proyecto',
            'execution_date' => now(),
            'is_active' => true,

        ]);
    }

O también si viene de un request, se puede pasar todo el request (obviamente se debe validar previamente, pero para efectos de este ejercicio podría ir así también)

    public function insertProject(Request $request)
    {

        return Project::create($request->all());
    }

Aquí pueden leer un poco más del tema:
https://laravel.com/docs/7.x/eloquent#other-creation-methods

Una forma mucho más fácil, más ordenada y más legible de insertar datos con Eloquent es usando la función “create” del modelo:

$project = Project::create([
            "city_id" => 1,
            "company_id" => 1,
            "user_id" => 1,
            "name" => 'Nombre del proyecto',
            "execution_date" => '2020-04-30',
            "is_active" => 1
]);

Con esto basta usar un array asociativo para hacer la inserción, y es un método más seguro, pues para que esa función pueda funcionar debes ir a tu modelo y especificar un atributo llamado $fillable indicando qué campos quieres que puedan ser insertables, si tratas de insertar un campo que NO definiste como insertable en $fillable devolverá un error, para definir $fillable, debes ir a tu modelo y agregar un array simple con los campos que son insertables:

protected $fillable = ["city_id", "company_id", "user_id", "name", "execution_date", "is_active"];

Cabe acotar que, si los campos que llegan en el request son similares en nombres a nuestra estructura de base de datos, se podría resumir de la siguiente forma:

public function insertProject() {
    $project = new Project;
    $project->fill($request);
    $project->save();

    return "Guardado";
}

Para esto, los campos dentro de la propiedad fillable del modelo tienen que contener todos los campos de la tabla correspondiente o haber seteado la propiedad guarded a un array vacío. Por ejemplo:

# Project model
# Pueden hacerlo de esta forma 👇 (se define propiedades para permitir realizar asignación masiva)
protected $fillable = [
    'city_id', 'company_id', 'user_id', 'name', 'execution_date', 'is_active'
];

# O de esta 👇 (se definen propiedades para evitar realizar asignación masiva)
protected $guarded = [];

Link de referencia

Hola para cubrir este reto les recomindo usar Seeding y Factories

woooow anteriormente yo también me preguntaba por que no se guardaban los campos created_at y updated_at pero con gracias a esta lectura puedo saber que es porque save() ya se encarga de asignarles la fecha y hora actual de manera automática o:

Aqui mi metodo para insertar registros de prueba

public function insertProject () {
        $project = new Project;
        $project->name = 'Nombre del proyecto';
        $project->save();

        foreach (range(0, 30) as $number) {
            $user = new User;
            $user->name = "User - {$number}";
            $user->save();

            $company = new Company;
            $company->name = "Company - {$number}";
            $company->save();

            $city = new City;
            $city->name = "City - {$number}";
            $city->save();
        }
    }

dejo mi repositorio por si alguien quiere checar mi base de mi reto usando factory y seeding

https://github.com/MiguelAngelMP/Curso-de-Manejo-de-Datos-en-Laravel-con-Eloquen/tree/featureFactoryseeder

recomiendo para hacer esta tarea los seeders y factories
https://laravel.com/docs/7.x/seeding

La forma más sencilla que se me ocurrió (sin usar Seeders) por que no los puso como opción fue la siguiente:
Creé 6 ciudades manualmente en la BD, 5 usuarios Manuales, 6 compañías y de ahí cree la siguiente función:

public function insertProjects() {
        for ($i=1; $i < 31; $i++) { 
            $project = new Project;
            $project->city_id = rand(1,5);
            $project->company_id = rand(1,6);
            $project->user_id = rand(1,5);
            $project->name = "Proyecto {$i}";
            $project->execution_date = "2020-04-{$i}";
            $project->is_active = rand(0,1);
            $project->save();
        }
            return "Registros exitosamente guardados ";
    }

Y justo aquí el gran problema de los ORM que implementan Active Record!

completado 😃

reto completado!!!

Done!

Lo que ha hecho que me enamore de laravel, aunque existe en otros frameworks en php puro con consultas sql nunca lo pude hacer ni encontré documentación, o seguramente hasta ahora se me abrió el panorama. OBTENER EL ID DEL INSERT.

en php puro y querrys, haces el insert y despues hacer la consulta del ultimo registro y ahi lo obtienes, el problema viene cuando tienes un sistema de alta demanda, se te cruza la información justo en esa consulta, y debes agregar condicionales de busqueda. lo que lo hace más tardado, con laravel queda así:

    //metodo save
    $project = new Project;
    $project->city_id = 1;
    $project->company_id = 1;
    $project->user_id = 1;
    $project->name = 'Nombre del proyecto';
    $project->execution_date = '2020-04-30';
    $project->is_active = 1;
    $project->save();

    return "Guardado. ".$project->project_id;

Para generar datos de prueba:

ProjectFactory

$factory->define(Project::class, function (Faker $faker) {
    return [
        'name' => $faker->sentence(),
        'budget' => rand(1000, 10000),
        'execution_date' => $faker->date(),
        'is_active' => rand(0, 1),
        'city_id' => rand(1, 10),
        'company_id' => rand(1, 5),
        'user_id' => rand(1, 20)
    ];
});

CityFactory

$factory->define(City::class, function (Faker $faker) {
    return [
        'name' => $faker->city()
    ];
});

CompanyFactory

$factory->define(Company::class, function (Faker $faker) {
    return [
        'name' => $faker->company()
    ];
});

Para crear los datos semilla:
DataBaseSeeder

public function run()
    {
        factory(App\User::class, 20)->create();
        factory(App\City::class, 10)->create();
        factory(App\Company::class, 5)->create();
        factory(App\Project::class, 30)->create();
    }

Clase breve y sencilla :0

Hola para los que desean hacer el Factory de la tabla projects y no estan seguros de como agregar un id foraneo con faker:

//Factory
public function definition()
    {
        $cities = City::all()->pluck('id')->toArray();
        $companies = Company::all()->pluck('id')->toArray();
        $users = User::all()->pluck('id')->toArray();
        //$is_active = [0,1];

        return [
            'city_id' => $this->faker->randomElement($cities),
            'company_id' => $this->faker->randomElement($companies),
            'user_id' => $this->faker->randomElement($users),
            'name' => $this->faker->name,
            'execution_date' => $this->faker->date('Y-m-d', 'now'),
            //'is_active' => $this->faker->randomElement($is_active)
            'is_active' => 1
        ];
    }

Los campos created_at y updated son campos de tipo TIMESTAMP

Estuve revisando un poco los comentarios y aunque vi algunas soluciones similares, creo que el mío puede aportar un poco también. Versión de Laravel 8.

ProjectController

public function insertProject(ProjectRequest $projectRequest)
{
    Project::create($projectRequest->validated());

    return response()->json(['message' => 'Guardado exitosamente'], Response::HTTP_CREATED);
}

Se puede mejorar por supuesto. Pero la intención era aplicar lo aprendido hasta ahora, creando una clase “ProjectRequest” que pudiera proveer de una validación al recibir datos de manera dinámica desde un cliente, en particular yo usé Postman. Si todo pasa bien y se crea el proyecto entonces respondo con un mensaje y el status correspondiente (Recomiendo usar siempre la clase “Symfony\Component\HttpFoundation\Response” de manera de no tener nuestros status en duro).

ProjectRequest

<?php

namespace App\Http\Requests;

use Illuminate\Contracts\Validation\Validator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Exceptions\HttpResponseException;

class ProjectRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'city_id' => ['required', 'exists:cities,city_id'],
            'company_id' => ['required', 'exists:companies'],
            'user_id' => ['required', 'exists:users'],
            'name' => ['required'],
            'execution_date' => ['required'],
            'is_active' => ['required', 'boolean']
        ];
    }

    protected function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(response()->json($validator->errors(), 422));
    }
}

La función protected failerValidation, funciona muy bien cuando tienes la rutas definidas a nivel de API en Laravel y esperas una respuesta del tipo JSON y de esa manera puedes devolver error entendibles por cliente que espere JSON.

**Project ** (modelo)

     /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'city_id',
        'company_id',
        'user_id',
        'name',
        'is_active',
        'execution_date'
    ];

Para poder especificar cuales son los campos que va a recibir masivamente.

A continuación, el resto de la lógica para el llenado de las tablas utilizando las funcionalidades de factory y seeder de Laravel.

CityFactory

namespace Database\Factories;

use App\Models\City;
use Illuminate\Database\Eloquent\Factories\Factory;

class CityFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = City::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'name' => $this->faker->city
        ];
    }
}

CompanyFactory

namespace Database\Factories;

use App\Models\Company;
use Illuminate\Database\Eloquent\Factories\Factory;

class CompanyFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Company::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'name' => substr($this->faker->company, 0, 20)
        ];
    }
}

Hago un truncado del faker para evitar quese me pase dela restricciónde 20 caracteres quese introdujo enla base de datos al definir la tabla.

UserFactory

namespace Database\Factories;

use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class UserFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = User::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        /*return [
            'name' => $this->faker->name,
            'email' => $this->faker->unique()->safeEmail,
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];*/
        return [
            'name' => $this->faker->firstName
        ];
    }

    /**
     * Indicate that the model's email address should be unverified.
     *
     * @return \Illuminate\Database\Eloquent\Factories\Factory
     */
    /*public function unverified()
    {
        return $this->state(function (array $attributes) {
            return [
                'email_verified_at' => null,
            ];
        });
    }*/
}

ProjectFactory

namespace Database\Factories;

use App\Models\Project;
use Illuminate\Database\Eloquent\Factories\Factory;

class ProjectFactory extends Factory
{
    /**
     * The name of the factory's corresponding model.
     *
     * @var string
     */
    protected $model = Project::class;

    /**
     * Define the model's default state.
     *
     * @return array
     */
    public function definition()
    {
        return [
            'city_id' => rand(1, 30),
            'company_id' => rand(1, 30),
            'user_id' => rand(1,30),
            'name' => substr($this->faker->company . ' Project', 0, 30),
            'execution_date' => $this->faker->dateTimeBetween('now', '90 days')->format('Y-m-d'),
            'is_active' => rand(0,1)
        ];
    }
}

Como solo voy a crear 30 ciudades, compañías y usuarios pues especifico que los ids solo esten entre esos valores, además también valido para que solo me duelva un nombre denomás de 30 caracteres y quela fecha de ejecición sea una fecha mayor a la fecha enla cual estoy ejecutando el seeder.

DatabaseSeeder

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
         \App\Models\City::factory(30)->create();
         \App\Models\Company::factory(30)->create();
         \App\Models\User::factory(30)->create();
         \App\Models\Project::factory(30)->create();
    }
}

Es importante destacar el orden enquese ejecutan porque el proyecto (Project) necesita de todos los modelos anteriores para poder crearse adecuadamente.

NOTA: Por favor si creen que algo no está bien implementado, es mejorable, o hay un error o mezcla de conceptos sin duda dejarlo en los comentarios para que todos podamos aprender.