Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Думаю, это будет вопрос скорее по PHP, но всё же структура Laravel тоже имеет влияние. Может быть, Вы в ответе предложите один из инструментов Laravel.
Итак, я хочу избежать хардкоднга, потому храню имена таблиц и их полей, псевдонимы маршрутов и т. д. в массиве, а вернее, в отдельном классе, например:
class References {
const DB_TABLES = array(
'pages' => array(
'tableName' => 'pages',
'fieldNames' => array(
'id' => 'id',
'pagename' => 'name',
'title' => 'title',
'metadesc' => 'metadesc',
'keywords' => 'keywords'
)
);
}
Обращение к этому массиву длиннее, чем прямое указание строкового значения, зато легко переименовать поле без внедрения в логику:
use App\Extenders\References as REF;
private function getTopPageHtmlHeadData(){
return DB::table(REF::DB_TABLES['pages']['tableName'])
-> where(REF::DB_TABLES['pages']['fieldNames']['pagename'], REF::OPEN_PAGE_NAMES_IN_DB['top'])
-> first();
}
Вопрос у меня такой: насколько такое средство избежания хардкодинга отрицательно скажется на производительности и какие более быстрее, но не хардкодные альтернативы есть?
Всерьёз занявшись улучшением поддерживаемости кода, создал поля класса контроллера и добавл конструктор. Попробовал осуществить запрос к базе данных в конструкторе (вернее, вызвать соответствующий метод из конструктора), а не как обычно (то есть в методе, вызываемого из маршрутов web.php, в примере ниже — renderTopPage). Работает.
class TopPageController extends Controller {
private $pageHtmlHeadData;
public function __construct() {
$this -> pageHtmlHeadData = $this -> getTopPageHtmlHeadData();
}
public function renderTopPage(){
// код этого метода не нужен в данном примере, но именно этот метод вызывается из web.php
}
private function getTopPageHtmlHeadData(){
retrun // SQL запрос к БД ...
}
}
Вопрос такой: а будет ли выигрыш в скорости генерации страницы засчёт того, что SQL-запрос был выполнен до метода, где создаётся вид? Я бы смог ответить на этот вопрос, если бы знал, когда создаётся экзепляр контроллера (а он где-то создаётся, хотя у родительских классов конструкторов нет).
Никак не могу найти причину ошибки Swift_TransportException Process could not be started. На одном проекте работает — на другом — ни вкакую. И ещё в скобках показаны крокозябры:
Swift_TransportException Process could not be started [w肳ꂽpX܂B ]
При попытке локализовать ошибку я убрал всё лишее из функции отправки email, приведённый ниже код так же не работает, как и исходный:
private function submitRequestEmailToAdmin(){
Mail::send('open.email.consultRequestNotification', [],
function($message){
});
}
Настройки среды такие (в другом проекте с ними всё работает):
MAIL_DRIVER=mail MAIL_HOST= MAIL_PORT= MAIL_USERNAME= MAIL_PASSWORD= MAIL_ENCRYPTION=
'driver' => env('MAIL_DRIVER', 'smtp'),
В следующем эксперименте я получаю false в первой строке при каждой перезагрузке страницы.
dump($request->session()->has('someSessionVariable')); // false
$request->session()->put('someSessionVariable', 'value');
dump($request->session()->has('someSessionVariable')); // true
Маршрут обрабатывается последником web (впрочем, без него то же самое), драйвер сессий — по умолчанию, т. е. file. SESSOON_LIFETIME тоже не менял — по умолчанию 120, expire_on_close — false.
Хочу добавить собственный класс в проект. На одном из формумов было сказано, что лучше свои классы помещать в app/, тогда я добавил свой класс в директорию app/Extenders/ (назначение этого класса не важно в данном вопросе).
Теперь пытаюсь импортировать свой класс в миграцию:
use App\Extenders\References as REF;
При попытке выполнить миграцию получается ошибка:
[Symfony\Component\Debug\Exception\FatalThrowableError]
Class 'App\Extenders\References' not found
Я просмотрел много ответов, но рабочего решения нигде не нашёл. %% composer dump-autoload не помогло %%. Видел :[QUOTE][https://stackoverflow.com], решение[/QUOTE]:
"autoload": {
"classmap": [
"app/database/migrations"
],
"psr-4": {
"Acme\\controllers\\": "app/controllers"
}
}
Но этого кода не достаточно, чтобы понять, что делать. Во-первых, этих autoload в composer.lock уйма, и непонятно, какой из них менять или новый добавлять… Да и что за psr-4, тоже непонятно.
Используй стандартные файлы шаблонов или переопредели методы.
Нет, мне нужны именно свои собственные, со своим дизайном и организованные в файловой системе так, как мне комфортно.
Потому что в этих таблицах разные данные для аутентификации. Всё, что нужно администраторам для аутентификации — это имя, email и пароль; в данном случае аутентификация осуществляется по email. Другое дело с таблицей аутентификационных данных для заказчиков. Там будет помимо имени заказчика и пароля также название сайта, алиас и номер заказа; аутентификация в данном случае осуществляется по номеру заказа, а не по имени заказчика.
Если все выше описанные задачи выполнимы стандартными средствами без кодизврата, то почему бы и нет. Но я пока сомневаюсь, что стандартные средства настолько гибки.
Хорошо, но как? Как решается эта задача, если:
— Макеты с формой входа пользовательские и они лежат во views, но там, где мне надо (не в стандартном пути, генерируемом php artisan make:auth). На данный момент страница входа в закрытую зону сайтов в разработке — такая же открытая страница, как и многие другие потому маршрут к ней определяется так:
Route::get('/login_to_sites_in_development_zone',
[ 'as' => 'loginToSitesInDevelopmentZonePage',
'uses' => 'MainController@renderLoginToSiteInDevelopmentZonePage']
);
— Разные таблицы с разными данными для админов и заказчиков. На данный момент аутентификацию для админов я ещё не проработал, но уже организовал последовательную проверку номера заказа и соответствующего пароля с выводом пользовательских ошибок. То есть у меня выводит что-то поинтереснее, чем стандартное Laravel-сообщение об ошибке:
if (is_null($orderIdInDB)) {
return Redirect::route('loginToSitesInDevelopmentZonePage')->withErrors(['wrongOrderId' => true])->withInput();
}
xml @if ((bool) $errors->first('wrongOrderId')) <div class="signInForm-errorMessagebox" id="invalidID-errorMessage"> <div class="signInForm-errorMessagebox-heading">Неверный ID заказа</div> <div class="signInForm-errorMessagebox-contains"> Вы ввели неверный или несуществующий ID заказа.</div> </div> @endif
— Регистрация и сброс паролей не требуются, меня сейчас интересует только аутентификация. Соответственно большинство того, что создаётся php artisan make:auth — лишнее.
Если я правильно понял, то в приведённом ниже примере из документации по ручной аутентификации метод attept сверяет данные с данными в таблице users:
public function authenticate(){
if (Auth::attempt(['email' => $email, 'password' => $password])) {
// Аутентификация успешна
return redirect()->intended('dashboard');
}
}
Если так, то встаёт вопрос — а как же сверять данные с какой-либо другой таблицей? Я уже посмотрел имеющиеся ответы на этот вопрос, и везде показывали, как эту таблицу менять глобально. Я хочу оставить таблицу users и в одних случаях сверять данные с этой таблицы, но в других — с другой таблицей.
Предвижу ответ: «Локально указаться таблицу при конструировании запроса невозможно». Если так, то хорошо, не критично: сравнить данные можно и без Auth::attempt, и я уже это реализовал. А вопрос такой: как теперь вручную проверять, авторизован ли пользователь, если до этого фасад Auth вообще не использовался?
У Вас наверняка возникнет вопрос, что я такое вытворяю, для чего всё это. Задача специфическая; не готов утверждать, что выбрал лучший путь. У меня две аутентификации: одна для админов, которая даёт доступ к админ-панели, другая — для заказчиков, которая даёт доступ к его сайту, находящемуся в процессе разработки и временно являющегося частью моего сайта. Может, это можно реализовать и через авторизацию, но эти две аутентификации совершенно для разных целей и для каждой аутентификации необходимы разные наборы данных (отсюда — две таблицы под каждую идентификацию). Например, у каждого заказчика есть поле в БД «номер заказа» — администратору такое поле незачем.
Даже если и можно, то едва ли это будет менее трудозатратно, чем добавить дополнительный сайт в виде группы новых маршрутов. Кстати говоря, только задумался: для вложенного сайта-то динамическая часть не нужна! В случае сайта-портфолио достаточно показать вёрстку. Так что на добавлении новой группы запросов разработка серверной части портфолио-сайта практически закончится.
Я бы хотел создать свой личный сайт на Laravel, при этом он будет себя включать портфолио - другие сайты, которые сделаны тоже на движке Laravel.
Можно сразу ссылаться на опубликованные портфолио-сайты, вместо того, чтобы делать их частью своего сайта, но предположим, что они больше недоступны по какой-то причине. Скрыть портфолио-сайт с неактуальной информацией от поисковика в целях дезинформирования посетителей можно, сделав к нему ограниченный доступ, при этом указав для желающих посмотреть портфолио данные аутентификации.
Можно загрузить портфолио-сайты на другие домены, но тогда надо покупать новый домент под каждый сайт и ещё каждый продлевать. Не подходит.
Что же можно сделать, чтобы был Laravel-сайт в Laravel-сайте с минимумом перенастроек? К маршрутизацией, в целом, всё понятно:
gleb-webmaster.ru - корень
gleb-webmaster.ru/portfolio - список портфолио-сайтов
gleb-webmaster.ru/portfolio/website1 - пример главной страницы портфолио-сайта
gleb-webmaster.ru/portfolio/website1/about - пример внутренней страницы портфолио-сайта
Теперь вопрос в том, как организовать файловую структуру. Можно, конечно прописать группу маршрутов gleb-webmaster.ru/portfolio/website1/, но тогда придётся переписывать контроллер с оригинального проекта website1. Если ли более быстрый способ заставить заработать Laravel-проект, вложенный в другой Laravel-проект?
В своих вопросах я уже неоднократно высказывал недовольство в адрес Laravel Elixir и Lavarel Mix, но эксперты Laravel настойчиво рекомендуют использовать именно эти инструменты. В первую очередь я критикую указаные выше инструменты за отсутствия гибкости и сложности в пользовательских настройках. Я думаю, этим инструментам не по зубам то, что я делаю спомощью gulp и webpack, но это лишь мои предположения и я могу ошибаться. В этом вопросе, я бы хотел сравнить Laravel Mix с возможностями нативных gulp и webpack и узнать предел возможностей Laravel Mix.
Далее я приведу настройки, которые использую в своих Laravel-проектах на данный момент (я добавляю в корень проекта собственные package.json и webpack.config.js и далее устанавливаю нативные gulp и webpack). Пожалуйста, перепишите эти настройки в инструкции для Laravel Mix, чтобы эффект от этих инструкций был такой же, как и от моих инструкций; либо открыто заявите, что это невозможно (только уточните, что именно и почему невозможно). Отсутствие ответа на данный вопрос длительное время тоже можно будет расценить как ответ «Laravel Mix это не по зубам…».
Я прекрасно понимаю, что многим лень переписывать эти настройки за бесплатно или просто нет на это времени, но опять же, это повышает вероятность того, что для Laravel Mix эти инструкции будут в случшем случае не слишком проще, а в худшем — гораздо сложнее с внедрением в какие-то конфигурационные файлы Laravel.
var gulp = require('gulp'), pug = require('gulp-pug'), sass = require('gulp-sass'), browserSync = require('browser-sync'), cssnano = require('gulp-cssnano'), autoprefixer = require('gulp-autoprefixer'), rename = require('gulp-rename'), del = require('del'), imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant'), cache = require('gulp-cache'), runSequence = require('run-sequence'), shorthand = require('gulp-shorthand'); gulp.task('default', ['watch']); gulp.task('pug', function() { return gulp.src('resources/assets/pug/*.pug') .pipe(pug({ pretty: true, basedir: 'resources/assets/pug' })) .pipe(gulp.dest('resources/assets')) .pipe(browserSync.reload({stream: true})); }); gulp.task('sass', function(){ return gulp.src('resources/assets/sass/*.+(sass|scss)') .pipe(sass()) .pipe(autoprefixer(['last 15 versions', '> 1%', 'ie 8', 'ie 7'], { cascade: true })) .pipe(gulp.dest('resources/assets/css')) .pipe(browserSync.reload({stream: true})); }); gulp.task('browser-sync', function() { browserSync({ server: { baseDir: 'resources/assets' }, notify: false }); }); gulp.task('watch', ['browser-sync', 'pug', 'sass'], function() { gulp.watch('resources/assets/pug/**/*.pug', ['pug']); gulp.watch('resources/assets/sass/*.+(sass|scss)', ['sass']); gulp.watch('resources/assets/es6/*.js', browserSync.reload); }); // Продакшен gulp.task('Build production', function(){ runSequence( 'Clean previous production build', 'sass', 'Prepare CSS for production', 'Copy Fonts Folder To Production', 'Prepare images for production' ); }); gulp.task('Clean previous production build', function() { return del.sync(['public/css/*.css', 'public/img/**/*']); }); gulp.task('Prepare CSS for production', function(){ return gulp.src('resources/assets/css/*.css') .pipe(shorthand()) .pipe(cssnano()) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('public/css')); }); gulp.task('Copy Fonts Folder To Production', function(){ return gulp.src('resources/assets/fonts/**/*') .pipe(gulp.dest('public/fonts')); }); gulp.task('Prepare images for production', function() { return gulp.src('resources/assets/img/**/*') .pipe(cache(imagemin({ interlaced: true, progressive: true, svgoPlugins: [{removeViewBox: false}], use: [pngquant()] }))) .pipe(gulp.dest('public/img')); }); gulp.task('Clear cash', function () { return cache.clearAll(); });
В папке resources/assets/pug находятся файлы препроцессора pug, которые компилируются в .html и помещаются в resources/assets.
gulp.task('pug', function() { return gulp.src('resources/assets/pug/*.pug') .pipe(pug({ pretty: true, basedir: 'resources/assets/pug' })) .pipe(gulp.dest('resources/assets')) .pipe(browserSync.reload({stream: true})); });
gulp-таск по умолчанию после выполнения других тасков (в т. ч. pug и sass) открывает файл index.html. Это лишь вёрстка; превращение её в шаблоны blade — это уже следующий этап. Как сказал мастер constb в вопросе [https://laravel.ru], Настройка средств front-end разработки без использоваия elixir,
Вполне можно разрабатывать на одной кодовой базе сразу и бэкенд и фронт
с тех пор я увлёкся организацией разработки фронтэнда и бэкэнда на одной базе.
* В папке resources/assets/sass находятся файлы расширения .scss, которые при development-сборке компилируются в resources/assets/css с добавлением вендорных префиксов, а при production-сборке — компилируются, минифицируются, оптимизируются (gulp-shorthand) и выкладываются в public/css:
gulp.task('sass', function(){ return gulp.src('resources/assets/sass/*.+(sass|scss)') .pipe(sass()) .pipe(autoprefixer(['last 15 versions', '> 1%', 'ie 8', 'ie 7'], { cascade: true })) .pipe(gulp.dest('resources/assets/css')) .pipe(browserSync.reload({stream: true})); }); gulp.task('Prepare CSS for production', function(){ return gulp.src('resources/assets/css/*.css') .pipe(shorthand()) .pipe(cssnano()) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('public/css')); });
* Таск Prepare images for production сжимает изображения и выкладывает их в public/img, а Copy Fonts Folder To Production просто копирует шрифты в public/fonts.
* Функция runSequence, которая используется в таске Build production, требует новейшие версии gulp.
Вообще gulp-таски не хорошо писать в несколько слов с пробелами, но я противник запоминания консольных комманд, а среда NetBeans позволяет запускать нужные таски без консоли, так что я могу отдавать предпочтение хотя и длинным, но понятным именам задач.
За всё, что связино с JavaScript, отвечает webpack. Исходники находится в папке es6.
const NODE_ENV = process.env.NODE_ENV || 'development'; const webpack = require('webpack'); const output_path = NODE_ENV === 'production' ? (__dirname + '/public/js'): (__dirname + '/resources/assets/js'); module.exports = { context: __dirname + '/resources/assets/es6', entry: { top: './top.js', about: './about.js' }, output: { path: output_path, filename: '[name].js' }, watch: NODE_ENV === 'development', watchOptions: { aggregateTimeout: 100 }, devtool: NODE_ENV === 'development' ? 'cheap-inline-module-source-map' : false, resolve : { alias: { "jquery-ui": "jquery-ui-dist/jquery-ui.js" }, extensions: ['.js', '.jsx', '.json', '*'] }, module: { rules: [ { test: [ /\.jsx?$/ ], exclude: /node_modules/, use: [ 'babel-loader' ] } ] }, plugins: [ new webpack.ProvidePlugin({ jQuery: "jquery", $: "jquery" }) ] }; if (NODE_ENV === 'production') { module.exports.plugins.push( new webpack.optimize.UglifyJsPlugin({ beautify: NODE_ENV === 'development' ? true : false, mangle: { screw_ie8: true, keep_fnames: true }, compress: { screw_ie8: true }, comments: false }) ); }
* При development сборке es6 (но расширение тоже .js) конвертируется в JavaScript стандарта es5, происходит сборка модулей в файлы точек входа и они помещаются в /resources/assets/js
* При production-сборке происходит также минификация js-файлов, а затем они они отправляются в public/js.
На данный момент я пока запускаю gulp и webpack отдельно, потому что ещё не решил задачу интеграции gulp и свежей версии webpack, но работаю над этим. Если всё получится, то отдельный запуск webpack и файл webpack.config.js станут ненужными.
Оффтоп, но я хочу знать, почему это плохая идея и почему в коммерческих сайтах надо использовать встроенные средства.
Я одно время хотел использовать Laravel Mix, но тут же оказалось, что он совершенно лишён гибкости и крайне плохо кастомизируем. Я приведу ниже свои настройки для gulp и webpack, которые на данный момент использую в Laravel-проектах, но по своей методике, то есть с самостоятельной настройкой нативных gulp и webpack . Вот скажите: с помощью Laravel Mix я могу так же гибко всё настроить?
gulpfule.js
var gulp = require('gulp'),
pug = require('gulp-pug'),
sass = require('gulp-sass'),
browserSync = require('browser-sync'),
cssnano = require('gulp-cssnano'),
autoprefixer = require('gulp-autoprefixer'),
rename = require('gulp-rename'),
del = require('del'),
imagemin = require('gulp-imagemin'),
pngquant = require('imagemin-pngquant'),
cache = require('gulp-cache'),
runSequence = require('run-sequence'),
shorthand = require('gulp-shorthand');
gulp.task('default', ['watch']);
gulp.task('pug', function() {
return gulp.src('resources/assets/01_pug/*.pug')
.pipe(pug({
pretty: true,
basedir: 'resources/assets/01_pug'
}))
.pipe(gulp.dest('resources/assets'))
.pipe(browserSync.reload({stream: true}));
});
gulp.task('sass', function(){
return gulp.src('resources/assets/02_sass/*.+(sass|scss)')
.pipe(sass())
.pipe(autoprefixer(['last 15 versions', '> 1%', 'ie 8', 'ie 7'], { cascade: true }))
.pipe(gulp.dest('resources/assets/css'))
.pipe(browserSync.reload({stream: true}));
});
gulp.task('browser-sync', function() {
browserSync({
server: {
baseDir: 'resources/assets'
},
notify: false
});
});
gulp.task('watch', ['browser-sync', 'pug', 'sass'], function() {
gulp.watch('resources/assets/01_pug/**/*.pug', ['pug']);
gulp.watch('resources/assets/02_sass/*.+(sass|scss)', ['sass']);
gulp.watch('resources/assets/03_es6/*.js', browserSync.reload);
});
// === Production Build
gulp.task('Build production', function(){
runSequence( 'Clean previous production build',
'sass', 'Prepare CSS for production',
'Copy Fonts Folder To Production',
'Prepare images for production'
);
});
gulp.task('Clean previous production build', function() {
return del.sync(['public/css/*.css', 'public/img/**/*']);
});
gulp.task('Prepare CSS for production', function(){
return gulp.src('resources/assets/css/*.css')
.pipe(shorthand())
.pipe(cssnano())
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest('public/css'));
});
gulp.task('Copy Fonts Folder To Production', function(){
return gulp.src('resources/assets/fonts/**/*')
.pipe(gulp.dest('public/fonts'));
});
gulp.task('Prepare images for production', function() {
return gulp.src('resources/assets/img/**/*')
.pipe(cache(imagemin({
interlaced: true,
progressive: true,
svgoPlugins: [{removeViewBox: false}],
use: [pngquant()]
})))
.pipe(gulp.dest('public/img'));
});
gulp.task('Clear cash', function () {
return cache.clearAll();
});
webpack.config.js
'use strict';
const NODE_ENV = process.env.NODE_ENV || 'development';
const webpack = require('webpack');
const output_path = NODE_ENV === 'production' ?
(__dirname + '/public/js'):
(__dirname + '/resources/assets/js');
module.exports = {
context: __dirname + '/resources/assets/03_es6',
entry: {
index: './01indexEP.js',
about: './02aboutEP.js',
business: './03businessEP.js',
feedback: './05feedbackEP.js'
},
output: {
path: output_path,
filename: '[name].js'
},
watch: NODE_ENV === 'development',
watchOptions: {
aggregateTimeout: 100
},
devtool: NODE_ENV === 'development' ? 'cheap-inline-module-source-map' : false,
resolve : {
alias: {
"jquery-ui": "jquery-ui-dist/jquery-ui.js"
},
extensions: ['.js', '.jsx', '.json', '*']
},
module: {
rules: [
{
test: [
/\.jsx?$/
],
exclude: /node_modules/,
use: [
'babel-loader'
]
}
]
},
plugins: [
new webpack.ProvidePlugin({
jQuery: "jquery",
$: "jquery"
})
]
};
if (NODE_ENV === 'production') {
module.exports.plugins.push(
new webpack.optimize.UglifyJsPlugin({
beautify: NODE_ENV === 'development' ? true : false,
mangle: {
screw_ie8: true,
keep_fnames: true
},
compress: {
screw_ie8: true
},
comments: false
})
);
}
Правильно ли я понял, что функция-хелпер asset(), использующаяся в шаблонизаторе Blade, просто заменяет относительный путь на абсолютный, при этом никакого отношения к папке assets не имеет?
Каково назначение папки assets (resources/assets)?
Я знаю, что в только что собранном проекте там находятся стили и JS-код по умолчанию, который Laravel Mix компилирует в выдаёт в папку public.
Теперь предположим, что я по какой-то причине не хочу использовать Laravel Mix и не хочу держать стили и js в assests - долго до них добираться + интуитивно непонятное назначение папки по её названию. Я подумываю вообще удалить папку assets, а все исходники (HTML-вёрстку, SASS, JS и прочее) хранить в папке frontend, которая находится в корневом каталоге проекта (такое имя папки лучше соответствует её содержимому). Development и prodution-сборку стилей и JS в public с помощью gulp и webpack я могу настроить самостоятельно без использования Laravel-mix.
Будут ли в этом случае какие-либо отрицательные последствия, если я удалю папку assets?
Благодарю Вас за ответ!
А так нормально будет с точки зрения SEO?
[url]http://example.com/ru/somepage[/url]
[url]http://example.com/en/somepage[/url]
[url]http://example.com/zh/somepage[/url]
В шаблоны каких страниц следует добавлять в <head> нижеследующий код?
<meta name="csrf-token" content="{{ csrf_token() }}">
Я видел, что такой код есть в шаблонах аутентификации пользователей вдобавок к csrf-полю.
Достаточно ли для автоматического определения локали добавить тэгу html атрибут lang="{{ app()->getLocale() }}? Или же нужно ещё какие-то настройки прописать, чтобы локаль автоматически определялась?
И ещё: как протестировать с локального сервера корректное определение для каждой локали? Естественно, что будет отображаться тот язык, который соответствует главной локали, указанной в config/app.php, но как проверить корректность отображения страниц с другими локалями?
Предполагается, что на сайте доступно более двух языков (то есть помимо основной и fallback локалей есть и другие).
Только что прочитал про основы работы с локализацией в Laravel. С короткими сообщениями всё понятно: создаём соловарь, в нём создаём ассоциативный массив, и переводим на нужный язык (ну или берём готовые словари). А что же делать с длинными фрагментами текста, которые, возможно, будут содержать большое количество HTML-тегов? Куда лучше поместить их переводы и как с ними работать? Полагаю, что хранить мы их будет не в ассоциативныом массиве...
Допустим, я не хочу использовать стандартный механизм регистрации пользователей, поскольку не предполагается, что среди пользователей (администраторов) будет больше двух человек. Таким образом, мне не нужен view для регистрации и RegisterController, а добавление пользователей в базу данных нужно будет сделать вручную. Ничего сложного, только непонятно, как правильно захэшировать пароль, то есть сделать это такими же способом, как Laravel. Какой тип хэширования использует метод bcrypt()? md5?