docker : imagenes, contenedores daemons

Arquitectura docker:

se tiene el docker host que es donde se ejecuta el servidor de docker, ahi se corre el demonio Dockerd

se tiene el docker client a traves de una consola y ejecutando comandos se comunica con el DockerD para que realice tareas.


La imagen es como una plantilla de elementos que se necesitan para por ejemplo ubuntu+git+python
son de solo lectura, a partir de una imagen se crean los contenedores.

(analogia Imagen=Clase, y Un Contenedor = una instancia)

Las imagenes se almacenan en el docker host.

Las imagenes se obtienen de un repositorio de imagenes Image Registry, el mas famoso es docker hub.



docker instalacion

ir a https://docs.docker.com/
en el menu de la izquierda
Get Docker->install->Docker CE (el community)
y seleccionar el sistema operativo que tengas


clickear en la version stable, descargarla. Ejecutarla.
Luego reiniciar la maquina, docker se iniciara automaticamente
pero hay que esperar a que docker este es estado "is running".

paraverificar la instalacion abrimos una consola
 y tipeamos
docker version

nos deberia salir algo asi

entonces se ve que se esta usando un contenedor linux,
se puede cambiar a uno de tipo windows simplemente click derecho sobre el icono de docker que aparece en la esquina inferior derecha

y seleccionar Switch to Windows containers.







slim 3 php-di

dentro de tu aplicacion slim

composer require php-di/slim-bridge
ir a composer.json, agregar la sgt linea

"autoload": {
      "psr-4": {
         "App\\": "src/"
      }
    }


ejecutar por consola

composer dumpautoload

This means that you have a directory called src and any class inside that directory, will have a base namespace of App and then any other directories act as sub-namespaces.
i.e. if you have a file called src/Controllers/UserController.php, then the class definition in that file will be:
<?php
namespace App\Controllers;
class UserController
{
    // methods here
}

reemplazar el contenido del public/index.php

por este otro

<?php

require_once __DIR__ . '/../vendor/autoload.php';

use \Psr\Http\Message\RequestInterface;
use \Psr\Http\Message\ResponseInterface;


use App\Controllers\TodoController;

$app = new \DI\Bridge\Slim\App;

/*$app->get('/', function (RequestInterface $request, ResponseInterface $response) {
    $response->getBody()->write('Hello world!');

    return $response;
});
*/
$app->get('/[{greetee}]', TodoController::class . '::index');

// Register middleware
require __DIR__ . '/../src/middleware.php';

$app->run();



para probar la inyection de dependencias vamos a instalar mustache que resuelve vistas para inyectarselo a nuestro controller

composer require mustache/mustache


luego

<?php
namespace App\Controllers;

use \Psr\Http\Message\RequestInterface;
use \Psr\Http\Message\ResponseInterface;

class TodoController
{
private $mustache;

    public function __construct(\Mustache_Engine $mustache)
    {
       $this->mustache = $mustache;
    }

    public function index(RequestInterface $request, ResponseInterface $response, $greetee = null)
    {
    /*
        $response->getBody()->write('HOlaaaaaaaaaaaaaaaaaa!');

        return $response;*/

       /* $response->getBody()->write(
            $this->mustache->render('Hello {{ greetee }}', [
                'greetee' => 'World!'
            ])
        );*/

$response->getBody()->write(
            $this->mustache->render('Hola {{ greetee }} ', [
                'greetee' => $greetee ?? 'Mundo!'
            ])
        );
        return $response;
    }
}

When our container sees that TodoController needs a Mustache_Engine, it tries to create one to fulfill the dependency. Behold, the power of autowiring!




laravel 5.6 usuarios y roles - con tabla Roles

vamos a crear el modelo Role

php artisan make:model Role -m

-m nos crea el archivo de migracion

al que agregaremos algunos campos

Schema::create('roles', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name')->unique();
            $table->string('display_name');
            $table->text('description')->nullable();
            $table->timestamps();
        });
la diferencia entre string y text es la cantidad de caracteres, string solo 255, y text 20mil


php artisan migrate

creamos otra migration para la tabla Users para eliminar el campo role y agregar
uno nuevo llamado role_id (por convencion, singular de la tabla de la tabla a la que
hace referencia seguido del campo clave)

php artisan make:migration add_role_users_table --table=users

