Mostrando entradas con la etiqueta laravel. Mostrar todas las entradas
Mostrando entradas con la etiqueta laravel. Mostrar todas las entradas

martes, 15 de diciembre de 2015

25 - Tutorial de Laravel 5 - OAuth2 Socialite (Registrar y autenticar al usuario)




En este capítulo del Tutorial de Laravel 5 continuamos dándole forma a la autenticación y registro de usuarios a través de proveedores como Facebook y Google, este capítulo es la continuación del anterior.

Para empezar realizamos una modificación en la tabla "users" agregándole una nueva columna llamada "social" del tipo BOOLEAN y con valor por defecto 0 (false). Esta columna nos permitirá determinar saber si el usuario autenticado es un usuario registrado de forma normal o a través de un proveedor de servicios. También editaremos la columna "password" de la tabla "users" permitiendo valores nulos.

Crearemos una nueva tabla con artisan llamada "user_social_accounts" en la cual guardaremos información extra de los usuarios, tales como el id de registro del usuario de la tabla "users", el proveedor y el id del proveedor.

Abrir una consola, ir a la raiz del proyecto Laravel y ejecutar el siguiente comando para crear la clase ...

php artisan make:migration user_social_accounts --create=user_social_accounts


En la carpeta "database\migrations" se ha generado un nuevo archivo "xxx_user_social_accounts.php", abrirlo y agregar el método up() el siguiente código ...

        Schema::create('user_social_accounts', function (Blueprint $table) {
            $table->increments('id');
	    $table->integer('user_id');
	    $table->string('provider');
	    $table->string('uid_provider');
        });


Guardar el archivo, regresar a la consola y realizar la migración con el siguiente comando ...

php artisan migrate


A continuación crearemos un modelo que nos permita utilizar eloquent para esta nueva tabla, en la carpeta "app" crearemos un nuevo archivo llamado "Social.php" y le agregaremos el siguiente código ...

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Social extends Model
{
    protected $table = 'user_social_accounts';
    public $timestamps = false;
}


A continuación nos dirigimos al controlador que creamos en el capítulo anterior SocialController para realizar las modificaciones necesarias para la acción que recibe la respuesta del proveedor con la información del usuario, primero agregamos el nuevo modelo: 

use App\Social;

Y luego modificamos la acción getSocialAuthCallback ...

  public function getSocialAuthCallback($provider=null)
       {
          if($user = Socialite::driver($provider)->user()){
			  
             if ($the_user = User::select()->where('email', '=', $user->email)->first())
			 {
				 Auth::login($the_user);
			 }	else{
				 $new_user = new User;
				 $new_user->name = $user->name;
				 $new_user->email = $user->email;
				 $new_user->perfiles = $user->avatar;
				 $new_user->active = 1;
				 $new_user->social = 1;
				 $new_user->save();
				 Auth::login($new_user);
				 
				 //Registrar Información extra
				 $social = new Social;
				 $social->user_id = $new_user->id;
				 $social->provider = $provider;
				 $social->uid_provider = $user->id;
				 $social->save();
			 }
			 return redirect('home');
          }else{
             return '¡¡¡Algo fue mal!!!';
          }
       }


En esta acción comprobamos primeramente si hemos podido obtener información del usuario, si es así, comprobamos si se encuentra registrado en la tabla "users" a través de su email, de ser así, autenticamos el usuario, de lo contrario, si el usuario no se encuentra registrado, lo registramos y lo autenticamos y guardamos la información extra del usuario en la nueva tabla "user_social_accounts".

Ahora realicen la prueba de registrarse en la aplicación a través de Facebook y Google. Otra cosa que se muestra en el vídeo es como establecer a través de una condición si el usuario es registrado normal o a través de un proveedor, el ejemplo se muestra en la vista user.blade.php que muestra el panel de usuario, donde se muestran distintas opciones, entre ellas la posibilidad de cambiar el password, para el caso de los usuarios autenticados a través de un proveedor, esta opción no debe estar disponible, de modo que con una simple condición podemos mostrar o no la opción de cambiar el password ...

	@if(Auth::user()->social == 0)
    <li><a href="{{url('user/password')}}">Cambiar mi password</a></li>
	@endif


Como pueden ver en esta condición entra en juego la columna "social", 0 es para usuarios registrados de forma normal y 1 para usuarios registrados a través de un proveedor.




lunes, 14 de diciembre de 2015

24 - Tutorial de Laravel 5 - OAuth2 Socialite (Facebook & Google)




En este capítulo del Tutorial de Laravel 5 veremos como podemos integrar servicios como Google y Facebook para autenticar usuarios en nuestra aplicación.


Lo primero es crear ambas aplicaciones para obtener las claves de acceso a las apis de Facebook y Google, el proceso de creación de las aplicaciones se muestran al inicio del vídeo.


Seguiremos las instrucciones de la documentación de Laravel para instalar Socialite a través de composer, Socialite nos ofrece soporte para los siguientes proveedores: Facebook, Twitter, LinkedIn, Google, GitHub y Bitbucket.


Abrir una consola, ir a la raíz del proyecto laravel, en el vídeo se utiliza composer.phar para su instalación y ejecutar el siguiente comando ...


php composer.phar require laravel/socialite


Agregar el nuevo proveedor y el alias en el archivo "config\app.php" ...


//Providers
Laravel\Socialite\SocialiteServiceProvider::class,

//Aliases
'Socialite' => Laravel\Socialite\Facades\Socialite::class,


Agregar las credenciales de acceso a los servicios de google y facebook en el archivo "config\service.php" ...


 'facebook' => [
  'client_id' => '',
  'client_secret' => '',
  'redirect' => 'http://localhost/tutorial-laravel/public/social/callback/facebook',
 ],
 
 'google' => [
  'client_id' => '',
  'client_secret' => '',
  'redirect' => 'http://localhost/tutorial-laravel/public/social/callback/google',
 ],


Crear un nuevo controlador llamado "SocialController.php" con el siguiente código ...


<?php 

namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use Auth;
use Socialite;

class SocialController extends Controller {

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

       public function getSocialAuth($provider=null)
       {
           if(!config("services.$provider")) abort('404');

           return Socialite::driver($provider)->redirect();
       }


       public function getSocialAuthCallback($provider=null)
       {
          if($user = Socialite::driver($provider)->user()){
             dd($user);  
          }else{
             return '¡¡¡Algo fue mal!!!';
          }
       }
}


A este controlador sólo tendrán acceso los usuarios invitados, la acción getSocialAuth es la encargada de realizar la petición al proveedor y la acción getSocialAuthCallback es la encargada de obtener la respuesta con los datos del usuario.


Agregaremos las nuevas rutas en routes.php ...


//Social Login
Route::get('social/{provider?}', 'SocialController@getSocialAuth');
Route::get('social/callback/{provider?}', 'SocialController@getSocialAuthCallback');


El argumento provider es opcional y tendrá como valor el nombre del proveedor a acceder, en nuestro caso, Google ó Facebook.


En el vídeo se comenta la posibilidad de obtener un error en Windows al obtener la respuesta de los proveedores "cURL error 60: SSL certificate problem: unable to get local issuer certificate (see http://curl.haxx.se/libcurl/c/libcurl-errors.html ...", para solventar este error descargaremos el siguiente certificado ... cacert.pem, lo guardaremos en la carpeta "xampp", abriremos la carpeta php y abriremos el archivo "php.ini" para agregar la siguiente línea al final ...

