Фреймворк Laravel пользуется популярностью за счет ряда факторов:
Кроме того, в нем доступна масса инструментов для развертывания приложений и упрощения веб-разработки [31-А].
Чтобы запустить на веб-сервере Laravel, в Ubuntu необходимо удовлетворить ряд зависимостей. Все необходимые для работы компоненты имеются в наличии на виртуальной машине Laravel Homestead. Поэтому разработчики рекомендуют использовать именно ее для запуска на локальной машине.
Тем не менее, развертывать и тестировать приложение придется на веб-серверах с Linux, а не на Homestead. Чтобы установить Laravel на таком веб-сервере, на нем должны быть установлена версия PHP >= 7.2.0 и следующие расширения PHP:
В Ubuntu эти зависимости можно установить при помощи команды в терминале:
sudo apt install php php-mysql php-mbstring php-tokenizer php-xml php-json php-common php-dompdf
Кроме того, у Laravel еще есть несколько требований к серверу:
PHP >= 7.2
OpenSSL PHP Extension
Если с момента последнего запуска composer прошло более 30 дней, то необходимо обновить composer.
composer slef-update
После обновления composer запустим команду установки Laravel [32].
Composer create-project laravel/laravel -–prefer-dist
Laravel установлен.
Далее необходимо изменить права на запись. Папки внутри storage должны быть доступны web-серверу для записи. Воспользуемся командой chmod.
sudo chmod -R 777 storage
Изабвляеся от public в запросах. Для того, чтобы слово public не присутстовало в запросах приложения, создадим файл .htaccess, который будет перенаправлять запрос.
RewriteEngine On RewriteRule ^(.*)$ public/$1 [L]
Теперь все запросы автоматически перенаправляются в папку public, а все остальные папки проекта стали закрытыми.
Маршрутизация проекта
Все маршруты прописаны в файле routes/web.php. Так как каждый маршрут является неотъемлимой частью всего web-приложения, рассмотрим их все:
//--------------------------------------------------------------------- Auth::routes(); Route::get('/home', 'HomeController@index'); //ajax Route::post('ajax', 'AjaxController@postIndex'); Route::post('/ajax/public/{id}/', 'Ajax\MenuController@postPublics'); Route::post('ajax/showCatalog', 'AjaxController@postCatalog'); Route::post('ajax/showArticle', 'AjaxController@postArticle'); Route::post('/ajax/addAnswer', 'AjaxController@postAnswer'); Route::post('/ajax/register', 'Ajax\MenuController@postRegister'); Route::post('/ajax/common/{id}/{into}', 'Ajax\MenuController@postCommon'); Route::group(['middleware' => ['auth']], function () { Route::get('/delete/{id}', 'PublicController@getPublicDelete'); //for student Route::get('work/delete/{id}','Student\CourseController@getDelete'); Route::get('work/edit/{id}','Student\CourseController@getEdit'); Route::get('lab/delete/{id}','Student\LabController@getDelete'); Route::post('lab/edit/{id}','Student\LabController@postEdit')->middleware('teacher'); Route::post('student/work/','Ajax\StudentController@postWork'); Route::post('student/work/edit/{id}','Student\CourseController@postEdit'); Route::post('/course/into/{id?}', 'Student\CourseController@postInto'); Route::post('addCourse', 'Student\CourseController@addCourse'); // for user Route::get('home/edit', 'HomeController@edit'); Route::get('home/edit/{id}','HomeController@getOne'); Route::get('home/projects', 'Auth\ProjectController@getIndex'); Route::get('home/students', 'Auth\GroupController@getGroups'); Route::get('/profile', 'Auth\ProfileController@getIndex'); Route::get('course/add/{cat_id}/{course_id}','Auth\CourseController@getAdd'); // ajax Route::get('/home/ajax/group','Ajax\GrController@getIndex'); Route::post('/ajax/into/', 'Ajax\MenuController@postInto'); Route::post('/ajax/work/', 'Ajax\LabsController@postForm'); Route::post('/ajax/editArticle', 'AjaxController@postEditArticle'); Route::post('/ajax/editMaterial','AjaxController@postMaterial'); Route::post('/ajax/editCatalog', 'AjaxController@postEditCatalog'); Route::post('/ajax/addPublic', 'AjaxController@postPublic'); Route::post('/ajax/editCatalogStudent', 'Ajax\StudentController@postEditCatalog'); // post Route::post('home/edit/{id}','HomeController@postOne'); Route::post('home/group/add', 'Auth\GroupController@postGroup'); Route::post('/profile', 'Auth\ProfileController@postIndex'); Route::post('home/project','Auth\ProjectController@postIndex'); Route::post('addCatalog/{catalog?}', 'FormController@addCatalog'); Route::post('addArticle', 'FormController@addArticle'); Route::post('editArticle', 'FormController@editArticle'); Route::post('materials/link/{url}', 'MaterialController@postLink'); Route::post('materials/lists/{id}', 'MaterialController@postList'); Route::post('/form/into/{id?}', 'FormController@postInto'); Route::get('/{chapter}/{cat}/{art}/edit', 'Auth\EditController@getArticle'); Route::post('/{chapter}/{cat}/{art}', 'Auth\EditController@postArticle'); Route::post('lab/{id}','Ajax\LabsController@postAdd'); Route::post('/ajax/course', 'Ajax\CourseController@postAll'); //files Route::get('delete/{id}', 'UploaderController@getDelete'); Route::post('laravel-filemanager/upload','UploaderController@postFirst'); Route::post('/uploader', 'LibsController@getUpload'); }); Route::post('/ajax/labs/', 'Ajax\LabsController@postCourse'); //othes Route::get('/', 'IndexController@getChapt'); //controller for main page Route::get('projects','ProjectController@getAll'); Route::get('project/{id}','ProjectController@getOne'); Route::get('/conference', 'ConferenceController@getIndex'); Route::get('/eruds', 'ThesesController@getEruds'); //controller for theses Route::get('/theses', 'ThesesController@getIndex'); //controller for theses Route::get('/links', 'LinkController@getIndex'); Route::get('/lists', 'ListController@getIndex'); Route::get('/courses', 'ThesesController@getCourses'); Route::get('/course/{id}', 'WorkController@getCourse'); Route::get('/lab/{id}', 'WorkController@getCourse'); Route::get('/media/{name}','MediaController@getOne'); Route::get('/publics/add/{catalolg_id}/{public_id}', 'PublicController@getIndex'); Route::get('/document/doc/{url}','DocsController@getDoc'); //in doc Route::get('/document/pdf/{url}','DocsController@getPdf'); //in pdf Route::get('/document/html/{url}','DocsController@getHtml'); //in html Route::get('/course/doc/{id}','DocsController@getCourseDoc'); Route::get('/course/html/{id}','DocsController@getCourseHtml'); Route::get('/articles', 'ThesesController@getArticles'); Route::get('/keywords','KeyController@getAll'); Route::get('/authors','AuthorController@getAll'); Route::get('/author/{name}','AuthorController@getOne'); Route::get('/user/{id}', 'UserController@getOne'); Route::get('key/{id}','KeyController@getIndex'); Route::get('/page/{url}','PageController@getIndex'); Route::get('/{chapter}', 'IndexController@getChapt'); //chapters of erud Route::get('/{chapter}/{cat}', 'IndexController@getCat'); //chapter and catalog Route::get('/{chapter}/{cat}/{art}', 'IndexController@getArt'); Route::post('backend/upload','UploaderController@files');
Подключение базы данных
Сперва создадим базу данных. Для этого перейдем в PHPMyAdmin.
http://127.0.0.1/phpmyadmin/
Создаем базу с именем web.
Поключение к базе осуществляется в файле .env в корне проекта. Для этого переопределим переменные окружающей среды.
DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=web DB_USERNAME=root DB_PASSWORD=
Artisan
Laravel поставляется совместно с встроенным программным обеспечением — Artisan. Artisan — название интерфейса командной строки, входящей в состав Laravel. Он предоставляет полезные команды для использования во время разработки вашего приложения. Работает на основе мощного компонента SymfonyConsole [31-Б].
Чтобы вывести все доступные команды Artisan, воспользуемся командой list:
php artisan list
Рассмотрим используемые в проекте команды подробнее:
make:command — создаёт новый класс команды
make:console — создаёт новую команду Artisan
make:controller — создаёт новый класс контроллера
make:event — создаёт новый класс события
make:middleware — создаёт новый класс промежуточного ПО
make:migration — создаёт новый файл миграции
migrate - выполнение существующих миграций
make:model — создаёт новый класс модели, опционально и миграцию
make:provider — создаёт новый класс поставщика услуг
make:request — создаёт новый класс запроса формы
event:generate — генерирует пропущенные события и обработчики
Каждая команда также включает и инструкцию, которая отображает и описывает доступные аргументы и опции для команды. Чтобы её вывести, необходимо добавить слово help перед командой:
php artisan help migrate
Для определения текущей версии Laravel, можно воспользоваться опцией — version.
php artisan —version
Усовершенствование концепции HMVC в фрэймворке Laravel заключается во введении вспомгательных и промежуточных решений применяемых во взаимодействии контроллеров с моделями. Такими решениями являются: миграции, middleware, или подготовительное программное обеспечение, serviceProvider, или классы библиотек, другие решения [47].
Миграции
Миграции базы данных являются весьма полезны для любого проекта, особенно для проектов с несколькими разработчиками, позволяя иметь последнюю версию базы данных у всех разработчиков. В Laravel для этого достатчно выполнить одну команду в командной строке [33].
Для создания и выполнения миграций воспользуемся интерфейсом командной строки Artisan.
Откроем консоль командной строки из папки, где расположен файл artisan. В консоли введем следующие команды:
php artisan make:model -m Catalog //команда для создания файлов модели и миграции Catalog php artisan make:model -m Article //команда для создания файлов модели и миграции Article
Данные команды создадут файлы миграций вместе с моделями. Для реализации миграций можно воспользоваться примером готовой миграции из файла 2014_10_12_000000_create_users_table.php.
use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateUsersTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->string('email')->unique(); $table->string('password'); $table->rememberToken(); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('users'); } }
Файл миграции представлен двумя методами, up() и down(). Метод up() содержит схемы, используемые при создании таблиц, а метод down() вызвается, когда необходимо удалить таблицу.
Метод down() будет одинаков для всех миграций, а вот методы up(), реализуюище сами таблицы, необходимо рассмотреть.
Выполняемый метод up() файла миграции таблицы categories содержит следующий код.
public function up() { Model::unguard(); Schema::create('categories',function(Blueprint $table){ $table->increments("id"); $table->string("name"); $table->string("parent_id")->nullable(); $table->enum("showhide", ["show", "hide"])->nullable(); $table->string("type")->nullable(); $table->timestamps(); $table->softDeletes(); }); }
Выполняемый метод up() файла миграции таблицы articles содержит следующий код.
public function up() { Schema::create('articles', function (Blueprint $table) { $table->increments('id'); $table->integer('user_id')->default(0); $table->integer('category_id')->default(0); $table->string('name'); $table->text('description'); $table->string('url'); $table->enum('showhide', array('show','hide'))->default('show'); $table->timestamps(); }); }
Если база данных подключена, можно приступить к выполнению миграций:
php artisan migrate
Данная команда создает несколько таблиц, в том числе таблицы users, catalogs и articles.
Controller
Контроллеры хранятся в папке app/controllers/. Этот путь, в свою очередь определен в файле composer.json в настройке classmap.
Все контроллеры должны наследовать класс BaseController. Этот класс также может хранится в папке app/controllers, и в него можно поместить общую логику для других контроллеров. BaseController расширяет базовый класс Controller.
В приложении имеется более десяти контроллеров. Основными являются IndexController, ThesesController и DocsController.
Создаем контроллеры:
php artisan make:controller IndexController php artisan make:controller ThesesController php artisan make:controller DocsController
Конечной точкой маршрутизатора является контроллер. Контроллер принимает переменные запроса (если таковые имеются) и содержит логику приложения. Логика приложения может быть прописана либо в самих контрллерах, либо во вспомогательных файлах, к которым контроллер обращается.
Каждый из контроллеров выполняется независимо от других, и содержит следующую логику:
IndexController - главный контроллер приложения, который содержит экшны (методы) реализующие главную страницу, список открытых категорий и открытую статью выбранной категории
ThesesController - контроллер содержащий экшны диссертаций
DocsController - контроллер, реализующий ответы страницы в виде различных форматов: .doc, .pdf, .html и другие.
Рассмотрим контроллер IndexController.php
namespace App\Http\Controllers; use App\Article; use Illuminate\Http\Request; use App\Catalog; use App\MaterialPicture; class IndexController extends Controller { public function getChapt() { $getChapter = Catalog::where('parent_id', 0)->get(); return view('index', compact('getChapter')); } public function getCat(){ return view('article_list'); } public function getArt($prog=null, $cat=null, $id=null){ $pictures = MaterialPicture::where('url',$cat) ->orderBy('id','DESC')->get(); $catalog = Catalog::where('url', $cat)->first(); $previous = Article::where('id', '<', $id) ->where('cat_id', $catalog→id)→ ->max('id'); $next = Article::where('id', '>', $id)→ ->where('cat_id', $catalog→id)→ ->min('id'); return view('article_show', compact('previous','next','pictures')); } }
Model
Модель - это класс, через который программист взаимодействует с сущностями базы данных. По-умолчанию Laravel хранит все модели в папке app/ [31-В].
При создании моделей мы можем обращаться либо к существующим таблицам текущей базы данных, либо одной командой созавать файлы и модели и миграции, которая содержит структуру таблицы. Для одновременного создания файлов моделей и миграций, можно воспользоваться командой:
php artisan make:model Category -m
Модель Article связана с моделью Category по ключу category_id.
Сама связь таблиц реализована в файлах моделей.
Рассмотрим класс модели Category:
class Category extends Model { protected $fillable = [ 'name', 'parent_id', 'type', ]; public function articles() { return $this->hasMany('App\Article','cat_id'); } public function user(){ return $this->belongsTo('App\User'); } }
Модель Category содержит две связи:
articles() - связь с моделей Article по полю cat_id. Каждая запись модели Category содержит множество записей модели Article.
users() - связь c моделью User по полю user_id (по-умолчанию). Каждая запись модели Category принадлежит какой-то записи модели User.
Расмотрим класс модели Article.
class Article extends Model { protected $fillable = [ 'name', 'description', 'user_id', 'cat_id' ]; public function catalogs() { return $this->belongsTo('App\Category', 'cat_id'); } public function users() { return $this->belongsTo('App\User', 'user_id'); } }
Каждая запись модели Article принадлежит записи моделям Category и User, для реализации связи были созданы методы catalogs и users.
На данном этапе у нас уже прописана маршрутизация проекта, созданы модели, через которые мы можем делать запросы в базу данных и сами контроллеры.
View
По умолчанию, Laravel работает с шаблонизатором blade. Шаблоны создаются в папке app/views и имеют расширение blade.php. Шаблоны подключаются в экшне через хелпер view(), входящим параметром в который передается имя шаблона без расширения blade.php [31-Г].
Blade — простой, но мощный шаблонизатор, поставляемый с Laravel. В отличие от других популярных шаблонизаторов для PHP Blade не ограничивает вас в использовании чистого PHP-кода в ваших шаблонах. На самом деле все шаблоны Blade скомпилированы в чистый PHP-код и кешированы, пока в них нет изменений, а значит, Blade практически не нагружает ваше приложение. Файлы шаблонов Blade используют расширение .blade.php и обычно хранятся в директории resources/views.
Два основных преимущества использования Blade — наследование шаблонов и секции. Для начала давайте рассмотрим простой пример. Во-первых, рассмотрим макет "главной" страницы. Поскольку многие веб-приложения используют один общий макет для разных страниц, удобно определить этот макет как один шаблон Blade:
// Хранится в resources/views/layouts/app.blade.php
Файл имеет типичную HTML-разметку, со специальными директивами @section и @yield. Директива @section, как следует из её названия, определяет секцию содержимого, а директива @yield используется для отображения содержимого заданной секции.
Определив макет для нашего приложения, давайте определим дочернюю страницу, которая унаследует макет.
При определении дочернего шаблона используйте Blade-директиву @extends для указания макета, который должен быть "унаследован" дочерним шаблоном. Шаблоны, которые наследуют макет Blade, могут внедрять содержимое в секции макета с помощью директив @section. Запомните, как видно из приведённого выше примера, содержимое этих секций будет отображено в макете при помощи @yield:
@extends('layouts.app') @section('content') Это html-содержимое меняющейся части страницы. @endsection
Директива @section('content') будет заменена содержимым макета при отрисовке шаблона.
Специальной artisan-команды для создания элементов представления не существует. Поэтуму blade-файлы создаются в ручную в папке resources/views/
Middleware
HTTP Middleware (посредники) - это фильтры обработки HTTP-запроса. Так, например, в Laravel включены middlewares для проверки аутентификации пользователя. Если пользователь не залогинен, middleware перенаправляет его на страницу логина. Если же залогинен - middleware не вмешивается в прохождение запроса, передавая его дальше по цепочке middleware-посредников к собственно приложению [31-Д].
Middlewares можно использовать в качестве фильтров для роутов.
Конечно, проверка авторизации - не единственная задача, которую способны выполнять middlewares. Это также добавление особых заголовков (например, CORShttp-ответ вашего приложения) или логирование всех http-запросов.
В Laravel есть несколько дефолтных middleware, которые находятся в папке app/Http/Middleware. Это middlewares для реализации режима обслуживания сайта ("сайт временно не работает, зайдите позже"), проверки авторизации, CSRF-защиты и т.п.
Для создания middleware можно воспользоваться artisan-командой make:middleware:
php artisan make:middleware Admin
В папке app/Http/Middleware будет создан файл с классом Admin и методом handle(), к которому добавим следующую логику:
if(Auth::user()->isAdmin != 1){ return redirect()->guest('auth/login'); }
Чтобы пропустить запрос дальше, нужно вызвать функцию-замыкание $next с параметром $request.
Лучше всего представлять middlewares как набор уровней, которые HTTP-запрос должен пройти, прежде чем дойдёт до вашего приложения. На каждом уровне запрос может быть проверен по различным критериям и, если нужно, полностью отклонён.
Далее необходимо добавить middleware в свойство routeMiddleware класса app/Http/Kernel.php, назначив ему некоторое имя, например, admin, которое будет ключем массива:
protected $routeMiddleware = [ 'auth' => 'App\Http\Middleware\Authenticate', 'admin' => 'App\Http\Middleware\Admin', 'guest' => 'App\Http\Middleware\RedirectIfAuthenticated', ];
Теперь в приложении имеется возможность скрывать контроллеры и маршруты как от не авторизованных пользователей, так и от не админов, путем подключения данного middleware.
public function __construct(){ parent::__construct(); $this->middleware('admin'); }
ServiceProviders
Основная задача поставщика услуг, или ServiceProviders – это загрузка вспомогательных, в том числе, и собственных классов [32].
Если открыть конфигурационный файлa app.php, то мы увидим там множество провайдеров, определенных в массиве providers. Это все классы, которые будут загружены для приложения. Многие из них являются отложенными, что означает, что они не будут загружаться при каждом запросе, а только тогда, когда они действительно необходимы, т.е. когда они будут вызываться.
Все провайдеры должны наследоваться от класса Illuminate\Support\ServiceProvider. Данный абстрактный класс требует, чтобы был определен хотя бы один метод класса-провайдера: register. В этом методе регистрируется вспомогательный класс.
Сам провайдер можно создать с помощью artisan:
php artisan make:provider PhpqueryServiceProvider
В папке providers появился файл PhpqueryServiceProvider.
Провайдеры регистрируются в файле config/app.php.
'providers' => [ // другиесервис-провайдеры 'App\Providers\AppServiceProvider', ],
Теперь вся логика поставщика услуг будет доступна всему приложению. Удобство использования поставщиков услуг заключается в том, что мы можем передавать переменные в элементы представлений минуя контроллеры.
Request
Классы Request предназначены для валидации данных форм, создаются с помощью слдеюущей artisan-команды.
php artisan make:request CategoryRequest
Команда создаст файл с именем CategoryRequest и с соответствующим классом, который содержит два метода authorize() и rules() в папке requests/.
public function authorize() { return true; // имеет ли доступ текущий пользователь }
public function rules() { return []; // возвращаем массив правил по обработке }
Правила валидации, которые используются в методе rules(), прописаны в файле resources/lang/validation.php. Все элементы массива, которые есть в этом файле, можно использовать в качестве правил в request-файлах.
public function rules(){ return [ 'name'=>'required|max:100', 'body' => 'required|min:2', 'theme_id'=>'required|numeric' ]; }
В модели, к которой мы хотим привязать эти request-данные, должно быть определено свойство $fillable, в котором мы указываем, какие имена полей таблицы будут задействованы при множественной вставки данных.
class Category extends Model { protected $fillable = [ 'name', 'body', 'user_id', 'theme_id', ]; }
Контроллер, который будет перехватывать данные из request-запроса, и через модель, с помощью множественной вставки (метод create()) помещать их в таблицу news:
namespace App\Http\Controllers; use Illuminate\Http\Request; use Auth; use App\Http\Requests; use App\Http\Controllers\Controller; class CabinetController extends Controller { public function __consturct(){ parent::__construct(); } public function getIndex(){ return view('cabinet'); } public function postIndex(Requests\CategoryRequest $r){ $r['user_id'] = Auth::user()->id; \App\Category::create($r->all()); return redirect()->back(); } }
При множественной вставке имена полей в таблице должны совпадать с именами элементов форм.
В шаблоне мы можем перехватывать ошибки валидации (волшебство laravel заключается в том, что специально эти ошибки в шаблон передавать не надо). Просто проверяем существует ли массив $errors, и если он существует, значит форма не прошла валидацию, и с помощью foreach проходимся по всем ошибкам, выводя их на экран.
@if (count($errors) > 0) Whoops!Найдены следующие ошибки. @foreach ($errors->all() as $error) {{ $error }} @endforeach @endif
Массив $errors является ассоциативным, где ассоциацией (индексом) массива является имя элемента формы, в которой выявлена ошибка. В тоже время Laravel позволяет работать с ним, как с объектом.
Проверим каждый элемент с помощью специальных методов:
@if($errors->has('name')) {{ $errors->first('name') }} @endif
Для перевода компонентов сайта на русский язык, в конфигурационном файле app.php, в настройках locale укажем ru.
'locale' => 'ru',
Если локаль выставлена в значение «ru», то файлы переводов будут искаться в папке ru. В папке resources/lang создадим еще одну папку – ru. В ее можно вставить скопированный файл en/validation.php. И перевести на русский язык необходимые ошибки. При этомом слова, начинающиеся с : (двоеточия) не переводим, т.к. это атрибуты.
Авторизация
Модуль авторизации поставляется совместно с фрэймворком Laravel. Файл конфигурации авторизации находится в файле config/auth.php [33].
По умолчанию, для сохранения пользовательских данных, Laravel использует модель App\User.
Также модуль поставляется с двумя контроллерами аутентификации из коробки, которые находятся в App\HTTP\Controllers\Auth. AuthController содержит методы регистрации нового пользователя и аутентификации, в то время как PasswordController содержит логику помощи существующим пользователям сбросить свои забытые пароли. Каждый из этих контроллеров использует трэйты (traits), чтобы включить их необходимые методы. Для многих приложений вам не нужно будет изменить эти контроллеры вообще.
Для создания шаблонов и ротов авторизации, необходимо выполнить artisan-команду make:auth.
php artisan make:auth
Авторизация готова. Теперь в приложении доступны следующие url:
http://localhost//register http://localhost/login http://localhost/home http://localhost/logout
Маршруты /register и /login определены для неавторизованных пользователей, а /home и /logout соответственно для авторизованных.
Для разделения логики авторизованных пользователей от неавторизованных в шаблонизаторе blade используются диррективы @auth или @guest:
@guest() // реализация html кода для неавторизованных пользователей @else // реализация html кода для авторизированных пользователей @endguest
В результате проделанных действий была разработана серверная часть web-приложения.