Hola a todos! Continuamos la serie de publicaciones de derechos de autor en previsión del inicio del curso
"Marco Laravel" . En un
artículo anterior
, analizamos los fundamentos teóricos de Laravel. Sin embargo, la teoría de cualquier marco puede estudiarse durante mucho tiempo y no entender nada hasta que escriba algo en la práctica.

Así que vamos a usted y escribo la aplicación en la que cada usuario puede autenticar y crear nuevos álbumes y subir fotos a.
Si aún no sabe qué es MVC, lea esto , pronto tendrá que usarlo en la práctica .
Las guías de este tipo comienzan con una explicación de cómo configurar su entorno, etc. El problema es que en cada plataforma es diferente, pero quiero que el artículo sea interesante para todos. Solo daré enlaces a lo necesario, e intentarás instalarlo y configurarlo tú mismo.
Entonces necesitamos:
Compositor Para aquellos en el tanque, Composer es un administrador de paquetes para PHP (sí, como npm para JavaScript). Puedes descargarlo
aquí .
El mismo
Laravel . Hay algunas de las opciones más populares aquí: Homestead y Valet (y, de hecho, muchas otras). Sin embargo, este último sólo para Mac OS. Técnicamente, el lector puede usar cualquier ensamblaje favorito, si solo cumple con
estos requisitos.
Y un detalle sutil, pero
Node.js también será necesario para que podamos instalar paquetes npm.
Ejecute el comando:
composer global require laravel/installer
para instalar Laravel.
Recuerde poner el
$Home/.composer/vendor/bin
(o su equivalente en su sistema operativo) en su variable
PATH
para que el comando Laravel funcione en su sistema.
Entonces, un buen proyecto comienza con un TOR comprensible.
Tratemos de formular los requisitos básicos para nuestra aplicación simple:
El usuario tiene la posibilidad de subir fotos al sitio por ellos mismos discos. Él puede registrarse y puede iniciar sesión. La base de datos es MySQL. El marco que se usa para simplificar el proceso de diseño es Bootstrap, como el marco de diseño más común.
La primera acción que realiza inmediatamente después de la creación es conectar la base de datos. Si aún no comprende cómo instalar y ejecutar su base de datos, use soluciones de escritorio ya preparadas de Evil Corporation:
aquí y
aquí . Esto será suficiente al principio.
Entonces, todo está listo. Vamos a su directorio favorito y comenzamos el proyecto con
laravel new gallery
A continuación, debe conectar nuestra base de datos. Para hacer esto, vaya a MySQL Branch y cree una nueva base de datos de la
galería (no olvide establecer el juego de caracteres en utf-8 y ollation en
utf_general_ci
para evitar problemas con el idioma ruso).