curl.cainfo = "C:\xampp\cacert.pem"

Guardar el archivo y reiniciar nuevamente apache.


Para ver la prueba agregaremos dos links a la vista "auth\login.blade.php" para acceder a los proveedores ...


 ...
 <br />
 <a href='{{url("social/facebook")}}'>Iniciar sesión con Facebook</a>
 <br />
 <a href='{{url("social/google")}}'>Iniciar sesión con Google</a>


Ahora prueben a iniciar sesión con Facebook ó Google para ver como los proveedores te solitican la primera vez que permitas a la aplicación tener información tuya y como posteriormente te redirecciona mostrando la información de usuario.





lunes, 7 de diciembre de 2015

23 - Tutorial de Laravel 5 - Admin Panel (Panel de Administrador)




En este capítulo del Tutorial de Laravel 5 veremos un supuesto en el cual tenemos que crear un Panel de Administrador. La condición de administrador o no, la realizaremos desde la tabla users, para esta tarea crearemos una nueva columna llamada "user" del tipo integer y con un valor por defecto 0, el valor de esta columna nos determinará el tipo de usuario del que se trata, 0 para usuario normal y 1 para usuario administrador.


Empezaremos con el uso de artisan para realizar la migración, primero generaremos la clase, abrir una consola, dirigirnos a la raiz de nuestro proyecto e introducir el siguiente comando ...


php artisan make:migration add_user_to_users


Una vez se ha generado el archivo, nos dirigimos a "database\migrations" y abrimos el archivo xxx_add_user_to_users.php e incluimos el siguiente código dentro del método up() para crear la nueva columna ...


        Schema::table('users', function($table){
            $table->integer('user')->default(0);
        });


A continuación regresamos a la consola y realizamos la migración ...


php artisan migrate


Ok, ya tenemos la nueva columna "user" en la tabla "users".


Para el acceso al panel de administrador crearemos un nuevo controlador "AdminController", el controlador lo crearemos con artisan, desde la consola ...


php artisan make:controller AdminController


Nos dirigimos al nuevo controlador que se encuentra en "app\Http\Controllers" y dejamos la clase vacía, es decir, quitamos todos los métodos que se incluyen por defecto e importamos las siguientes clases ...


use App\User;
use Validator;
use Auth;


A continuación crearemos una acción-ruta "createAdmin" que permitirá al propietario de la aplicación crear un administrador o administradores, esta acción-ruta ha de ser usada y posteriormente comentada para evitar el acceso a cualquier usuario ...


Agregar el código de la acción "createAdmin" al controlador AdminController ...


public function createAdmin(Request $request){
  
  if ($request->isMethod('post'))
  {
   //Roles de validación
   $rules = [
    'name' => 'required|min:3|max:16|regex:/^[a-záéíóúàèìòùäëïöüñ\s]+$/i',
    'email' => 'required|email|max:255|unique:users,email',
    'password' => 'required|min:6|max:18|confirmed',
   ];
   
   //Posibles mensajes de error de validación
   $messages = [
    'name.required' => 'El campo es requerido',
    'name.min' => 'El mínimo de caracteres permitidos son 3',
    'name.max' => 'El máximo de caracteres permitidos son 16',
    'name.regex' => 'Sólo se aceptan letras',
    'email.required' => 'El campo es requerido',
    'email.email' => 'El formato de email es incorrecto',
    'email.max' => 'El máximo de caracteres permitidos son 255',
    'email.unique' => 'El email ya existe',
    'password.required' => 'El campo es requerido',
    'password.min' => 'El mínimo de caracteres permitidos son 6',
    'password.max' => 'El máximo de caracteres permitidos son 18',
    'password.confirmed' => 'Los passwords no coinciden',
   ];
   
   $validator = Validator::make($request->all(), $rules, $messages);
   
   //Si la validación no es correcta redireccionar al formulario con los errores
   if ($validator->fails()){
    return redirect()->back()->withErrors($validator);
   }
   else{ // De los contrario guardar al usuario
    $user = new User;
    $user->name = $request->name;
    $user->email = $request->email;
    $user->password = bcrypt($request->password);
    $user->remember_token = str_random(100);
    $user->confirm_token = str_random(100);
    //Activar al administrador sin necesidad de enviar correo electrónico
    $user->active = 1;
    //El valor 1 en la columna determina si el usuario es administrador o no
    $user->user = 1;
    
    if ($user->save()){
     return redirect()->back()->with('message', 'Enhorabuena nuevo administrador creado correctamente');
    } else{
     return redirect()->back()->with('error', 'Ha ocurrido un error al guardar los datos');
    }
   }
  }
  
  return View('admin.createadmin');
 }


Esta acción estará disponible tanto para los métodos get y post, get para mostrar la vista "createadmin" que contiene el formulario de registro de administradores y post para recibir los argumentos del formulario. Si el formulario es enviado se valida, si pasa la validación se registra el nuevo usuario activándolo y con permisos de administrador.


A continuación creamos una nueva ruta para asociarla a esta acción en routes.php ...

Route::match(['get', 'post'], 'admin/createadmin', 'AdminController@createAdmin');


Y creamos una nueva carpeta para las vistas del controlador "AdminController", en "resources\views", creamos una carpeta con nombre "admin" y agregamos la vista "createadmin.blade.php" que contiene el formulario de registro de administradores, el código es el siguiente ...

@extends('layouts.home')
@section('content')
<h1>Crear un nuevo administrador</h1>
<div class='bg-danger' style='padding: 20px'>¡¡¡Una vez termines de crear el administrador desactiva esta acción-ruta!!!</div>
<hr />
@if (Session::has('message'))
 <div class='bg-info' style='padding: 20px'>
  {{Session::get('message')}}
 </div>
 <hr />
@endif
@if (Session::has('error'))
 <div class='bg-danger' style='padding: 20px'>
  {{Session::get('error')}}
 </div>
 <hr />
@endif
<form method="POST" action="{{url('admin/createadmin')}}">
    {!! csrf_field() !!}

    <div class='form-group'>
        <label for="name">Nombre:</label>
        <input type="text" name="name" class="form-control" value="{{ old('name') }}" />
        <div class="text-danger">{{$errors->first('name')}}</div>
    </div>

    <div class="form-group">
        <label for="email">Email:</label>
        <input type="email" name="email" class="form-control" value="{{ old('email') }}" />
        <div class="text-danger">{{$errors->first('email')}}</div>
    </div>

    <div class="form-group">
        <label for="password">Password:</label>
        <input type="password" class="form-control" name="password">
        <div class="text-danger">{{$errors->first('password')}}</div>
    </div>

    <div class="form-group">
        <label for="password_confirmation">Confirmar Password:</label>
        <input type="password" class="form-control" name="password_confirmation">
    </div>

    <div>
        <button type="submit" class="btn btn-primary">Crear administrador</button>
    </div>
</form>
<br /><br /><br /><br />
@stop


Como podéis ver el formulario es prácticamente igual al formulario de registro que ya creamos en un capítulo anterior.

Ahora en el navegador, vamos a la nueva ruta "admin/createadmin" para registrar un administrador. Una vez que hemos creado el/los administrador/es es muy importante que comentemos la acción "createAdmin" y la ruta que la conecta.

Ahora incluiremos la lógica al controlador "AdminController", para ello incluiremos el método constructor y haremos uso de middleware para permitir el acceso al mismo sólo a los usuarios autenticados, excepto a la acción createAdmin.

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