Schema::table('users', function (Blueprint $table) {
            //
             $table->integer('role_id');
             $table->dropColumn('role');

        });

vamos a crear una funcion para relacionar User con un Role

public function role(){
        return $this->belongsTo(Role::class);
    }

para luego modificar la condicion en la funcion que verifica los roles

public function hasRoles(array $roles)
    {
        foreach ($roles as $role) {
            if($this->role->name == $role){
                return true;
            }
        }
        return false;
    }

y en la vista users/index.blade.php

<td>{{$user->role->display_name}}</td>

para definir la relacion de muchos usuarios con un Role

vamos al model Role y agregamos la sgt function

 
    public function user(){
    return $this->hasMany('App\User');
    }

como prueba podemos crear el sgt end point, para ver los roles con los usuarios correspondientes

Route::get('roles',  function(){
    return \App\Role::with('user')->get();

// return \App\Role::all();//no te muestra la relacion con usuarios

});





laravel 5.6 usuarios y roles - forma simple

para empezar:

 crear el
controller UsersController y la function index()
vista index.blade.php

para la bd:

creamos una migration para agregarle el campo "role" a la tabla User

ejecutarla

php artisan migrate

con el cliente de bd editar el campo de algunos registros y ponerle a algunos admin y a otros moderador y operadores, para el ejemplo supongamos que los usuarios 'admin' y 'moderador' tienen acceso al listado de usuarios.

entonces, creamos

el metodo en User

function hasRoles(array $roles){
  foreach($roles as $role){
    if($this->role === $role){
        return true;
    }
  }
  return false;
}

entonces, esta funcion nos puede servir para usar como condicion en el menu para mostrar o no, la opcion "Usuarios"

