Laravel по-русски

Русское сообщество разработки на PHP-фреймворке Laravel.

Ты не вошёл. Вход тут.

#1 04.02.2020 01:08:27

Работа с базой и объекты. Куда прописать свои классы?

День добрый! Программирую давно, а ларавель, как и ООП-подход начал изучать недавно. Собственно, и в мир "большого" программирования еще на стадии вливания. Прошу не кидать камнями за, возможно, глупый вопрос, ответ на который я наверняка искал недостаточно усердно.

К делу.

Есть проект по сбору и обработке информаци из СМС сообщений. Не буду вдаваться в ненужные подробности о проекте, перейду сразу к сути.

Задача реализовать загрузку СМС сообщений в мою базу в таблицу '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)

Не в сети

#2 04.02.2020 11:36:26

Re: Работа с базой и объекты. Куда прописать свои классы?

Версия laravel 5.2

Не в сети

#3 05.02.2020 11:31:49

Re: Работа с базой и объекты. Куда прописать свои классы?

Решено.

Не в сети

#4 05.02.2020 12:09:06

Re: Работа с базой и объекты. Куда прописать свои классы?

Приветствую.

Модель нужна для взаимодейстия таблицей, как с объектом, а контроллер для взаимодействия с таблицей уже через модель. Вроде верно. Поправьте если не так.

Лучше сделать немного не так.
Контроллер сделать тонким, а всю логику переложить в реп, который уже будет вызвать нужные ему модели бд. Т.е. примерно так:
/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. Нет никакой необходимости создавать еще одну таблицу(это вообще то лишняя нагрузка на бд), можно просто создать поле.

Не в сети

#5 06.02.2020 12:33:49

Re: Работа с базой и объекты. Куда прописать свои классы?

Приветствую.

Благодарю за ответ! Информации много, а дельную отличать все еще сложно. Ответы людей для меня на вес золота.

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';

}

Не в сети

#6 06.02.2020 13:51:50

Re: Работа с базой и объекты. Куда прописать свои классы?

Приветствую.

Могу ли написать Вам в ЛС и немного у вас проконсультироваться по поводу построения логики работы приложения?

Не в сети

#7 06.02.2020 15:16:03

Re: Работа с базой и объекты. Куда прописать свои классы?

Как правильно к ней подключаться пока не знаю,

изи.. как обычно
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)

Не в сети

#8 06.02.2020 15:36:28

Re: Работа с базой и объекты. Куда прописать свои классы?

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

Не в сети

#9 06.02.2020 15:57:31

Re: Работа с базой и объекты. Куда прописать свои классы?

Да, все понятно. Здесь, наверное, логичнее использовать очереди. Пойду в них. Спасибо за помощь!

Не в сети

Подвал раздела