A continuación crearemos un método privado que será el encargado de comprobar si el usuario autenticado es administrador o no. Este método luego será utilizado en cada una de las acciones del controlador. Código del método privado isAdmin() ...

    private function isAdmin(){
        if (Auth::user()->user == 1) return true;
        else return false;
    }


El método anterior regresa un valor boolean. Si la columna "user" del usuario autenticado es igual 1 es que es administrador. Para ver la prueba crearemos una nueva acción-ruta llamada "admin" con el siguiente código ...

    public function admin(){
        if ($this->isAdmin()){
            return View('admin.admin');
        } else{
            return redirect()->back();
        }
    }


Si el usuario es administrador mostramos una vista de lo contrario lo expulsamos redireccionándolo de dónde vino.

Esta acción "admin" la conectaremos a una nueva ruta en routes.php ...

Route::get('admin', 'AdminController@admin');


Y crearemos la nueva vista "admin.blade.php" en la carpeta "admin" con el siguiente código ...

@extends('layouts.home')
@section('content')
<h1>Bienvenid@ {{Auth::user()->name}} a su Panel de Administrador</h1>
@stop


Otra cosa que podemos hacer para finalizar es agregar un link al ménu del layout "home.blade.php" que permita al usuario administrador, ir al panel de administrador ...

          <ul class="nav navbar-nav navbar-right">
   @if (Auth::check())
                        @if (Auth::user()->user == 1)
   <li><a href="{{url('admin')}}">Panel de Administrador</a></li>
                        @endif
   <li><a href="{{url('user')}}">{{Auth::user()->name}}</a></li>
   <li><a href="{{url('auth/logout')}}">Salir</a></li>
   @else
            <li><a href="{{url('auth/login')}}">Iniciar sesión</a></li>
   @endif
          </ul>


Ahora prueben a iniciar sesión como usuarios normales y como administradores. 







viernes, 4 de diciembre de 2015

22 - Tutorial de Laravel 5 - Download Files (Descargar archivos del servidor)




En este capítulo del Tutorial de Laravel 5 veremos un nuevo supuesto, en el cual nos solicitan incluir una opción en el Panel de Usuario para descargar un archivo pdf con los "términos y condiciones de uso del portal". La descarga de archivos sólo estará permitida a los usuarios autenticados.

Lo primero que haremos es agregar esta nueva opción a la vista "user.blade.php" ...

<li><a href="{{url('user/download')}}">Descargar términos y condiciones de uso</a></li>


A continuación crearemos la carpeta donde se incluirán los archivos descargables, si creamos esta carpeta en la carpeta "public" cometemos el error de que estará disponible a cualquier usuario, así que la crearemos en la carpeta "app" con el nombre "files" y le agregaremos un archivo pdf con el nombre "terminos.pdf".

A continuación agregaremos la ruta de descarga en routes.php, lógicamente es la misma que estamos indicando en el link de la opción ...

Route::get('user/download', 'UserController@download');


Esta ruta está conectada al controlador "UserController" y a una acción llamada "download", recuerden que sólo los usuarios autenticados pueden tener acceso a las acciones de este controlador.

Para la reutilización de código crearemos un nuevo método protegido llamado downloadFile, sólo accesible desde la clase y clases heredadas, este método lo podremos migrar a otra clase en caso de ser necesario. A este método tenemos que pasar un argumento, el cual es la ruta del archivo, este método regresa un valor boolean, si el archivo existe se procede a su descarga y retorna true, de lo contrario false. En el controlador UserController agregaremos el método ...

    protected function downloadFile($src){
        if(is_file($src)){
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
            $content_type = finfo_file($finfo, $src);
            finfo_close($finfo);
            $file_name = basename($src).PHP_EOL;
            $size = filesize($src);
            header("Content-Type: $content_type");
            header("Content-Disposition: attachment; filename=$file_name");
            header("Content-Transfer-Encoding: binary");
            header("Content-Length: $size");
            readfile($src);
            return true;
        } else{
            return false;
        }
    }


También en el controlador UserController agregaremos la acción "download", en esta acción haremos uso del método downloadFile comprobando si la descarga se ha realizado con éxito o no, si no es así, redireccionamos atrás nuevamente ...

    public function download(){
        if(!$this->downloadFile(app_path()."/files/terminos.pdf")){
            return redirect()->back();
        }
    }


Finalmente probaremos en el Panel de Control de usuario esta nueva opción.






jueves, 3 de diciembre de 2015

21 - Tutorial de Laravel 5 - Public Profile (Perfil público de usuario)




En este capítulo del Tutorial de Laravel 5 veremos un supuesto en el cual tenemos que crear un perfil público de usuario, a partir, de la aplicación desarrollada hasta el momento.

Lo primero será crear una nueva ruta en la cual se muestre el perfil, esta ruta se la agregaremos a los nombres de usuario que aparecen en las vistas home.blade.php y search.blade.php.

En home.blade.php estas modificaciones las haremos en la sección para públicar comentarios y en la sección en la que se muestran los comentarios. Código completo de la vista home.blade.php ...

@extends('layouts.home')

@section('content')
<h1>Bienvenid@s a la aplicación Laravel</h1>
<hr />
@if (Session::has('status'))
 <div class="bg-success" style="padding: 20px;">
  {{Session::get('status')}}
 </div>
 <hr />
@endif
@if (Session::has('error'))
 <div class="bg-danger" style="padding: 20px;">
  {{Session::get('error')}}
 </div>
 <hr />
@endif
@if (Auth::check())
 <form method="post" action="{{url('user/createcomment')}}">
  {{csrf_field()}}
  <div class="form-group">
   <div class="row">
    <div class="col-md-1">
     <img src="{{url(Auth::user()->perfiles)}}" class='img-responsive' style='max-width: 60px' />
                                        <strong><a href="{{url('home/user/'.Auth::user()->id)}}">{{Auth::user()->name}}</a></strong>
    </div>
    <div class="col-md-6">
     <textarea name="comment" class="form-control"></textarea>
     <br />
     <button type="submit" class="btn btn-primary">Publicar</button>
    </div>
   </div>
  </div>
 </form>
 <hr />
        <?php 
        $comments = App\Comments::select()->orderBy('id', 'desc')->simplePaginate(5);
        $modal = 0;
        foreach($comments as $comment):
            $user = App\User::select()->where('id', '=', $comment->id_user)->first();
        ?>
        <div class="row">
            <div class="col-md-1">
                <img src='{{url($user->perfiles)}}' class='img-responsive' style='max-width: 60px' />
                <strong><a href="{{url('home/user/'.$user->id)}}">{{$user->name}}</a></strong>
            </div>
            <div class='col-md-6'>
               {{$comment->comment}} 
               <br />
               <i>Fecha: {{$comment->date}} · Hora: {{$comment->time}}</i>
               
               
               
               @if($comment->id_user == Auth::user()->id)
               <hr />
                <!-- Botón que abre la ventana modal eliminar -->
                <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteComment{{$modal}}">
                  Eliminar
                </button>

                <!-- Ventana modal para eliminar -->
                <div class="modal fade" id="deleteComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">¿Realmente quieres eliminar este comentario?</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/deletecomment')}}">
                            {{csrf_field()}}
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-danger">Eliminar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>

                <!-- Botón para abrir la ventana modal de editar -->
                <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#editComment{{$modal}}">
                  Editar
                </button>

                <!-- Ventana modal editar -->
                <div class="modal fade" id="editComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">Editar comentario</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/editcomment')}}">
                            {{csrf_field()}}
                            <div class="form-group">
                            <textarea name="comment" rows="10" class="form-control">{{$comment->comment}}</textarea>
                            </div>
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-primary">Editar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>
                <?php $modal++ ?>
               @endif
            </div>
        </div>
        <hr />
        <?php endforeach ?>
        <div class='text-center'>
        <?php /*Nuevo*/ $comments->setPath('') ?>
        <?php echo $comments->render() ?>
           <p>Página {{$comments->currentPage()}}</p>
        </div>
        <br /><br /><br /><br />