@if( auth()->user()->hasRoles(['admin','moderador'])
<li class="nav-item {{ activeMenu('users') }}">
<a class="nav-link" href="{{ route('users.index') }}" >Usuarios</a>
</li>
@endif

ahora tenemos que hacer que la url sea solo accesible por los usuarios con esos roles, entonces,
creamos un middleware:

php artisan make:middleware CheckRoles

public function handle($request, Closure $next)
    {

        $roles = array_slice(func_get_args(), 2);

        if(auth()->user()->hasRoles($roles)){
            return $next($request);   
        }
        return redirect('/');
       
    }


donde:

func_get_args() trae todos los parametros que se envian en la llamada al middleware
array_slice(func_get_args(), 2) excluye a los 2 primeros ($request y $next) para quedarse con los restantes que serian la lista de roles validos

no olvidar registrar el middleware en el kernel.php

 'checkRoles' => \App\Http\Middleware\CheckRoles::class,

finalmente, en el constructor de UsersController

 public function __construct(){
       $this->middleware(['auth','checkRoles:admin,moderador']);
    }





php eloquent collection filter

$filtered_collection = $collection->filter(function ($item) {
    return $item->isDog();
});

php array_filter

en una clase...


private function criteria_nonsensitive_equal_than($key,$value){
//le mando la key porque cada item es un array con los indices representandome los campos
      return function($item) use ($key,$value) {
        return strtolower(trim($item[$key])) == strtolower(trim($value));
      };
    }

    public function getByName(istring $name) {

   
   
      $regions =  ..devuelve una \Illuminate\Support\Collection;
     

      $result = new \Illuminate\Support\Collection(array_filter($regions->toArray(), $this->criteria_nonsensitive_equal_than("name",$name)));
     
      return $result;


     
           
    }

git error al hacer pull

fatal: update_ref failed for ref 'HEAD': Cannot update the ref 'refs/heads/dev-israelb.1': unable to append to .git/logs/refs/heads/dev-israelb.1: Permiso denegado

solucion:

sudo chown -Rc $UID .git/

git comandos

mostrar las ramas locales
git branch

mostrar las ramas remotas
git branch -r



mostrar todas las ramas
git branch -a

cambiar de un branch a otro

git checkout otro-rama

crear una rama local a partir de una remota

git checkout --track origin/rama-remota
(se creara con el mismo nombre del remoto)

git checkout -b myBranchName repo2/master

git checkout -b [branch] [remotename]/[branch]


a veces, cuando se trabaja, los archivos estan en un estado sucio (messy state)
y justo necesitamos cambiar de branch, para lo cual deberemos tener todos
los cambios commiteados. Pero no queremos tener que commitear archivos
que aun no estan terminados. La solucion es

git stash

si se tuviese algun archivo sin trackear (nuevo)

git stash -u
si se quiere guardar con algun nombre
git stash save -u "algun nombre"

para traer de nuevo los cambios guardados en el stash en el branch en el que estes

git stash apply


como mergear 2 branches locales, por ejemplo pasar los cambios de rama2 a rama1


git checkout rama1 (situarse en el branch)
Then merge the rama2:

git merge rama2
para borrar un branch local
git branch -d the_local_branch

para forzar la eliminacion


git branch -D the_local_branch
eliminar/borrar branch remoto
git push origin --delete the_remote_branch



laravel 5.6 mix webpack css bottstrap



en package.json tenemos definidas las dependencias de node.js para instalarlas usamos su manejador de paquetes npm

npm install

esto nos creara una nueva carpeta node_modules

el archivo webpack.mix.js
es donde iran todas las tareas programadas

por default ya vienen un par

mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css');

para compilar app.js y que el resultado se grabe en public/js
y oara compilar app.scss y copiar el resultado en public/css

entonces , aprovechamos y pegamos en app.scss el codigo de css que teniamos en el layout

.active {
  text-decoration: none;
  color: green;
}
.error {
  font-size: 12px;
  color: red;
}

y luego corremos

npm run dev


ahora solo falta agregarlo en el head del layout

<link rel="stylesheet" type="text/css" href="{{ asset('/css/app.css') }}">

ahora pasemos nuestro codigo a bootstrap 4 (es la version que viene)

para facilitarnos la tarea instalamos un package de sublime

ctrl+shift+p

y luego buscamos bootstrap 4 snippets

luego de que se instale vamos

a preferences->settings
y agregamos la sgt linea

"auto_complete_triggers": [{"selector": "text.html", "characters": "b4"}]


ahora volvamos al layout, vamos a hacerlo desde cero

y tipeamos

b4template   (seleccionar b4:template:navbars)

esto nos creara toda la estructura vacia con distintos navbars, dejar el que necesitemos, y volver a escribir los links verdaderos.



tip: para que se compile automaticamente los cambios en app.scss
en la consola
npm run watch

para optimizar los archivos generados de css y js

ejecutar

npm run dev


se puede tambien unir varios archivos de estilos
por ejemplo si tengo un archivo signin.css

en resources/assets

creo una carpeta (por convencion) llamada components
y lo guardo ahi con la extension scss

luego en app.scss lo importo

@import 'components/signin'

el resultado ira a un unico archivo app.css



para agregar bootstrap.js

vamos al archivo webpack.mix.js
y agregamos la tarea

mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css')
   .js('node_modules/bootstrap/dist/js/bootstrap.js', 'public/js');

esto nos creara un archivo llamado bootstrap dentro de public/js/


como bootstrap necesita de jquery si en package.json no estuviera

lo instalamos como dependencia

npm install jquery --save

(--save lo registra en package.json)

luego en webpack.mix.js lo agregamos como tarea para que compile y llevarlo a nuestra carpeta public/js

mix.js('resources/assets/js/app.js', 'public/js')
   .sass('resources/assets/sass/app.scss', 'public/css')
   .js('node_modules/jquery/dist/jquery.js', 'public/js')
   .js('node_modules/bootstrap/dist/js/bootstrap.js', 'public/js');

compilarlo con npm run dev

y en el layout antes de la etiqueta de fin del body

<script type="text/javascript" src="{{ asset('/js/jquery.js') }}"></script>
<script type="text/javascript" src="{{ asset('/js/bootstrap.js') }}"></script>



laravel 5.6 autenticacion usuario


laravel viene con un controlador en app/http/controllers/Auth llamado LoginController

este usa el trait trait AuthenticatesUsers
que tiene el metodo  showLoginForm que devuelve la vista auth.login(hay que crearla)

en las rutas web.php

Route::get('login', ['as'=>'login', 'uses'=>'Auth\LoginController@showLoginForm']);

el formulario llamara a login pero por el metodo Post

Route::post('login', ['as'=>'login', 'uses'=>'Auth\LoginController@showLoginForm']);

crearemos una vista con el formulario de login

@extends('layout')

@section('contenido')

<h1>Login</h1>

<form action="{{ route('login') }}" method="POST">
{!! csrf_field() !!}
<input type="text" name="email" placeholder="email">
<input type="password" name="password" placeholder="password">
<input type="submit" value="ingresar">
</form>
@stop

previamente creamos algun usuario de prueba en nuestra BD
por ejemplo asi

Route::get('creausuario/{name}', ['as'=>'creausuario', function($name){
$user = new App\User;
$user->name =$name;
$user->email =$name.'@gmail.com';
$user->password =bcrypt('123123');
$user->save();
return $user;
}]);

cuando laravel validate que el email y password existen, redirecciona a la ruta home

podemos crear tambien la tuta para salir

Route::get('logout', ['as'=>'logout', 'uses'=>'Auth\LoginController@logout']);


y modificar el layout para que aparezcan las opciones de login o salir segun si se esta logueado:

@if( auth()->guest() )
  <a href="{{ route('login') }}"  class ="{{ activeMenu('login') }}">login</a>
@else
  <a href="{{ route('logout') }}"  class ="{{ activeMenu('logout') }}">Salir</a>
    @endif



para validar el ingreso a una pagina solo si el usuario esta authenticado
usamos el middleware  Authenticate.php

el cual redirecciona al login si el usuario no esta authenticado

este middleware esta registrado en el kernel con la key 'auth'

 'auth' => \Illuminate\Auth\Middleware\Authenticate::class,

entonces
si por ejemplo queremos restringir el acceso al modulo de mensajes
en el constructor de messagesController le especificamos el middleware

 public function __construct(){
        $this->middleware('auth');

    }

restringiendo el ingreso a todas las funciones del controller

esto lo podemos cambiar, especificando a quienes aplicarlo 'only' o a cuales no 'except'

por ejemplo si queremos que la pagina de contacto sea de acceso libre

 public function __construct(){
       $this->middleware('auth',['except'=>['create']]);


 }

       
       




laravel 5.6 ORM eloquent



Route::get('mensajes/crear', ['as'=>'mensajes.create','uses'=>'MessagesController@create']);
Route::post('mensajes', ['as'=>'mensajes.store','uses'=>'MessagesController@store']);
Route::get('mensajes', ['as'=>'mensajes.index','uses'=>'MessagesController@index']);
Route::get('mensajes/{id}', ['as'=>'mensajes.show','uses'=>'MessagesController@show']);
Route::get('mensajes/{id}/edit', ['as'=>'mensajes.edit','uses'=>'MessagesController@edit']);
Route::put('mensajes/{id}', ['as'=>'mensajes.update','uses'=>'MessagesController@update']);
Route::delete('mensajes/{id}', ['as'=>'mensajes.destroy','uses'=>'MessagesController@destroy']);


todas las lineas anteriores, se pueden reemplazar por una sola linea:

Route::resource('mensajes','MessagesController');

si listamos todas las rutas de nuestro proyecto

php artisan route:list

veremos algo asi











ORM

representacion de una tabla como una clase

table messages = clase Message

por convencion las tablas en plural y la clase en singular


php artisan make:model Message

esto creara en App el archivo Message.php

Laravel relacionara automaticamente una tabla con el mismo nombre de la clase pero en plural.

(si se quiere tener una clase que no cumpla esta regla se puede
agregar la sgt propiedad

protected $table = 'nombre de la tabla';
)

entonces ahora en el controller reemplazamos el querybuilder con el modelo

en la funcion que lista los mensajes


//$messages = DB::table('messages')->get();

 $messages = Message::all();


en la que crea un mensaje

 Message::create($request->all());


claro que para que funcione (asi nos dara una error porque en la asignacion masiva de datos no encuentra  un campo llamado _token, por ahora se lo quitamos y desactivamos la validacion por csfr

debemos tambien indicarle a laravel que campos vamos a permitir que se envien de modo masivo
(de otro modo manipulando el dom, se podran enviar campos como id que no queremos que se envien)

entonces en el modelo

protected $fillable = ['nombre','email','mensaje'];

laravel automaticamente le agrega los campos created_at  y updated_at


y en los metodos que muestra un mensaje:

   $message = Message::find($id);

claro que si se introduce un id que no existe nos va a dar una exception pues la vista por ejemplo de show va a querer acceder a las propiedades de un objeto nulo.

lo que se puede hacer es

$message = Message::findOrFail($id);

si no lo encuentra devuelve un error 404

podemos entonces ahora personalizar el error

en resources/views/errors

creamos 404.blade.php

<!DOCTYPE html>
<html>
<head>
<title>error</title>
</head>
<body>
No se pudo encontrar el recurso.

<a href="{{ route('home') }}">volver</a>
</body>
</html>

para la actualizacion:

$message = Message::findOrFail($id);
        $message->update($request->all())  ;

se puede hacer en una linea

Message::findOrFail($id)->update($request->all())  ;

para la eliminacion:

Message::findOrFail($id)->delete()  ;










laravel 5.6 implementacion de arquitectura rest con query builder


para generar un Restfull controller debemos agregar la opcion "--resource" a nuestro comando de creacion de controlador


php artisan make:controller MessagesController --resource

/**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }

ahora vamos a crear la ruta que llame al metodo create para que nos muestre el formulario de creacion

en routes/web.php:

Route::get('mensajes/crear', ['as'=>'messages.create','uses'=>'MessagesController@create']);

por convencion el nombre de la ruta
sera el nombre del recurso + un punto + el metodo del controlador

creamos en resources/views la carpeta messages y dentro la vista create.blade.php

para poder llamarla desde el controlador asi:

public function create()
    {
        return view('messages.create');
    }

ahora hacemos lo mismo para la funcion que procesa los datos del formulario:

en web.php

Route::post('mensajes', ['as'=>'messages.store','uses'=>'MessagesController@store']);


en la vista create.blade.php

<form method="POST" action="{{ route('messages.store') }}">


en el controller:

use DB;
use Carbon\Carbon;
 public function store(Request $request)
    {
        DB::table('messages')->insert([
            "nombre" => $request->input('nombre'),
            "email" => $request->input('email'),
            "mensaje" => $request->input('mensaje'),
            "created_at" => Carbon::now(),
            "updated_at" => Carbon::now()
        ]);
        return redirect()->route('messages.index');
    }

nos falta crear ahora la ruta messages.index, la vista y la llamada en el controller.

Route::get('mensajes', ['as'=>'messages.index','uses'=>'MessagesController@index']);

  public function index()
    {
        $messages = DB::table('messages')->get();
        return view('messages.index',compact('messages'));
    
    }
en la vista
@foreach($messages as $message)
<tr>
<td> {{$message->nombre}}</td>
<td>{{$message->email}}</td>
<td>{{$message->mensaje}}</td>
           
       
</tr>
@endforeach


para ver los datos de un mensaje por id

Route::get('mensajes/{id}', ['as'=>'messages.show','uses'=>'MessagesController@show']);

en el controller

use DB;
public function show($id)
    {
        $message = DB::table('messages')->where('id',$id)->first();
        return view('messages.show',compact('message'));
    }

en la vista de index. podemos agregar un link por cada registro para ver informacion de ese registro
asi:

<li><a href="{{ route('messages.show',$message->id) }} ">ver</a> </li>

igualmente para editar:

Route::get('mensajes/{id}/edit', ['as'=>'messages.edit','uses'=>'MessagesController@edit']);
Route::put('mensajes/{id}', ['as'=>'messages.update','uses'=>'MessagesController@update']);

la primera ruta llama a la vista con el formulario de edicion
la segunda ruta ejecuta la edicion

en el controller:

 public function edit($id)
    {
        $message = DB::table('messages')->where('id',$id)->first();
         return view('messages.edit',compact('message'));
    
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        
        DB::table('messages')->where('id',$id)->update([
            "nombre" => $request->input('nombre'),
            "email" => $request->input('email'),
            "mensaje" => $request->input('mensaje'),
            "updated_at" => Carbon::now()
        ]);
        return redirect()->route('messages.index');
    }
y en la vista edit.blade.php:

<form method="POST" action="{{ route('messages.update', $message->id) }}">
{{-- <input type="hidden" name="_token" value="{{ csrf_token() }}">
--}}
{!! method_field('PUT') !!}

{!!  csrf_field() !!}
<label for="nombre">
nombre
<input type="text" name="nombre" value="{{ $message->nombre }}">
{!! $errors->first('nombre','<span  class=error>:message</span>') !!}
</label>
<label for="email">
email
<input type="text" name="email" value="{{ $message->email }}">
{!! $errors->first('email','<span  class=error>:message</span>') !!}
</label>
<label for="mensaje">
mensaje
<textarea name="mensaje">{{$message->mensaje }}</textarea>
{!! $errors->first('mensaje','<span  class=error>:message</span>') !!}
</label>

<input type="submit" value="enviar">

</form>


para eliminar un registro:

Route::delete('mensajes/{id}', ['as'=>'messages.destroy','uses'=>'MessagesController@destroy']);

desde el listado se puede llamar por cada registro asi:

<form style="display:inline" method="POST" action="{{route('messages.destroy',$message->id)}}">
            {!! method_field('DELETE') !!}
            {!!  csrf_field() !!}
<input type="submit" value="eliminar">
           
            </form>

y en controller

 public function destroy($id)
    {
        DB::table('messages')->where('id',$id)->delete();
     return redirect()->route('messages.index');
    }


laravel 5.6 configuracion base de datos migraciones

en config/database.php

'default' => env('DB_CONNECTION', 'mysql'),

quiere decir que busca en el archivo .env la variable DB_CONNECTION
en nuestro caso es igual a mysql...

si no existiera esa variable toma el valor del 2do parametro 'mysql'

en .env debemos definir esa y otras variables

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db_blog
DB_USERNAME=root
DB_PASSWORD=

las migraciones es una suerte de control de versiones de nuestra base de datos,
estas se encuentran en database/migrations

por default Laravel viene con 2 migraciones de users y passwords.


cada migracion tiene 2 funciones up() y down()

veamos la up() de users
 public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }


donde  $table->rememberToken()
es lo mismo que escribir (ver metodo en Blueprint)

$this->string('remember_token', 100)->nullable();

y donde

 $table->timestamps();

es lo mismo que escribir:

$this->timestamp('created_at', $precision)->nullable();
$this->timestamp('updated_at', $precision)->nullable();

para ejecutar todas estas migraciones desde la consola escribimos:

php artisan migrate

para hacer un rollback (o llamar a las funciones down() de todas las migraciones que se ejecutaron en el ultimo migrate) desde la consola escribimos:

php artisan migrate:rollback

para crear una migration usamos

php artisan make:migration create_messages_table

esto nos creara un archivo con la fecha y hora p.e 2018_03_21_122354_create_messages_table.php
con los metodos vacios, si queremos generar automaticamente un archivo de migration para la creacion de una tabla hacemos

php artisan make:migration create_messages_table --create=messages



ahora si, el archivo creado tiene implementado minimamente la funcion up()

 public function up()
    {
        Schema::create('messages', function (Blueprint $table) {
            $table->increments('id');
            $table->timestamps();
        });
    }


y lo completamos con los datos que queremos

 public function up()
    {
        Schema::create('messages', function (Blueprint $table) {
            $table->increments('id');
            $table->string('nombre');
            $table->string('email');
            $table->text('mensaje');
           
            $table->timestamps();
        });
    }

para ejecutar la migration

php artisan migrate

si queremos agregar un campo nuevo

php artisan make:migration add_telefono_messages_table --table=messages

ahora la funcion up del archivo de migration tiene la sgt forma:

  public function up()
    {
        Schema::table('messages', function (Blueprint $table) {
            //
        });
    }

ahora agregamos el campo nuevo y en la funcion down() la sentencia contraria, osea la eliminacion de ese campo:

public function up()
    {
        Schema::table('messages', function (Blueprint $table) {
            $table->string('telefono')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('messages', function (Blueprint $table) {
            $table->dropColumn('telefono');
        });
    }

tip: para recrear totalmente tu base de datos se usa

php artisan migrate:refresh

para hacer migratios que modifican/eliminan columnas de la tabla debemos instalar antes doctrine/dbal asi:

composer require doctrine/dbal






*******************
https://laravel.com/docs/5.6/migrations
campos disponibles para migrations

CommandDescription
$table->bigIncrements('id');Auto-incrementing UNSIGNED BIGINT (primary key) equivalent column.
$table->bigInteger('votes');BIGINT equivalent column.
$table->binary('data');BLOB equivalent column.
$table->boolean('confirmed');BOOLEAN equivalent column.
$table->char('name', 100);CHAR equivalent column with an optional length.
$table->date('created_at');DATE equivalent column.
$table->dateTime('created_at');DATETIME equivalent column.
$table->dateTimeTz('created_at');DATETIME (with timezone) equivalent column.
$table->decimal('amount', 8, 2);DECIMAL equivalent column with a precision (total digits) and scale (decimal digits).
$table->double('amount', 8, 2);DOUBLE equivalent column with a precision (total digits) and scale (decimal digits).
$table->enum('level', ['easy', 'hard']);ENUM equivalent column.
$table->float('amount', 8, 2);FLOAT equivalent column with a precision (total digits) and scale (decimal digits).
$table->geometry('positions');GEOMETRY equivalent column.
$table->geometryCollection('positions');GEOMETRYCOLLECTION equivalent column.
$table->increments('id');Auto-incrementing UNSIGNED INTEGER (primary key) equivalent column.
$table->integer('votes');INTEGER equivalent column.
$table->ipAddress('visitor');IP address equivalent column.
$table->json('options');JSON equivalent column.
$table->jsonb('options');JSONB equivalent column.
$table->lineString('positions');LINESTRING equivalent column.
$table->longText('description');LONGTEXT equivalent column.
$table->macAddress('device');MAC address equivalent column.
$table->mediumIncrements('id');Auto-incrementing UNSIGNED MEDIUMINT (primary key) equivalent column.
$table->mediumInteger('votes');MEDIUMINT equivalent column.
$table->mediumText('description');MEDIUMTEXT equivalent column.
$table->morphs('taggable');Adds taggable_id UNSIGNED INTEGER and taggable_type VARCHAR equivalent columns.
$table->multiLineString('positions');MULTILINESTRING equivalent column.
$table->multiPoint('positions');MULTIPOINT equivalent column.
$table->multiPolygon('positions');MULTIPOLYGON equivalent column.
$table->nullableMorphs('taggable');Adds nullable versions of morphs()columns.
$table->nullableTimestamps();Alias of timestamps() method.
$table->point('position');POINT equivalent column.
$table->polygon('positions');POLYGON equivalent column.
$table->rememberToken();Adds a nullable remember_tokenVARCHAR(100) equivalent column.
$table->smallIncrements('id');Auto-incrementing UNSIGNED SMALLINT (primary key) equivalent column.
$table->smallInteger('votes');SMALLINT equivalent column.
$table->softDeletes();Adds a nullable deleted_at TIMESTAMP equivalent column for soft deletes.
$table->softDeletesTz();Adds a nullable deleted_at TIMESTAMP (with timezone) equivalent column for soft deletes.
$table->string('name', 100);VARCHAR equivalent column with a optional length.
$table->text('description');TEXT equivalent column.
$table->time('sunrise');TIME equivalent column.
$table->timeTz('sunrise');TIME (with timezone) equivalent column.
$table->timestamp('added_on');TIMESTAMP equivalent column.
$table->timestampTz('added_on');TIMESTAMP (with timezone) equivalent column.
$table->timestamps();Adds nullable created_at and updated_atTIMESTAMP equivalent columns.
$table->timestampsTz();Adds nullable created_at and updated_atTIMESTAMP (with timezone) equivalent columns.
$table->tinyIncrements('id');Auto-incrementing UNSIGNED TINYINT (primary key) equivalent column.
$table->tinyInteger('votes');TINYINT equivalent column.
$table->unsignedBigInteger('votes');UNSIGNED BIGINT equivalent column.
$table->unsignedDecimal('amount', 8, 2);UNSIGNED DECIMAL equivalent column with a precision (total digits) and scale (decimal digits).
$table->unsignedInteger('votes');UNSIGNED INTEGER equivalent column.
$table->unsignedMediumInteger('votes');UNSIGNED MEDIUMINT equivalent column.
$table->unsignedSmallInteger('votes');UNSIGNED SMALLINT equivalent column.
$table->unsignedTinyInteger('votes');UNSIGNED TINYINT equivalent column.
$table->uuid('id');UUID equivalent column.
$table->year('birth_year');YEAR equivalent column.


linux ubuntu mint actualizar chrome

 desde una terminal: $ sudo apt update $ sudo apt install google-chrome-stable