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.
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
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
ejecutar por consola
composer dumpautoload
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
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;
}
}
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);
}
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']);
}
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;
}
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:
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 [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
para forzar la eliminacion
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
'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
Command | Description |
---|---|
$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_token VARCHAR(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_at TIMESTAMP equivalent columns. |
$table->timestampsTz(); | Adds nullable created_at and updated_at TIMESTAMP (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. |
Suscribirse a:
Entradas (Atom)
linux ubuntu mint actualizar chrome
desde una terminal: $ sudo apt update $ sudo apt install google-chrome-stable
-
por consola y desde la raiz de tu proyecto php artisan --version
-
en nuestro proyecto creamos una carpeta llamada donde estaran todas nuestras clases, por ejemplo una llamada: MiApp adentro de esta irian b...
-
Integridad al nivel de la base de datos Oracle Oracle valida la integridad de la base de datos y presenta los siguientes mensajes de erro...