@else
 <hr />
 <p class="bg-info" style="padding: 20px;">Para poder publicar comentarios tienes que <a href="{{url('auth/login')}}">iniciar sesión</a></div>
 <hr />
@endif
@stop


En la vista search.blade.php esta modificación será realizada sólo en la sección donde se muestran los comentarios:

@extends('layouts.home')
@section('search', $search)
@section('content')
<h3>Resultado de la búsqueda: {{$search}}</h3>
@if (isset($message))
<div class='bg-warning' style='padding: 20px'>
    {{$message}}
</div>
@endif
<hr />
@if (isset($comments))
<?php 
        $modal = 0;
        foreach($comments as $comment):
            $user = App\User::select()->where('id', '=', $comment->id_user)->first();
        ?>
        <div class="row">
            <div class="col-md-1">
                <img src='{{url($user->perfiles)}}' class='img-responsive' style='max-width: 60px' />
                <strong><a href="{{url('home/user/'.$user->id)}}">{{$user->name}}</a></strong>
            </div>
            <div class='col-md-6'>
               {{$comment->comment}} 
               <br />
               <i>Fecha: {{$comment->date}} · Hora: {{$comment->time}}</i>
               
               
               @if(isset(Auth::user()->id))
               @if($comment->id_user == Auth::user()->id)
               <hr />
                <!-- Botón que abre la ventana modal eliminar -->
                <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteComment{{$modal}}">
                  Eliminar
                </button>

                <!-- Ventana modal para eliminar -->
                <div class="modal fade" id="deleteComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">¿Realmente quieres eliminar este comentario?</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/deletecomment')}}">
                            {{csrf_field()}}
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-danger">Eliminar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>

                <!-- Botón para abrir la ventana modal de editar -->
                <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#editComment{{$modal}}">
                  Editar
                </button>

                <!-- Ventana modal editar -->
                <div class="modal fade" id="editComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">Editar comentario</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/editcomment')}}">
                            {{csrf_field()}}
                            <div class="form-group">
                            <textarea name="comment" rows="10" class="form-control">{{$comment->comment}}</textarea>
                            </div>
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-primary">Editar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>
                <?php $modal++ ?>
               @endif
      @endif
            </div>
        </div>
        <hr />
        <?php endforeach ?>
        <?php
        $currentPage = $comments->currentPage(); //Página actual
        $maxPages = $currentPage + 3; //Máxima numeración de páginas
        $firstPage = 1; //primera página
        $lastPage = $comments->lastPage(); //última página
        $nextPage = $currentPage+1; //Siguiente página
        $forwardPage = $currentPage-1; //Página anterior
        $comments->setPath('');
        ?>
<ul class="pagination">
        <!-- Botón para navegar a la primera página -->
        <li class="@if($currentPage==$firstPage){{'disabled'}}@endif">
                <a href="@if($currentPage>1){{$comments->url($firstPage)}}@else{{'#'}}@endif" class='btn'>Primera</a>
        </li>
        <!-- Botón para navegar a la página anterior -->
        <li class="@if($currentPage==$firstPage){{'disabled'}}@endif">
                <a href="@if($currentPage>1){{$comments->url($forwardPage)}}@else{{'#'}}@endif" class='btn'>«</a>
        </li>
        <!-- Mostrar la numeración de páginas, partiendo de la página actual hasta el máximo definido en $maxPages -->
        @for($x=$currentPage;$x<$maxPages;$x++)
                @if($x <= $lastPage)
                <li class="@if($x==$currentPage){{'active'}}@endif">
                        <a href="{{$comments->url($x)}}" class='btn'>{{$x}}</a>
                </li>
                @endif
        @endfor
        <!-- Botón para navegar a la pagina siguiente -->
        <li class="@if($currentPage==$lastPage){{'disabled'}}@endif">
                <a href="@if($currentPage<$lastPage){{$comments->url($nextPage)}}@else{{'#'}}@endif" class='btn'>»</a>
        </li>
        <!-- Botón para navegar a la última página -->
        <li class="@if($currentPage==$lastPage){{'disabled'}}@endif">
                <a href="@if($currentPage<$lastPage){{$comments->url($lastPage)}}@else{{'#'}}@endif" class='btn'>Última</a>
        </li>
</ul>
@endif
@stop


A continuación crearemos la nueva ruta en routes.php, en esta ruta capturaremos el id del usuario, el id es validado para aceptar sólo números enteros:

Route::get("home/user/{id}", "HomeController@user")->where(['id' => '[0-9]+']);


A continuación crearemos la nueva acción "user" en HomeController, pero antes importaremos la clase user al controlador: use App\User;, en la nueva acción realizaremos una consulta buscando al usuario a través del id enviado, si el usuario no existe redireccionamos atrás, de lo contrario mostramos una nueva vista "user" y le pasamos la información del usuario.

    public function user($id){
        $user = User::select()
                ->where('id', '=', $id)
                ->first();
        if (count($user) == 0){
            return redirect()->back();
        }
        else{
            return View('home.user')->with('user', $user);
        }
    }


A continuación crearemos la nueva vista "user.blade.php" en la carpeta "home" con el siguiente código:

@extends('layouts.home')
@section('content')
<h1>Perfil público de <a href="{{url('home/user/'.$user->id)}}">{{$user->name}}</a></h1>
<img src="{{url($user->perfiles)}}" class="img-responsive" style="max-width: 150px" />
<hr />
@if(Session::has('status'))
 <div class="bg-info" style="padding: 20px">{{Session::get('status')}}</div>
 <hr />
@endif
@if(Session::has('error'))
 <div class="bg-danger" style="padding: 20px">{{Session::get('error')}}</div>
 <hr />
@endif
<!-- Si el usuario está autenticado -->
@if (Auth::check())
 <!-- Y este es su id de perfil posibilitar la creación de comentarios -->
 @if($user->id == Auth::user()->id)
 <form method="post" action="{{url('user/createcomment')}}">
  {{csrf_field()}}
  <div class="form-group">
   <div class="row">
    <div class="col-md-1">
     <img src="{{url(Auth::user()->perfiles)}}" class='img-responsive' style='max-width: 60px' />
     <strong><a href="{{url('home/user/'.Auth::user()->id)}}">{{Auth::user()->name}}</a></strong>
    </div>
    <div class="col-md-6">
     <textarea name="comment" class="form-control"></textarea>
     <br />
     <button type="submit" class="btn btn-primary">Publicar</button>
    </div>
   </div>
  </div>
 </form>
 <hr />
 @endif
