Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
День добрый! Программирую давно, а ларавель, как и ООП-подход начал изучать недавно. Собственно, и в мир "большого" программирования еще на стадии вливания. Прошу не кидать камнями за, возможно, глупый вопрос, ответ на который я наверняка искал недостаточно усердно.
К делу.
Есть проект по сбору и обработке информаци из СМС сообщений. Не буду вдаваться в ненужные подробности о проекте, перейду сразу к сути.
Задача реализовать загрузку СМС сообщений в мою базу в таблицу 'sms'. MVC осваивать начал только с ларавелем, поэтому некоторые моменты еще не ясны. Итак, есть таблица, к ней приделана модель 'Sms'. Работа с таблицей осуществляется через эту модель и через 'SmsController'. Их задачи, в целом, понятны. Модель нужна для взаимодейстия таблицей, как с объектом, а контроллер для взаимодействия с таблицей уже через модель. Вроде верно. Поправьте если не так.
Так как смс приходят много, то они требуют постоянной подгрузки. Посему был создан еще один контроллер с названием "SmsUpdateController", который является неким центром, через который отрабатывает весь механизм загрузки. В нем мною определен основной метод main(), который отрабатывает по запросу через роутинг (потом посажу на крон). И все бы хорошо. Да вот проблема.
Я рассматриваю само смс-сообщение, как объект с полями 'text', 'sender', 'receiver' и 'datetime'. Собственно, они же и есть в таблице. Поэтому мне кажется логичным создать класс Sms, описывающий объект смс и "строчку" из таблицы. Мой коллега так не считает и предланает использовать ассоциативный массив и передввать его на всех циклах отработки загрузочного модуля. Я считаю это нелогичным, а посему решил все-таки создать класс Sms... и тут начплись проблемы.
Куда его прописывать? Создать папку Library в App? А как правильно подключить класс? Очень не хочется его втупую инклудить через 'use'. Может можно его как-то подгружать автоматически, чтоб он был виден автоматом везде в папке 'Controllers'. Или я ошибаюсь и так делать не нужно вовсе? Вообще и далее по ходу разработки понпдобятся собственные классы. Например, класс с регулярками для разбора смс хотел вынести в отдельный и подключать его в посредник-фильтер.
Вопрос на засыпку, стоит ли хранить системную информацию об объекте смс в отдельной таблице sms_meta? Или же пару лишних полей не испортят таблицу sms?
Изменено Remover_4000_pro (04.02.2020 01:22:11)
Не в сети
Версия laravel 5.2
Не в сети
Решено.
Не в сети
Приветствую.
Модель нужна для взаимодейстия таблицей, как с объектом, а контроллер для взаимодействия с таблицей уже через модель. Вроде верно. Поправьте если не так.
Лучше сделать немного не так.
Контроллер сделать тонким, а всю логику переложить в реп, который уже будет вызвать нужные ему модели бд. Т.е. примерно так:
/App/Http/Controllers/Frontend/SmsController.php:
<?php
namespace App\Http\Controllers\Frontend;
use App\Repositories\Frontend\SmsRepository;
class SmsController extends WebController
{
/**
* Конструктор
*
* @param SmsRepository $model
*/
public function __construct(SmsRepository $model)
{
$this->model = $model;
parent::__construct();
}
}
/App/Repositories/Frontend/SmsRepository.php:
namespace App\Repositories\Frontend;
use App\Models\db\dbSms;
class SmsRepository extends OptionsRepositary
{
//основная логика работы приложения
}
Более подробно о таком подходе см тут же на сайте, в разделе "Хорошие практики Laravel"
Так как смс приходят много, то они требуют постоянной подгрузки. Посему был создан еще один контроллер с названием "SmsUpdateController"
Вот тут ниче не понял. Зачем был создан еще один контроллер? Чем один не подошел? Что значит "много"?
Тут нужно сделать отступление и указать на не вполне очевидную, но задокументированную вещь: в Laravel искаропки есть ресурс-контроллеры, которые можно использовать в роутах напрямую, вот так:
Route::resources([
'sms' => 'SmsController',
]);
При этом в самом SmsController могут быть(а могут и нет) реализованы следующие методы: ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy']
Это значит, что к одному и тому же контроллеру при разных способах обращения (GET, POST, DELETE..) будут вызываться разные методы. Поэтому совсем необязательно(а я считаю, что и вредно) создавать колхоз со всякими там public function setValueOnUpdate с последующим прописанием этого пути в роутер. Вышеуказанных методов более чем достаточно, если нет, то Вы делаете что то не торт.
В нем мною определен основной метод main()
ну вот как раз, то, что я писал выше...
предланает использовать ассоциативный массив и передввать его на всех циклах отработки загрузочного модуля
Из описания ничего не понятно, что за массив, что за циклы отработки, что за загрузка...
У ларавель есть несколько способов работы с долгими задачами - например очереди, но если у Вас некий центр обработки, в котором пришедшая смс должна пройти по разным стадиям в разных обработчиках, то более разумно использовать Enent:
$sms = new dbSms;
$sms->fill($data);
$sms->save();
Event::fire(new SMSEvent($sms));
при этом все слушатели события SMSEvent получат экземпляр dbSms в качестве сообщения.
Куда его прописывать? Создать папку Library в App?
Модели бд обычно прописываются в App/Models/db например... Library - это другое, тут обычно находятся общие библиотеки, ну например какие то парсеры, методы вычисления углов по пятнам на Солнце итп.
А как правильно подключить класс?
В наш то просвещенный век уже есть PSR-2, который описывает как именно именовать классы через наймспейсы.
<?php
namespace App\Models\db;
use Illuminate\Database\Eloquent\Model
class dbSms extends Model
{
//необязательно, имя таблицы подставится из имени класса
protected $table = 'sms';
}
Затем, там где надо используешь
use App\Models\db\dbSms;
Вообще и далее по ходу разработки понпдобятся собственные классы. Например, класс с регулярками для разбора смс
вот ему самое место в Library
стоит ли хранить системную информацию об объекте смс в отдельной таблице sms_meta? Или же пару лишних полей не испортят таблицу sms?
В mySql есть замечательное поле типа Json. Нет никакой необходимости создавать еще одну таблицу(это вообще то лишняя нагрузка на бд), можно просто создать поле.
Не в сети
Приветствую.
Благодарю за ответ! Информации много, а дельную отличать все еще сложно. Ответы людей для меня на вес золота.
SmsController я задумывал как контроллер, включающий в себя только методы работы с таблицей sms. Загрузить, выгрузить и т.п. SmsUpdaterController же должен являться некой общей точкой с логикой именно для загрузки новых смс. Смс берутся с чужой базы с доступом на чтение. Как правильно к ней подключаться пока не знаю, но предполагаю, что придется создавать отдельную модель под чужую таблицу. Если есть что посоветовать, то с радостью приму совет к сведению.
Далее
Немного о смысле программы. Сами смс - не цель. Цель - информация в них. Она шаблонна и требует фильтра на регулярках. Без последних никак не обойтись. Проходя через фильтр, информация сортируется и записывается в другую таблицу, которая одна для всех типов информации.
Идея в том, чтобы разделить цикл от получения смс до ее обработки на несколько этапов, где будут отрабатывать свои контроллеры. Первый этап - загрузка СМС в базу. Второй - обработка. Контроллер обработки берет необработанные СМС из соответствующей таблицы, пропускает через фильтр и записывает информацию в другую таблицу.
Как и на первом, так и на втором этапе нужен доступ к таблице sms, соответственно и контроллер работы с ней. То, что я вынес логику первого этапа в отдельный контроллер обусловлено разделением обязанностей контроллеров.
Ваше замечание по этому я понял. Видимо, я не до конца понимаю смысл контроллеров и моделей. Поэтому вынес логику в отдельные контроллеры.
Буду благодарен за объяснения своих недочетов и промахов. Вот то, что есть на данном этапе разработки:
class SmsController extends Controller
{
public static function getById($id) {
}
public static function insert($sms) {
Sms::insert($sms);
}
}
class SmsUpdater extends Controller
{
public function main() {
// получаем лист с новыми смс
$smsList = OtherDBController::getSmsList();
// передаем лист смс в контроллер работы с базой и записываем новые смс
SmsController::insert($smsList);
}
}
class OtherDBController extends Controller
{
public static function getSmsList() {
$smsList;
$sms1 = ['text'=>'Sms text 1', 'sender'=>'Sms sender 1', 'receiver'=>'Sms receiver 1', 'dateTime'=>'2020-02-19 12:08:05'];
$smsList[] = $sms1;
$sms2 = ['text'=>'Sms text 2', 'sender'=>'Sms sender 2', 'receiver'=>'Sms receiver 2', 'dateTime'=>'2020-02-19 12:08:05'];
$smsList[] = $sms2;
$sms3 = ['text'=>'Sms text 3', 'sender'=>'Sms sender 3', 'receiver'=>'Sms receiver 3', 'dateTime'=>'2020-02-19 12:08:05'];
$smsList[] = $sms3;
return $smsList;
}
}
class Sms extends Model
{
protected $table = 'sms';
protected $primaryKey = 'id';
public $incrementing = 'id';
}
Не в сети
Приветствую.
Могу ли написать Вам в ЛС и немного у вас проконсультироваться по поводу построения логики работы приложения?
Не в сети
Как правильно к ней подключаться пока не знаю,
изи.. как обычно
config/database.php:
//основная
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'homestead'),
'username' => env('DB_USERNAME', 'homestead'),
'password' => env('DB_PASSWORD', 'homestead'),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
],
//"внешняя"
'mysql2' => [
'driver' => 'mysql',
'host' => env('DB_HOST_EXT', '127.0.0.1'),
'port' => env('DB_PORT_EXT', '3306'),
'database' => env('DB_DATABASE_EXT', 'homestead'),
'username' => env('DB_USERNAME_EXT', 'homestead'),
'password' => env('DB_PASSWORD_EXT', 'homestead'),
'unix_socket' => env('DB_SOCKET_EXT', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'prefix_indexes' => true,
'strict' => true,
'engine' => null,
],
.env
DB_HOST_EXT=127.0.0.1
DB_DATABASE_EXT=mysqlbase
DB_USERNAME_EXT=login
DB_PASSWORD_EXT=pass
ну и в модели
class SomeModel extends Eloquent {
protected $connection = 'mysql2';
}
Изменено nailfor (06.02.2020 15:17:05)
Не в сети
SmsUpdaterController же должен являться некой общей точкой с логикой именно для загрузки новых смс.
Тогда имеет смысл перенести его в Console\Command и вызывать из командной строки ./artisan sms:import
Идея в том, чтобы разделить цикл от получения смс до ее обработки на несколько этапов, где будут отрабатывать свои контроллеры.
Для этого придуманы события (Event). Пример вызова из контроллера(или репа):
Event::fire(new SMS($dbSms));
Потребуется описать слушателей (Listeners) события SMS в EventServiceProvider:
SMS::class => [
listen1::class,
listen2::class,
listen3::class,
...
],
подробно про события тут
Но возможно я неправильно понял задачу и здесь более подойдут очереди.
Дело в том, что события передают всем слушателям один и тот же объект dbSms, а в очередях можно создавать задачи разным очередям и модифицировать информацию из одной задачи в другую.
Видимо, я не до конца понимаю смысл контроллеров и моделей. Поэтому вынес логику в отдельные контроллеры.
попробую на трех пальцах...
Запрос(Request) - специальный класс, в котором прописывается валидация входных данных
Контроллер - принимает подготовленный запрос и передает его в реп. Контроллер определяет какие именно методы HTTP доступны этому конкретному ресурсу (GET, POST, DELETE..)
Репозитарий - промежуточная модель, консолидирующая модели к БД, логику, какие то вызовы внешнего апи, все что угодно в общем. Данные из репа возвращаются в контроллер
Вьюха(view) - ответ системы. Может быть бинарной, текстовой(html, json, cvs..). Для преобразования данных в json хорошо подходят Resources
Не в сети
Да, все понятно. Здесь, наверное, логичнее использовать очереди. Пойду в них. Спасибо за помощь!
Не в сети