A continuación, vaya al archivo
.ENV
y configure una conexión similar, recordando cambiar las variables a su nombre de usuario y contraseña:
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=gallery DB_USERNAME=pavel DB_PASSWORD=
Después de eso, podremos migrar nuestras bases de datos.
php artisan migrate
Si configuró su conexión en
.ENV
correctamente, entonces todo debería funcionar para usted.
Como acordamos en t / z, tendremos un proceso de autorización, registro, y también el usuario tendrá la oportunidad de crear álbumes y subir fotos allí. Para implementar todo, necesitamos las tablas apropiadas en la base de datos.
Crea la tabla de álbumes
Entonces, ¿dónde comienza el backend? Desde crear una tabla en nuestra base de datos. Este comando en la terminal creará una oportunidad para que podamos migrar a la base de datos:
php artisan make:migration CreateAlbumsTable
Entonces, necesitamos determinar qué columnas deben estar en nuestra tabla. Esto debe hacerse en el archivo que creó debido a la última migración. Se encuentra en su proyecto en la carpeta
gallery/database/migrations
y su nombre está asociado con el momento de su creación. Debe editarse de la siguiente manera:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; class CreateAlbumsTable extends Migration { public function up() { Schema::create('albums', function(Blueprint $table) { $table->increments('id')->unsigned(); $table->string('name');
No te olvides de hacer
php artisan migrate
Ahora la pestaña de su base de datos en MySQL Branch debería tomar la siguiente forma:

Por lo tanto, hemos creado nuestra base de datos, ahora tenemos que atar a nuestro modelo
Eloquen base de datos que van a interactuar con nuestra base de datos.
Crear un modelo de álbum

Ahora tenemos que crear un modelo elocuente ORM. Si no comprende cómo nos mudamos tan rápido de uno a otro, debería leer
esto. Utilizaremos el mismo ayudante de Artisan para generar la plantilla del modelo:
marca artesanal php: álbum modelo
A continuación, vamos a
gallery/app/Album.php
y lo editamos:
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Album extends Model { protected $table = 'albums'; protected $fillable = array('name','description','cover_image'); public function Photos(){ return $this->hasMany('App\Image'); } }
Tabla de imágenes
Wow! Nuestro modelo de álbum está listo, ahora puedes hacer nuestras imágenes. Aquí el proceso se repetirá nuevamente:
php artisan make:migration CreateImagesTable
Vamos a editar nuestra migración:
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateImagesTable extends Migration { public function up() { Schema::create('images', function (Blueprint $table) { $table->increments('id'); $table->integer('album_id')->unsigned(); $table->string('image'); $table->string('description'); $table->foreign('album_id')->references('id')->on('albums')->onDelete('CASCADE')->onUpdate('CASCADE'); $table->timestamps(); }); } public function down() { Schema::dropIfExists('images'); } }
Y nuevamente hacemos la migración:
php artisan migrate
¡Espero que tu migración sea un éxito! Sin embargo, necesitamos explicar una cosa más que hubiera sido demasiado larga para escribir en los comentarios: utilizamos la clave
foreign
para unir las dos tablas
Álbumes e
Imágenes . Cada álbum tiene sus propias imágenes, y si desea eliminar algún tipo de álbum, entonces probablemente piense que las fotos también se eliminarán.
modelo imagen
Es hora de crear un modelo que funcione con la tabla de
imágenes . Espero que ya adivines qué hacer:
php artisan make:model Image
Se crea la plantilla, vaya a
gallery/app/Image.php
para editarla.
Aquí, también, todo debería estar claro:
class Image extends Model { protected $table = 'images'; // , protected $fillable = array('album_id','description','image'); // }
Nuestro modelo de
imagen está listo. Ahora necesitamos un controlador para crear álbumes en nuestra base de datos.
Creación del álbum
Para guardar, mostrar y eliminar en nuestro álbum, necesitamos algunas funciones en nuestro controlador. Pero primero necesitas el controlador en sí:
php artisan make:controller AlbumsController
Vaya a la
gallery/app/Http/Controllers/AlbumsController.php
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\MessageBag; use Validator; use App\Album; class AlbumsController extends Controller { public function getList() // { $albums = Album::with('Photos')->get(); return view('index')->with('albums',$albums); } public function getAlbum($id) { $album = Album::with('Photos')->find($id); $albums = Album::with('Photos')->get(); return view('album', ['album'=>$album, 'albums'=>$albums]); } public function getForm() { return view('createalbum'); // } public function postCreate(Request $request) { $rules = ['name' => 'required', 'cover_image'=>'required|image']; // $input = ['name' => null]; // $validator = Validator::make($request->all(), $rules); if($validator->fails()){ return redirect()->route('create_album_form')->withErrors($validator)->withInput(); } $file = $request->file('cover_image'); $random_name = str_random(8); $destinationPath = 'albums/'; $extension = $file->getClientOriginalExtension(); $filename=$random_name.'_cover.'.$extension; $uploadSuccess = $request->file('cover_image')->move($destinationPath, $filename); $album = Album::create(array( 'name' => $request->get('name'), 'description' => $request->get('description'), 'cover_image' => $filename, )); return redirect()->route('show_album',['id'=>$album->id]); } public function getDelete($id) // { $album = Album::find($id); $album->delete(); return Redirect::route('index'); } }
Entonces tenemos que redefinir nuestros caminos. Para aquellos que no lo saben, el enrutamiento es configurar las rutas que se muestran al usuario en el navegador y las acciones que nuestra aplicación debe realizar. Vamos al archivo
web.php
:
<?php // Route::get('/', array('as' => 'index','uses' => 'AlbumsController@getList')); // Route::get('/createalbum', array('as' => 'create_album_form','uses' => 'AlbumsController@getForm')); // Route::post('/createalbum', array('as' => 'create_album','uses' => 'AlbumsController@postCreate')); // Route::get('/deletealbum/{id}', array('as' => 'delete_album','uses' => 'AlbumsController@getDelete')); // Route::get('/album/{id}', array('as' => 'show_album','uses' => 'AlbumsController@getAlbum')); // // Route::get('/addimage/{id}', array('as' => 'add_image','uses' => 'ImageController@getForm')); // Route::post('/addimage', array('as' => 'add_image_to_album','uses' => 'ImageController@postAdd')); // Route::get('/deleteimage/{id}', array('as' => 'delete_image','uses' => 'ImageController@getDelete')); // Route::post('/moveimage', array('as' => 'move_image', 'uses' => 'ImageController@postMove'));
{id}', array ( 'como' => 'show_album', 'usos' => '@ AlbumsController getAlbum')); <?php // Route::get('/', array('as' => 'index','uses' => 'AlbumsController@getList')); // Route::get('/createalbum', array('as' => 'create_album_form','uses' => 'AlbumsController@getForm')); // Route::post('/createalbum', array('as' => 'create_album','uses' => 'AlbumsController@postCreate')); // Route::get('/deletealbum/{id}', array('as' => 'delete_album','uses' => 'AlbumsController@getDelete')); // Route::get('/album/{id}', array('as' => 'show_album','uses' => 'AlbumsController@getAlbum')); // // Route::get('/addimage/{id}', array('as' => 'add_image','uses' => 'ImageController@getForm')); // Route::post('/addimage', array('as' => 'add_image_to_album','uses' => 'ImageController@postAdd')); // Route::get('/deleteimage/{id}', array('as' => 'delete_image','uses' => 'ImageController@getDelete')); // Route::post('/moveimage', array('as' => 'move_image', 'uses' => 'ImageController@postMove'));
Wow Para que nuestra aplicación gane dinero, debemos asegurarnos de tener los enlaces necesarios a las etiquetas (alias) de las clases que necesitamos al final del gallery/config/app.php
. Estas son solo configuraciones técnicas:
'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, 'Bus' => Illuminate\Support\Facades\Bus::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, 'Form' => Collective\Html\FormFacade::class, 'Html' => Collective\Html\HtmlFacade::class, ], // FORM )
\ Fachadas \ App :: clase, 'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, 'Bus' => Illuminate\Support\Facades\Bus::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, 'Form' => Collective\Html\FormFacade::class, 'Html' => Collective\Html\HtmlFacade::class, ], // FORM )
\ Fachadas \ redirección :: clase, 'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, 'Bus' => Illuminate\Support\Facades\Bus::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, 'Form' => Collective\Html\FormFacade::class, 'Html' => Collective\Html\HtmlFacade::class, ], // FORM )
\ Fachadas \ Solicitud :: clase, 'aliases' => [ 'App' => Illuminate\Support\Facades\App::class, 'Artisan' => Illuminate\Support\Facades\Artisan::class, 'Auth' => Illuminate\Support\Facades\Auth::class, 'Blade' => Illuminate\Support\Facades\Blade::class, 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, 'Bus' => Illuminate\Support\Facades\Bus::class, 'Cache' => Illuminate\Support\Facades\Cache::class, 'Config' => Illuminate\Support\Facades\Config::class, 'Cookie' => Illuminate\Support\Facades\Cookie::class, 'Crypt' => Illuminate\Support\Facades\Crypt::class, 'DB' => Illuminate\Support\Facades\DB::class, 'Eloquent' => Illuminate\Database\Eloquent\Model::class, 'Event' => Illuminate\Support\Facades\Event::class, 'File' => Illuminate\Support\Facades\File::class, 'Gate' => Illuminate\Support\Facades\Gate::class, 'Hash' => Illuminate\Support\Facades\Hash::class, 'Lang' => Illuminate\Support\Facades\Lang::class, 'Log' => Illuminate\Support\Facades\Log::class, 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, 'Request' => Illuminate\Support\Facades\Request::class, 'Response' => Illuminate\Support\Facades\Response::class, 'Route' => Illuminate\Support\Facades\Route::class, 'Schema' => Illuminate\Support\Facades\Schema::class, 'Session' => Illuminate\Support\Facades\Session::class, 'Storage' => Illuminate\Support\Facades\Storage::class, 'URL' => Illuminate\Support\Facades\URL::class, 'Validator' => Illuminate\Support\Facades\Validator::class, 'View' => Illuminate\Support\Facades\View::class, 'Form' => Collective\Html\FormFacade::class, 'Html' => Collective\Html\HtmlFacade::class, ], // FORM )
Genial ¡Ahora necesitamos definir nuestras ideas! Vaya a la carpeta
gallery/resources/views
. Puedes eliminar
welcome.blade.php
, puedes irte, no importa. Crea
index.blade.php
e
includes
subcarpeta para agregar las partes repetidas de la
view
. Entonces, nuestro
index.blade.php
debería tomar la siguiente forma:
@include('includes.header') <body> @include('includes.nav') <div class="container"> <div class="starter-template"> <div class="row"> @foreach($albums as $album) <div class="col-lg-3"> <div class="thumbnail" style="min-height: 514px;"> <img alt="{{$album->name}}" src="/albums/{{$album->cover_image}}"> <div class="caption"> <h3>{{$album->name}}</h3> <p>{{$album->description}}</p> <p>{{count($album->Photos)}} image(s).</p> <p>Created date: {{ date("d FY",strtotime($album->created_at)) }} at {{date("g:ha",strtotime($album->created_at)) }}</p> <p><a href="{{route('show_album', ['id'=>$album->id])}}" class="btn btn-big btn-default"> </a></p> </div> </div> </div> @endforeach </div> </div><!-- /.container --> </div> </body> </html>
-> @include('includes.header') <body> @include('includes.nav') <div class="container"> <div class="starter-template"> <div class="row"> @foreach($albums as $album) <div class="col-lg-3"> <div class="thumbnail" style="min-height: 514px;"> <img alt="{{$album->name}}" src="/albums/{{$album->cover_image}}"> <div class="caption"> <h3>{{$album->name}}</h3> <p>{{$album->description}}</p> <p>{{count($album->Photos)}} image(s).</p> <p>Created date: {{ date("d FY",strtotime($album->created_at)) }} at {{date("g:ha",strtotime($album->created_at)) }}</p> <p><a href="{{route('show_album', ['id'=>$album->id])}}" class="btn btn-big btn-default"> </a></p> </div> </div> </div> @endforeach </div> </div><!-- /.container --> </div> </body> </html>
El contenido includes/header.blade.php
:
<!doctype html> <html lang="ru"> <head> <meta charset="UTF-8"> <title> </title> <link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0-rc1/css/bootstrap.min.css" rel="stylesheet"> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0-rc1/js/bootstrap.min.js"></script> <style> body { padding-top: 50px; } .starter-template { padding: 40px 15px; text-align: center; } </style> </head>
El contenido includes/nav.blade.php
:
<div class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <button type="button" class="navbar-toggle"data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/"> </a> <div class="nav-collapse collapse"> <ul class="nav navbar-nav"> <li><a href="{{URL::route('create_album_form')}}"> </a></li> </ul> </div><!--/.nav-collapse --> </div> </div>
¡Eso es todo por hoy! Esto, por supuesto, es solo la primera parte de nuestra aplicación. Gracias a todos por su atención, en la siguiente parte complementaremos nuestra
view
y discutiremos el tema de la validación de imágenes.
Enlaces utiles:Documentación en rusoUna guía útil en inglés que, mejor que la documentación, explica cómo funciona la herencia y la extensión de las plantillas Blade.Mucha información útil y ejemplos prácticos de creación de aplicaciones.