@endif
 <!-- Seleccionar los comentarios del usuario -->
 <?php 
  $modal = 0;
  $comments = App\Comments::where('id_user', '=', $user->id)->orderBy('id', 'desc')->simplePaginate(5);
  foreach($comments as $comment):
 ?>
  <div class="row">
            <div class="col-md-1">
                <img src='{{url($user->perfiles)}}' class='img-responsive' style='max-width: 60px' />
                <strong><a href="{{url('home/user/'.$user->id)}}">{{$user->name}}</a></strong>
            </div>
            <div class='col-md-6'>
               {{$comment->comment}} 
               <br />
               <i>Fecha: {{$comment->date}} · Hora: {{$comment->time}}</i>
      
      <!-- Si el usuario está autenticado, es decir, la propiedad id existe -->
      @if(isset(Auth::user()->id))
      <!-- Si el usuario está autenticado agregar las opciones editar y eliminar cuando visite en su perfil -->
               @if($comment->id_user == Auth::user()->id)
               <hr />
                <!-- Botón que abre la ventana modal eliminar -->
                <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteComment{{$modal}}">
                  Eliminar
                </button>

                <!-- Ventana modal para eliminar -->
                <div class="modal fade" id="deleteComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">¿Realmente quieres eliminar este comentario?</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/deletecomment')}}">
                            {{csrf_field()}}
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-danger">Eliminar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>

                <!-- Botón para abrir la ventana modal de editar -->
                <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#editComment{{$modal}}">
                  Editar
                </button>

                <!-- Ventana modal editar -->
                <div class="modal fade" id="editComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">Editar comentario</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/editcomment')}}">
                            {{csrf_field()}}
                            <div class="form-group">
                            <textarea name="comment" rows="10" class="form-control">{{$comment->comment}}</textarea>
                            </div>
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-primary">Editar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>
                <?php $modal++ ?>
               @endif
      @endif
   </div>
  </div>
  <hr />
 <?php endforeach ?>
 
 <!-- Agregar la paginación simple -->
 <div class='text-center'>
 <?php /*Nuevo*/ $comments->setPath('') ?>
 <?php echo $comments->render() ?>
    <p>Página {{$comments->currentPage()}}</p>
 </div>
 <br /><br /><br /><br />

@stop



En el perfil público de usuario se realizan distintas comprobaciones, una de ellas es verificar si el perfil pertenece al usuario actualmente autenticado, de ser así, se le incluye el formulario para crear comentarios y a la lista de comentarios las opciones de editar y eliminar.

Otra cosa, es el manejo de las variables flash 'status' y 'error' al inicio de la vista, esto permitirá que si el usuario realiza alguna acción como crear, editar o eliminar se le muestra esa información. Para que esto ocurra habrá que realizar unas pequeñas modificaciones en las acciones createComment, deleteComment y editComment del controlador UserController, modificando las redirecciones, en lugar de redireccionar a "home", redireccionar atrás con el método "back()", simplemente tenemos que reemplazar:

return redirect('home')->...


Por ...

return redirect()->back()->...


Otra cosa es mostrar la opción de ir al perfil público en el panel del usuario, abrir la vista "user.blade.php" de la carpeta "user" e incluirla ...

    <li><a href="{{url('home/user/'.Auth::user()->id)}}">Ir a mi perfil público</a></li>





miércoles, 2 de diciembre de 2015

20 - Tutorial de Laravel 5 - Pagination (Paginación personalizada)




En esta parte del Tutorial de Laravel 5 continuamos viendo la paginación, concretamente utilizaremos los helpers para crear una paginación personalizada.

Esta paginación tendrá el siguiente formato:



Previamente incluiremos el método setPath a la paginación con la cual trabajamos en el capítulo anterior, este método nos permitirá generar las rutas para los links correctamente. Código modificado en la vista "home" ...

<div class='text-center'>
<?php /*Nuevo*/ $comments->setPath('') ?>
<?php echo $comments->render() ?>
   <p>Página {{$comments->currentPage()}}</p>
</div>
<br /><br /><br /><br />


Empezamos a crear la paginación personalizada. En la acción search del controlador HomeController reemplazamos el método get de la consulta por el método paginate:

$comments = Comments::select()
  ->where('comment', 'LIKE', '%'.$search.'%')
  ->orderBy('id', 'desc')
  ->paginate(3);


En la vista "search" utilizamos los helpers para crear una serie de variables, que posteriormente nos serviran para crear los links de la paginación, código completo de la vista "search" ...

@extends('layouts.home')
@section('search', $search)
@section('content')
<h3>Resultado de la búsqueda: {{$search}}</h3>
@if (isset($message))
<div class='bg-warning' style='padding: 20px'>
    {{$message}}
</div>
@endif
<hr />
@if (isset($comments))
<?php 
        $modal = 0;
        foreach($comments as $comment):
            $user = App\User::select()->where('id', '=', $comment->id_user)->first();
        ?>
        <div class="row">
            <div class="col-md-1">
                <img src='{{url($user->perfiles)}}' class='img-responsive' style='max-width: 60px' />
                <strong>{{$user->name}}</strong>
            </div>
            <div class='col-md-6'>
               {{$comment->comment}} 
               <br />
               <i>Fecha: {{$comment->date}} · Hora: {{$comment->time}}</i>
               
               
               @if(isset(Auth::user()->id))
               @if($comment->id_user == Auth::user()->id)
               <hr />
                <!-- Botón que abre la ventana modal eliminar -->
                <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteComment{{$modal}}">
                  Eliminar
                </button>

                <!-- Ventana modal para eliminar -->
                <div class="modal fade" id="deleteComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">¿Realmente quieres eliminar este comentario?</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/deletecomment')}}">
                            {{csrf_field()}}
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-danger">Eliminar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>

                <!-- Botón para abrir la ventana modal de editar -->
                <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#editComment{{$modal}}">
                  Editar
                </button>

                <!-- Ventana modal editar -->
                <div class="modal fade" id="editComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">Editar comentario</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/editcomment')}}">
                            {{csrf_field()}}
                            <div class="form-group">
                            <textarea name="comment" rows="10" class="form-control">{{$comment->comment}}</textarea>
                            </div>
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-primary">Editar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>
                <?php $modal++ ?>
               @endif
      @endif
            </div>
        </div>
        <hr />
        <?php endforeach ?>
        <?php
        $currentPage = $comments->currentPage(); //Página actual
        $maxPages = $currentPage + 3; //Máxima numeración de páginas
        $firstPage = 1; //primera página
        $lastPage = $comments->lastPage(); //última página
        $nextPage = $currentPage+1; //Siguiente página
        $forwardPage = $currentPage-1; //Página anterior
        $comments->setPath('');
        ?>
<ul class="pagination">
        <!-- Botón para navegar a la primera página -->
        <li class="@if($currentPage==$firstPage){{'disabled'}}@endif">
                <a href="@if($currentPage>1){{$comments->url($firstPage)}}@else{{'#'}}@endif" class='btn'>Primera</a>
        </li>
        <!-- Botón para navegar a la página anterior -->
        <li class="@if($currentPage==$firstPage){{'disabled'}}@endif">
                <a href="@if($currentPage>1){{$comments->url($forwardPage)}}@else{{'#'}}@endif" class='btn'>«</a>
        </li>
        <!-- Mostrar la numeración de páginas, partiendo de la página actual hasta el máximo definido en $maxPages -->
        @for($x=$currentPage;$x<$maxPages;$x++)
                @if($x <= $lastPage)
                <li class="@if($x==$currentPage){{'active'}}@endif">
                        <a href="{{$comments->url($x)}}" class='btn'>{{$x}}</a>
                </li>
                @endif
        @endfor
        <!-- Botón para navegar a la pagina siguiente -->
        <li class="@if($currentPage==$lastPage){{'disabled'}}@endif">
                <a href="@if($currentPage<$lastPage){{$comments->url($nextPage)}}@else{{'#'}}@endif" class='btn'>»</a>
        </li>
        <!-- Botón para navegar a la última página -->
        <li class="@if($currentPage==$lastPage){{'disabled'}}@endif">
                <a href="@if($currentPage<$lastPage){{$comments->url($lastPage)}}@else{{'#'}}@endif" class='btn'>Última</a>
        </li>
</ul>
@endif
@stop


Ahora prueben la páginación al realizar búsquedas.





19 - Tutorial de Laravel 5 - paginate y simplePaginate (Paginación de resultados)




En este capítulo del Tutorial de Laravel 5 veremos como incluir una paginación de resultados haciendo uso de los métodos paginate y simplePaginate que nos ofrece laravel por defecto.

En el vídeo se hace una mención respecto al formulario de búsqueda del capítulo anterior para mostrar el valor de la búsqueda en el campo de texto. Esta modificación es realizada en el layout "home" ...


<input type="text" class="form-control" name='search' placeholder="Buscar ..." value='@yield("search")' />


Y en la vista "search", es decir, donde se muestran los resultados de la búsqueda, damos valor a la variable "search" creada con @yield ...

@section('search', $search)


La paginación de resultados será mostrada en la página de inicio "home", en la cual estamos mostrando los comentarios realizados por los usuarios autenticados. Más información en la documentación oficial de Laravel.

Primero veremos un ejemplo con el método "paginate", para ello simplemente modificar en la vista "home" lo siguiente ...

$comments = App\Comments::select()->orderBy('id', 'desc')->get();


Por esto otro ...

$comments = App\Comments::select()->orderBy('id', 'desc')->paginate(5);


Como podéis ver sólo hemos modificado el método get por paginate(número de registros por página).

Y a continuación, justo después de donde se cierra el búcle foreach para extraer comentario a comentario, incluimos los links de páginación ...

        <div class='text-center'>
        <?php echo $comments->render() ?>
           <p>Página {{$comments->currentPage()}} de {{$comments->lastPage()}}</p>
        </div>
        <br /><br /><br /><br />


Con el método render() mostramos los links y los métodos currentPage() y lastPage() forman parte de una serie de Helpers que nos proporciona laravel para obtener información de la paginación.

La otra demostración que se ve en el vídeo es el uso del método simplePaginate, esta paginación no muestra la numeración de las páginas y sólo muestra los botones para avanzar y retroceder.

Para ver este ejemplo seguiremos el mismo procedimiento que antes, cambiar el método paginate por simplePaginate y donde mostramos los links quitamos el helper lastPage, ya que este helper no esta disponible para simplePaginate.





martes, 1 de diciembre de 2015

18 - Tutorial de Laravel 5 - Search Form (Formulario de búsqueda)




En esta parte del Tutorial de Laravel 5 integraremos un formulario de búsqueda al menú para poder realizar búsquedas entre los comentarios. Las búsquedas podrán ser realizadas por los usuarios autenticados e invitados, si en los resultados de búsqueda de un usuario autenticado aparece algún comentario suyo, entonces, le agregaremos las opciones de editar y eliminar.

El formulario lo integraremos al menú del layout "home.blade.php" ...

<form class="navbar-form navbar-left" role="search" action="{{url('home/searchredirect')}}">
 <div class="form-group">
  <input type="text" class="form-control" name='search' placeholder="Buscar ..." />
 </div>
 <button type="submit" class="btn btn-default">Buscar</button>
</form>


Este formulario será enviado a través del método get. La ruta definida en el action la utilizaremos para manejar el argumento "search" y crear una redirección hacia una ruta amigable.

A continuación crearemos las rutas en routes.php ...

Route::get('home/searchredirect', function(){
     
    /* Nuevo: si el argumento search está vacío regresar a la página anterior */
    if (empty(Input::get('search'))) return redirect()->back();
    
    $search = urlencode(e(Input::get('search')));
    $route = "home/search/$search";
    return redirect($route);
});
Route::get("home/search/{search}", "HomeController@search");


Observen como la primera ruta es la que se encuentra en el formulario de búsqueda, obtiene el argumento get "search" y crea una nueva ruta pasándole el valor del argumento, la ruta amigable está conectada al controlador HomeController y a una nueva acción llamada "search".

Agregaremos al controlador HomeController la siguiente clase para trabajar con la tabla "comments":

use App\Comments;


Código de la acción "search" ...

    public function search($search){
        $search = urldecode($search);
        $comments = Comments::select()
                ->where('comment', 'LIKE', '%'.$search.'%')
                ->orderBy('id', 'desc')
                ->get();
        
        if (count($comments) == 0){
            return View('home.search')
            ->with('message', 'No hay resultados que mostrar')
            ->with('search', $search);
        } else{
            return View('home.search')
            ->with('comments', $comments)
            ->with('search', $search);
        }
    }


Como se puede ver en la acción obtenemos el valor del argumento "search" y guardamos los posibles comentarios en "$comments", la consulta de búsqueda la realizamos a través de la cláusula "LIKE". Si no se encuentran resultados se pasan dos variables a una nueva vista "search", la variable "message" es para mostrar un comentario de que no existen resultados y la variable "search" que guarda el valor de la búsqueda, de lo contrario, se pasan igualmente dos variables a la nueva vista, "comments" que contiene los comentarios y "search" que guarda el valor de la búsqueda.

Finalmente crearemos la vista "search.blade.php" ...

@extends('layouts.home')

@section('content')
<h3>Resultado de la búsqueda: {{$search}}</h3>
@if (isset($message))
<div class='bg-warning' style='padding: 20px'>
    {{$message}}
</div>
@endif
<hr />
@if (isset($comments))
<?php 
        $modal = 0;
        foreach($comments as $comment):
            $user = App\User::select()->where('id', '=', $comment->id_user)->first();
        ?>
        <div class="row">
            <div class="col-md-1">
                <img src='{{url($user->perfiles)}}' class='img-responsive' style='max-width: 60px' />
                <strong>{{$user->name}}</strong>
            </div>
            <div class='col-md-6'>
               {{$comment->comment}} 
               <br />
               <i>Fecha: {{$comment->date}} · Hora: {{$comment->time}}</i>
               
               
               @if(isset(Auth::user()->id))
               @if($comment->id_user == Auth::user()->id)
               <hr />
                <!-- Botón que abre la ventana modal eliminar -->
                <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteComment{{$modal}}">
                  Eliminar
                </button>

                <!-- Ventana modal para eliminar -->
                <div class="modal fade" id="deleteComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">¿Realmente quieres eliminar este comentario?</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/deletecomment')}}">
                            {{csrf_field()}}
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-danger">Eliminar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>

                <!-- Botón para abrir la ventana modal de editar -->
                <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#editComment{{$modal}}">
                  Editar
                </button>

                <!-- Ventana modal editar -->
                <div class="modal fade" id="editComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">Editar comentario</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/editcomment')}}">
                            {{csrf_field()}}
                            <div class="form-group">
                            <textarea name="comment" rows="10" class="form-control">{{$comment->comment}}</textarea>
                            </div>
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-primary">Editar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>
                <?php $modal++ ?>
               @endif
               @endif
            </div>
        </div>
        <hr />
        <?php endforeach ?>
@endif
@stop


Ahora prueben a realizar búsquedas.





lunes, 30 de noviembre de 2015

17 - Tutorial de Laravel 5 - CRUD Update (Sistema de comentarios)




En esta parte del Tutorial de Laravel 5, continuamos con el sistema de comentarios agregando la opción de editarlos. En la vista home se han realizado algunas modificaciones para las opciones "Eliminar" y "Editar", para mejorar la accesibilidad al usuario se han integrado unas ventanas modal (Bootstrap) para cada una de ellas.

El código que interviene en este capítulo es el siguiente:

Se adaptan las opciones "Eliminar" y "Editar" para el uso de ventanas modal, el código completo de la vista "home" es el siguiente:

@extends('layouts.home')

@section('content')
<h1>Bienvenid@s a la aplicación Laravel</h1>
<hr />
@if (Session::has('status'))
	<div class="bg-success" style="padding: 20px;">
		{{Session::get('status')}}
	</div>
	<hr />
@endif
@if (Session::has('error'))
	<div class="bg-danger" style="padding: 20px;">
		{{Session::get('error')}}
	</div>
	<hr />
@endif
@if (Auth::check())
	<form method="post" action="{{url('user/createcomment')}}">
		{{csrf_field()}}
		<div class="form-group">
			<div class="row">
				<div class="col-md-1">
					<img src="{{url(Auth::user()->perfiles)}}" class='img-responsive' style='max-width: 60px' />
					<strong>{{Auth::user()->name}}</strong>
				</div>
				<div class="col-md-6">
					<textarea name="comment" class="form-control"></textarea>
					<br />
					<button type="submit" class="btn btn-primary">Publicar</button>
				</div>
			</div>
		</div>
	</form>
	<hr />
        <?php 
        $comments = App\Comments::select()->orderBy('id', 'desc')->get();
        $modal = 0;
        foreach($comments as $comment):
            $user = App\User::select()->where('id', '=', $comment->id_user)->first();
        ?>
        <div class="row">
            <div class="col-md-1">
                <img src='{{url($user->perfiles)}}' class='img-responsive' style='max-width: 60px' />
                <strong>{{$user->name}}</strong>
            </div>
            <div class='col-md-6'>
               {{$comment->comment}} 
               <br />
               <i>Fecha: {{$comment->date}} · Hora: {{$comment->time}}</i>
               
               
               
               @if($comment->id_user == Auth::user()->id)
               <hr />
                <!-- Botón que abre la ventana modal eliminar -->
                <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteComment{{$modal}}">
                  Eliminar
                </button>

                <!-- Ventana modal para eliminar -->
                <div class="modal fade" id="deleteComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">¿Realmente quieres eliminar este comentario?</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/deletecomment')}}">
                            {{csrf_field()}}
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-danger">Eliminar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>

                <!-- Botón para abrir la ventana modal de editar -->
                <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#editComment{{$modal}}">
                  Editar
                </button>

                <!-- Ventana modal editar -->
                <div class="modal fade" id="editComment{{$modal}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                  <div class="modal-dialog" role="document">
                    <div class="modal-content">
                      <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
                        <h4 class="modal-title" id="myModalLabel">Editar comentario</h4>
                      </div>
                      <div class="modal-body">
                        <form method="post" action="{{url('user/editcomment')}}">
                            {{csrf_field()}}
                            <div class="form-group">
                            <textarea name="comment" rows="10" class="form-control">{{$comment->comment}}</textarea>
                            </div>
                            <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                            <button type="submit" class="btn btn-primary">Editar</button>
                        </form>
                      </div>
                      <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Cerrar</button>
                      </div>
                    </div>
                  </div>
                </div>
                <?php $modal++ ?>
               @endif
            </div>
        </div>
        <hr />
        <?php endforeach ?>
@else
	<hr />
	<p class="bg-info" style="padding: 20px;">Para poder publicar comentarios tienes que <a href="{{url('auth/login')}}">iniciar sesión</a></div>
	<hr />
@endif
@stop


Como se puede ver, en el nuevo formulario para Editar se agregan un textarea (comment) con el contenido actual del comentario y un campo oculto (id_comment) con el id del comentario. A continuación creamos la acción en el controlador UserController, esta acción se llama editComment ...

    public function editComment(Request $request){
        $rules = ['id_comment' => 'integer'];
        $comment = e($request->comment);
        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails()){
            return redirect('home')->with('error', 'Ha ocurrido un error');
        } else{
            if (Comments::where('id', '=', $request->id_comment)
                    ->where('id_user', '=', Auth::user()->id)
                    ->update(['comment' => $comment])){
                return redirect('home')->with('status', 'Enhorabuena comentario editado correctamente');
            }else{
                return redirect('home')->with('error', 'Ha ocurrido un error');
            }
        }
    }


Como se puede en esta acción se valida el campo oculto (id_comment) para aceptar sólo valores del tipo integer, si la validación falla se redirecciona a "home" con un mensaje flash de error, de lo contrario, se realiza una condición, si la actualización se ha llevado a cabo con éxito, se redirecciona con un "status", de lo contrario con un "error".

Otra cosa importante es modificar el modelo "Comments" para agregar una propiedad ($timestamps) con valor false que permita ignorar la columna "update_at", ya que al hacer uso del método "update()", este incluye en la consulta esta columna por defecto. Abrir "Comments.php" que se encuentra en la carpeta "app" y agregar a la clase la siguiente propiedad:

public $timestamps = false;


Por último conectaremos esta acción a una nueva ruta en routes.php ...

Route::post('user/editcomment', 'UserController@editComment');





viernes, 27 de noviembre de 2015

16 - Tutorial de Laravel 5 - CRUD Delete (Sistema de comentarios)




Bienvenid@s, en este capítulo del Tutorial de Laravel 5 continuamos con el sistema CRUD aplicándolo al sistema de comentarios, concretamente agregaremos la opción de eliminar en los comentarios realizados por el usuario.

Si el usuario está autenticado agregaremos un formulario con un campo oculto "id_comment" para que el usuario lo pueda eliminar. Esto lo haremos en la vista "home" que es la cual estamos utilizando como muro para cargar los comentarios, el código completo de la vista "home" es el siguiente:

@extends('layouts.home')

@section('content')
<h1>Bienvenid@s a la aplicación Laravel</h1>
<hr />
@if (Session::has('status'))
 <div class="bg-success" style="padding: 20px;">
  {{Session::get('status')}}
 </div>
 <hr />
@endif
@if (Session::has('error'))
 <div class="bg-danger" style="padding: 20px;">
  {{Session::get('error')}}
 </div>
 <hr />
@endif
@if (Auth::check())
 <form method="post" action="{{url('user/createcomment')}}">
  {{csrf_field()}}
  <div class="form-group">
   <div class="row">
    <div class="col-md-1">
     <img src="{{url(Auth::user()->perfiles)}}" class='img-responsive' style='max-width: 60px' />
     <strong>{{Auth::user()->name}}</strong>
    </div>
    <div class="col-md-6">
     <textarea name="comment" class="form-control"></textarea>
     <br />
     <button type="submit" class="btn btn-primary">Publicar</button>
    </div>
   </div>
  </div>
 </form>
 <hr />
        <?php 
        $comments = App\Comments::select()->orderBy('id', 'desc')->get();
        foreach($comments as $comment):
            $user = App\User::select()->where('id', '=', $comment->id_user)->first();
        ?>
        <div class="row">
            <div class="col-md-1">
                <img src='{{url($user->perfiles)}}' class='img-responsive' style='max-width: 60px' />
                <strong>{{$user->name}}</strong>
            </div>
            <div class='col-md-6'>
               {{$comment->comment}} 
               <br />
               <i>Fecha: {{$comment->date}} · Hora: {{$comment->time}}</i>
               @if($comment->id_user == Auth::user()->id)
               <form method="post" action="{{url('user/deletecomment')}}">
                   {{csrf_field()}}
                   <input type="hidden" name="id_comment" value="{{$comment->id}}" />
                   <button type="submit" class="btn btn-danger">Eliminar</button>
               </form>
               @endif
            </div>
        </div>
        <hr />
        <?php endforeach ?>
@else
 <hr />
 <p class="bg-info" style="padding: 20px;">Para poder publicar comentarios tienes que <a href="{{url('auth/login')}}">iniciar sesión</a></div>
 <hr />
@endif
@stop


A continuación crearemos una nueva acción en UserController que maneje la petición del formulario, código de la acción deleteComment:

    public function deleteComment(Request $request){
        $rules = ['id_comment' => 'integer'];
        $validator = Validator::make($request->only('id_comment'), $rules);
        if ($validator->fails()){
            return redirect('home')->with('error', 'Ha ocurrido un error');
        }
        else
        {
            if(Comments::where('id', '=', $request->id_comment)
                    ->where('id_user', '=', Auth::user()->id)->delete()
                    ){
                return redirect('home')->with('status', 'Enhorabuena comentario eliminado con éxito');
            }
            else{
                return redirect('home')->with('error', 'Ha ocurrido un error');  
            }
        }
    }


En esta acción validamos en input hidden "id_comment" para permitir sólo números enteros, si la validación falla lo redireccionamos a "home" con un mensaje flash "error" (esta es otra de las modificaciones de la vista "home"), si la validación pasa, entonces incluimos una condición, si el registro es eliminado con éxito, redireccionamos a home con un "status", de los contrarios, redireccionamos con un "error".

A continuación en routes.php asociamos la acción a la ruta indicada en el "action" del formulario:

Route::post('user/deletecomment', 'UserController@deleteComment');


Finalmente, prueben a publicar y eliminar comentarios con distintos usuarios. 






jueves, 26 de noviembre de 2015

15 - Tutorial de Laravel 5 - CRUD Create & Read (Sistema de comentarios)




En este capítulo del Tutorial de Laravel 5 crearemos una nueva tabla llamada "comments", sobre esta tabla veremos como realizar diferentes tipos de consultas tales como la creación, lectura, actualización y eliminación de registros.

El ejemplo consiste en permitir a los usuarios autenticados publicar comentarios desde la página de inicio, a modo de mural y mostrar los comentarios publicados en el mismo.

Lo primero que haremos es crear la clase que nos permita realizar la migración a través de artisan, para ello abriremos una consola nos dirigiremos al interior de la raiz de nuestro proyecto Laravel, donde se encuentra el archivo "artisan" y ejecutamos el siguiente comando ...

php artisan make:migration create_comments_table --create=comments


A continuación incluiremos una serie de columnas a la table "comments", así que nos dirigimos a la carpeta "database\migrations" y abrimos el archivo "xxx_create_comments_table.php", código para este archivo:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCommentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('comments', function (Blueprint $table) {
            $table->increments('id');
            $table->text('comment');
            $table->integer('id_user');
            $table->date('date');
            $table->time('time');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('comments');
    }
}



A continuación regresamos a la consola y realizamos la migración de la nueva tabla con el siguiente comando:

php artisan migrate


Ahora podéis revisar en vuestra base de datos para ver que la tabla "comments" ha sido creada con éxito.

A continuación crearemos una clase que nos permita conectar la tabla "comments" al driver eloquent, al igual que ocurre con la clase User, así que nos dirigimos a la carpeta "app" y creamos un nuevos archivo con el siguiente nombre Comments.php y con el siguiente código:

<?php
namespace App;

use Illuminate\Database\Eloquent\Model;

class Comments extends Model
{
    protected $table = 'comments';	
}


Lo siguiente es realizar una serie de modificaciones en la vista "home", el código completo de la vista es el siguiente:

@extends('layouts.home')

@section('content')
<h1>Bienvenid@s a la aplicación Laravel</h1>
<hr />
@if (Session::has('status'))
	<div class="bg-success" style="padding: 20px;">
		{{Session::get('status')}}
	</div>
	<hr />
@endif
@if (Auth::check())
	<form method="post" action="{{url('user/createcomment')}}">
		{{csrf_field()}}
		<div class="form-group">
			<div class="row">
				<div class="col-md-1">
					<img src="{{url(Auth::user()->perfiles)}}" class='img-responsive' style='max-width: 60px' />
					<strong>{{Auth::user()->name}}</strong>
				</div>
				<div class="col-md-6">
					<textarea name="comment" class="form-control"></textarea>
					<br />
					<button type="submit" class="btn btn-primary">Publicar</button>
				</div>
			</div>
		</div>
	</form>
	<hr />
        <?php 
        $comments = App\Comments::select()->orderBy('id', 'desc')->get();
        foreach($comments as $comment):
            $user = App\User::select()->where('id', '=', $comment->id_user)->first();
        ?>
        <div class="row">
            <div class="col-md-1">
                <img src='{{url($user->perfiles)}}' class='img-responsive' style='max-width: 60px' />
                <strong>{{$user->name}}</strong>
            </div>
            <div class='col-md-6'>
               {{$comment->comment}} 
               <br />
               <i>Fecha: {{$comment->date}} · Hora: {{$comment->time}}</i>
            </div>
        </div>
        <hr />
        <?php endforeach ?>
@else
	<hr />
	<p class="bg-info" style="padding: 20px;">Para poder publicar comentarios tienes que <a href="{{url('auth/login')}}">iniciar sesión</a></div>
	<hr />
@endif
@stop


En la vista podemos ver un mensaje flash "status" que mostrará un mensaje al usuario cuando el comentario se haya publicado con éxito, luego podemos ver como se comprueba si el usuario está autenticado, si lo está se carga el formulario para publicar comentarios con cierta información de usuario como la imagen de perfil y nombre, también se muestra como se realiza la consulta de selección de comentarios. De lo contrario, es decir, si el usuario no está autenticado, se muestra un mensaje indicando al usuario que debe iniciar sesión para poder publicar comentarios.

Lo siguiente es crear la acción createComment en el controlador UserController, esta acción será la encargada de insertar el registro en la tabla "comments", pero previamente agregaremos la clase "App\Comments" al controlador ...

use App\Comments;


Código de createComment ...

    public function createComment(Request $request){
        $comment = e($request->comment);
        $date = date('Y-m-d');
        $time = date('H:m:s');
        Comments::insert([
            'comment' => $comment,
            'id_user' => Auth::user()->id,
            'date' => $date,
            'time' => $time,
        ]);
        return redirect('home')->with('status', 'Enhorabuena comentario publicado con éxito');
    }


Y agregamos la nueva ruta en routes.php para conectarla a la acción ...

Route::post('user/createcomment', 'UserController@createComment');


Finalmente realizamos la prueba para publicar comentarios y ver como los comentarios creados son mostrados en el muro.