Русское сообщество разработки на PHP-фреймворке Laravel.
Ты не вошёл. Вход тут.
Ну во первых, all() возвращает коллекцию, а вы к коллекции как к объекту обращаетесь ниже в коде.
Во вторых сделайте нормальное название связей.
// Product model
public function categories()
{
return $this->belongsToMany(Category::class);
}
$products = Product::query()->whereHas('categories', function($q) use ($arr) {
$q->whereIn('categories.id', $arr);
})->get();
Распишите по подробнее таблицы. Не совсем понятно.
Таблица users
Таблица user_logins
При реге: создаете пользователя, затем заносите в user_logins тел пользователя / ид пользователя и код.
При авторизации: Делаете тоже самое с user_logins что и при реге.
Подтверждение: в user_logins находите по коду запись. По этой записи получаете пользователя. И авторизовываете его.
Можно еще добавить некий флаг в user_logins подтвержден код или нет. И запрос по времени created_at был не больше n минут к примеру
Однозначно второй вариант. На локалке протестить. И потом на сервер. А на сервере уже собирать.
То что вы хотите сделать называется OTP.
Вот пример реализации https://tighten.co/blog/creating-a-pass … in-laravel
Только в примере используется email
public function getSummaAttribute($value)
{
return number_format($value, 2, ',', ' ');
}
Вариант с компонентом возможно тут самый подходящий. Но если будет форм с отличающимся шаблоном (форма с табами к примеру), то придется либо опять компонент делать либо уже просто хтмл ее оставить.
Я для себя написал небольшой билдер (таблицы, формы, табы, чарты…), так как приходилось много проектов с идентичным функционалом делать
- На PHP вполне нормально реализуются долгоживущие парсеры. У самого PHP утечек нет, у меня бывали и бывают процессы, которые стартуют с ОС и работают, пока не перезагрузишь. Это именно проблема (или «нецелевое использование» — как угодно) Laravel. В твоем случае достаточно переписать пару мест на «более голый» PHP (степень «голости» зависит от тебя). Python — это слишком радикальное решение, ИМХО.
Дня 2 назад опять занялся этой задачей. И в итоге вроде нашел в чем проблема.
[2019-12-29 13:10:59] local.INFO: Parsing Started
17.52 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:10:59] local.INFO: Add content to crawler
17.54 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Content added
17.54 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Links found
17.63 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Found 498 links
17.62 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Unique 3 links
17.92 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Links saved
17.86 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Crawler cleaned
17.84 mb
this 592| manager591| link 1156| log 594
[2019-12-29 13:11:01] local.INFO: Begin recursive
17.9 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:05] local.INFO: Parsing Started
17.9 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:05] local.INFO: Add content to crawler
17.92 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:06] local.INFO: Content added
17.93 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:06] local.INFO: Links found
18.01 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:06] local.INFO: Found 499 links
18.01 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:07] local.INFO: Unique 7 links
18.3 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:07] local.INFO: Links saved
18.24 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:07] local.INFO: Crawler cleaned
18.22 mb
this 592| manager591| link 1359| log 594
[2019-12-29 13:11:07] local.INFO: Begin recursive
18.28 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:12] local.INFO: Parsing Started
18.28 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:12] local.INFO: Add content to crawler
18.3 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Content added
18.31 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Links found
18.41 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Found 498 links
18.4 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Unique 5 links
18.69 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Links saved
18.63 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Crawler cleaned
18.62 mb
this 592| manager591| link 1597| log 594
[2019-12-29 13:11:13] local.INFO: Begin recursive
18.68 mb
this 592| manager591| link 1835| log 594
Если смотреть на id после памяти, то объект ссылки пересоздается (судя по id). Ну это и понятно, так как идут запросы вида
// Модель Link.php
/**
* Get first pending link
*
* @return mixed
*/
public function getFirstPending()
{
return $this->oldest()
->where([
'state' => self::PENDING
])
->first();
}
/**
* Set parsed state
*
* @return mixed
*/
public function setParsed()
{
return $this->update([
'state' => self::PARSED
]);
}
/**
* Set failed state
*
* @return mixed
*/
public function setFailed()
{
return $this->update([
'state' => self::FAILED
]);
}
Ну а там внутри (в самих методах модели) newEloquentBuilder() которые и порождают новые объекты, которые скорее всего не умирают после отработки, а висят в памяти.
- В конце концов, «whereIn()->pluck()» это тот же PDO + array_column(), 2-3 строчки максимум.
- Видимо, здесь и утекает. В Laravel ногу сломишь, пока поймешь, где, что и кто не очистил (я еще в L3 находил утечки, даже Тейлору писал, а L3 был на порядок проще того, что сейчас), поэтому попробуй переписать этот кусок в виде сырого запроса, благо он у тебя простой. Если это не поможет — тогда попробуй и вовсе его закомментировать и заменить на чтение данных из файла (просто для тестов) через json_decode(file_get_contents()) или require() (если данные в виде PHP-кода — var_export()). Если действительно утечка здесь, то после замены память будет в норме, сколько бы итераций не прошло
- Много файлов за 0 лет работы скопилось?
Ыть, очепятолся. За 10 лет))
Эти все файлы были раньше базой в лотусе (таможенная софтина для учета экспортеров / импортеров). По сути, тот же ексель, только в своем формате. Ну, и кто то решил, что удобно будет экспортировать все в html таблицы…
- А чего ты хотел, Laravel оптимизированным по памяти никак не назовешь, с его кучей прокладок и фасадов. Он хорош в отдельно взятой области — обработке запросов от клиента. В этом плане никакие утечки не страшны, потому что в типичном запросе GC может вообще не вызываться, запрос быстро отработал и всю память собрали принудительно. А у тебя, видимо, тысячи объектов, и ты при этом хочешь плюшки Laravel в виде коллекций и ORM… Не, так не бывает
Крайняк, если не решу проблему, то на питоне все сделаю
Proger_XP, спасибо за помощ!
Незнаю как теперь быть, так как файлов еще очень много (помимо этих 10к). Эти все файлы за 0 лет работы скопились.
Хотел что бы какой нибудь из продаванов нажал пару кнопок, скрипт в очередь встал, и забыть про него.
Но теперь блин придется по ходу следить, или использовать шедулер что бы заного процесс запускать когда память сядит…
- А какой лимит по памяти у процесса (memory_limit)?
memory_limit = 1536M
Когда использовались коллекции, и память до 1.56 гб доходила. Процесс падал с 500 ошибкой и месагой *out of mamory limit…* ну это и понятно
- Попробуй gc_collect_cycles();
Ниже второй код с его использованием. разницы нет.
- Сравни с memory_get_usage(false).
// memory_get_usage(false)
[2019-12-26 10:56:45] local.INFO: Parsing Started
17.31 mb
[2019-12-26 10:56:45] local.INFO: Add content to crawler
17.36 mb
[2019-12-26 10:56:46] local.INFO: Content added
17.37 mb
[2019-12-26 10:56:46] local.INFO: Links found
17.44 mb
[2019-12-26 10:56:46] local.INFO: Found 484 links
17.45 mb
[2019-12-26 10:56:46] local.INFO: Unique 0 links
17.71 mb
[2019-12-26 10:56:46] local.INFO: Links saved
17.67 mb
[2019-12-26 10:56:46] local.INFO: Crawler cleaned
17.65 mb
[2019-12-26 10:56:46] local.INFO: Begin recursive
17.71 mb
...
[2019-12-26 11:03:08] local.INFO: Parsing Started
37.4 mb
[2019-12-26 11:03:08] local.INFO: Add content to crawler
37.42 mb
[2019-12-26 11:03:10] local.INFO: Content added
37.42 mb
[2019-12-26 11:03:10] local.INFO: Links found
37.5 mb
[2019-12-26 11:03:10] local.INFO: Found 486 links
37.49 mb
[2019-12-26 11:03:10] local.INFO: Unique 0 links
37.76 mb
[2019-12-26 11:03:10] local.INFO: Links saved
37.72 mb
[2019-12-26 11:03:10] local.INFO: Crawler cleaned
37.7 mb
[2019-12-26 11:03:10] local.INFO: Begin recursive
37.69 mb
// memory_get_usage(false) + gc_collect_cycles();
[2019-12-26 11:05:09] local.INFO: Parsing Started
17.14 mb
[2019-12-26 11:05:09] local.INFO: Add content to crawler
17.16 mb
[2019-12-26 11:05:11] local.INFO: Content added
17.16 mb
[2019-12-26 11:05:11] local.INFO: Links found
17.24 mb
[2019-12-26 11:05:11] local.INFO: Found 487 links
17.24 mb
[2019-12-26 11:05:11] local.INFO: Unique 0 links
17.51 mb
[2019-12-26 11:05:11] local.INFO: Links saved
17.47 mb
[2019-12-26 11:05:11] local.INFO: Crawler cleaned
17.45 mb
[2019-12-26 11:05:11] local.INFO: Begin recursive
17.51 mb
...
[2019-12-26 11:12:31] local.INFO: Parsing Started
38.64 mb
[2019-12-26 11:12:31] local.INFO: Add content to crawler
38.66 mb
[2019-12-26 11:12:34] local.INFO: Content added
38.66 mb
[2019-12-26 11:12:34] local.INFO: Links found
38.74 mb
[2019-12-26 11:12:34] local.INFO: Found 480 links
38.74 mb
[2019-12-26 11:12:34] local.INFO: Unique 0 links
39 mb
[2019-12-26 11:12:34] local.INFO: Links saved
38.9 mb
[2019-12-26 11:12:34] local.INFO: Crawler cleaned
38.88 mb
[2019-12-26 11:12:34] local.INFO: Begin recursive
38.93 mb
- Точнее сказать нельзя, потому что не известно, что там в getMissed()
Ну тут обычный запрос в бд, что бы выбрать уже имеющиеся ссылки, а затем сравнить их со всеми найденными ссылками что бы в итоге получить новые уникальные ссылки которых нет в базе.
Да, метод назван не явно, но тут и скрипт написан на коленке и рефакторинга еще не делал.
/**
* Check if link already exists
*
* @param array $links
* @return mixed
*/
public function getMissed(array $links)
{
return $this->whereIn('link', $links)->pluck('link')->all();
}
Имеется 10к html документов. В них обычные таблицы которые я через symfony dom crawler обхожу в цикле, и забираю нужную инфу.
// Выше в коде
set_time_limit(0);
/**
* Init crawler
*
* @return \Illuminate\Http\Response
* @throws \Exception
*/
public function init()
{
Log::info("Parsing Started \n" . $this->convert(memory_get_usage(true)));
// If no pending links in db
if(is_null($this->link)) {
return Response::make('Success', 200);
}
if($this->link->exists) {
$this->setDocument($this->link->document);
}
try {
Log::info("Add content to crawler \n" . $this->convert(memory_get_usage(true)));
$this->crawler->addHtmlContent($this->loadPage());
Log::info("Content added \n" . $this->convert(memory_get_usage(true)));
$this->searchLinks();
Log::info("Links found \n" . $this->convert(memory_get_usage(true)));
$this->storeParsedLinks();
Log::info("Links saved \n" . $this->convert(memory_get_usage(true)));
$this->clear();
Log::info("Crawler cleaned \n" . $this->convert(memory_get_usage(true)));
$this->writeToLog('Parsing finished');
} catch (\Exception $e) {
$this->writeToLog('ERROR: ' . $e->getMessage());
$this->link->setParsed();
}
$this->link = $this->link->getFirstPending();
Log::info("Begin recursive \n" . $this->convert(memory_get_usage(true)));
$this->init();
}
И вот где мне кажется память утекает судя по логам.
Пришлось этот метод, и метод получения ссылок переписать на чистые php функции для работы с массивами (array_unique(), array_diff(), array_filter()). Так стало улетать по 2мб памяти.
До этого все операции с массивами происходили методами коллекции,и память утекала на 40мб
/**
* Store parsed links to db
*
* @return void
*/
private function storeParsedLinks(): void
{
$links = $this->getLinks();
Log::info("Found " . count($links) . " links \n" . $this->convert(memory_get_usage(true)));
$dbLinks = $this->link->getMissed($links);
$newLinks = array_diff($links, $dbLinks);
Log::info("Unique " . count($newLinks) . " links \n" . $this->convert(memory_get_usage(true)));
foreach ($newLinks as $link) {
$this->link->store($link);
}
}
[2019-12-25 15:01:49] local.INFO: Parsing Started 20 mb [2019-12-25 15:01:49] local.INFO: Add content to crawler 20 mb [2019-12-25 15:01:51] local.INFO: Content added 20 mb [2019-12-25 15:01:51] local.INFO: Links found 20 mb [2019-12-25 15:01:51] local.INFO: Found 480 links 20 mb [2019-12-25 15:01:51] local.INFO: Unique 0 links 20 mb [2019-12-25 15:01:51] local.INFO: Links saved 20 mb [2019-12-25 15:01:51] local.INFO: Crawler cleaned 20 mb [2019-12-25 15:01:51] local.INFO: Begin recursive 20 mb [2019-12-25 15:01:55] local.INFO: Parsing Started 20 mb [2019-12-25 15:01:55] local.INFO: Add content to crawler 20 mb [2019-12-25 15:01:56] local.INFO: Content added 20 mb [2019-12-25 15:01:56] local.INFO: Links found 20 mb [2019-12-25 15:01:56] local.INFO: Found 482 links 20 mb [2019-12-25 15:01:56] local.INFO: Unique 0 links 22 mb [2019-12-25 15:01:56] local.INFO: Links saved 22 mb [2019-12-25 15:01:56] local.INFO: Crawler cleaned 22 mb [2019-12-25 15:01:56] local.INFO: Begin recursive 22 mb [2019-12-25 15:02:02] local.INFO: Parsing Started 22 mb [2019-12-25 15:02:02] local.INFO: Add content to crawler 22 mb [2019-12-25 15:02:04] local.INFO: Content added 22 mb [2019-12-25 15:02:04] local.INFO: Links found 22 mb [2019-12-25 15:02:04] local.INFO: Found 488 links 22 mb [2019-12-25 15:02:04] local.INFO: Unique 3 links 22 mb [2019-12-25 15:02:04] local.INFO: Links saved 22 mb [2019-12-25 15:02:04] local.INFO: Crawler cleaned 22 mb [2019-12-25 15:02:04] local.INFO: Begin recursive 22 mb [2019-12-25 15:02:08] local.INFO: Parsing Started 22 mb [2019-12-25 15:02:08] local.INFO: Add content to crawler 22 mb [2019-12-25 15:02:09] local.INFO: Content added 22 mb [2019-12-25 15:02:09] local.INFO: Links found 22 mb [2019-12-25 15:02:09] local.INFO: Found 488 links 22 mb [2019-12-25 15:02:09] local.INFO: Unique 0 links 22 mb [2019-12-25 15:02:09] local.INFO: Links saved 22 mb [2019-12-25 15:02:09] local.INFO: Crawler cleaned 22 mb [2019-12-25 15:02:09] local.INFO: Begin recursive 22 mb ... // Спустя какое то время память с 20мб до 64 доходит [2019-12-25 15:15:53] local.INFO: Parsing Started 62 mb [2019-12-25 15:15:53] local.INFO: Add content to crawler 62 mb [2019-12-25 15:16:00] local.INFO: Content added 62 mb [2019-12-25 15:16:00] local.INFO: Links found 62 mb [2019-12-25 15:16:00] local.INFO: Found 480 links 62 mb [2019-12-25 15:16:00] local.INFO: Unique 0 links 64 mb [2019-12-25 15:16:00] local.INFO: Links saved 64 mb [2019-12-25 15:16:00] local.INFO: Crawler cleaned 64 mb [2019-12-25 15:16:00] local.INFO: Begin recursive 64 mb [2019-12-25 15:16:04] local.INFO: Parsing Started 64 mb [2019-12-25 15:16:04] local.INFO: Add content to crawler 64 mb [2019-12-25 15:16:06] local.INFO: Content added 64 mb [2019-12-25 15:16:06] local.INFO: Links found 64 mb [2019-12-25 15:16:06] local.INFO: Found 481 links 64 mb [2019-12-25 15:16:06] local.INFO: Unique 0 links 64 mb [2019-12-25 15:16:06] local.INFO: Links saved 64 mb [2019-12-25 15:16:06] local.INFO: Crawler cleaned 64 mb [2019-12-25 15:16:06] local.INFO: Begin recursive 64 mb
Ну задавай здесь, может и бесплатно форумчане помогут
- А если у Вас в базе данных 4 цвета и 4 размера
То создается 16 вариантов. Если 4 цвет, 4 размера, 4 еще чего то, то соответственно 64 варианта будет.
- Вы по одному каждый вариант в БД пишете?
Нет, при добавлении товара я вывел все атрибуты и их значения. То есть все цвета, все размеры, все типы воротников, и тд. Затем выбираю нужное (чекбокс), жму генерировать, и создаются варианты с комбинациями. Допустим я выбрал размеры: S,M,L,XL и цвета: Красный, синий, черный, желтый, и тип воротника: V-образный, и еще 3 какие то типа. В итоге получу 64 варианта к одному товару.
- Можно ли сделать так чтобы в БД сразу создались вме комбинации, тоесть на основании 2ух столбцов создался третий столбец в котором будут все комбинации вариантов из первых двух
Это так и работает. Я взял эту структуру бд с престашоп.
Вот пример как это работает http://bo.demo.prestashop.com/demo/index.php/product/form/2#tab-step3
(Авторизуйтесь)
Я это делаю так (структура бд):
Основная таблица с товарами
products
- id
- sku
- name
...
Таблица с вариантами товара (один вариант может содержать от 1го до N комбинаций).
К примеру Размер - XL, Цвет - Красный.
product_variations
- id
- product_id
- quantity
- price
- sku
...
А тут сами компинации. Variation_id - ид варианта товара, а attribute_id - ид атрибута (Цвет, размер и тд)
product_variation_combination
- id
- attribute_id
- variation_id
Добрый день.
Стоит задача "Отображать каждый день разный контент на главной странице согласно ТП".
В таблице с тарифами есть поле "days", которое влияет на отображение товаров каждые n дней.
Как расчитать какие товары выводить на главной сегодня, согласно инфе в тп?
Пока пришло в голову только одно: расчитывать сколько дней прршло от даты регистрации продавца, до сегоднешнего дня,и потом как то высчитывать это дальше...
Как решить эту задачу?))
$dayReport = new DayReport();
Это просто пустая модель которая знает к какой таблице в бд она относится, но определенной записи этой таблице в моделе нет.
Сделай так
$dayReport = (new DayReport())->find(1); // передай сюда ид записи к которой надо привязать рабочее время
$dayReport -> username = Auth::user()->name;
$dayReport->elementaryReports()->saveMany([
new ElementaryReport(['type' => 'Рабочее время', 'project' => 'Рабочее время', 'subproject' => 'Рабочее время', 'report' => 'Рабочее время', 'time' => 5]),
new ElementaryReport(['type' => 'Рабочее врем2', 'project' => 'Рабочее врем2', 'subproject' => 'Рабочее врем2', 'report' => 'Рабочее врем2', 'time' => 6]),
]);
Добрый день.
Столкнулся с проблемой, и что то не как не могу ее решить.
Есть класс Form, в нем есть метод tab:
/**
* Add tabs to form
*
* @param callable $tab
* @return $this
*/
public function tab(callable $tab)
{
$section = new Tab($this->model);
call_user_func($tab, $section);
$this->tabs[] = $section;
return $this;
}
И есть отдельный класс, в котором я добавляю форму и табы к ней:
$form->url('store')->method('post')->tab(function (Tab $tab) {
$tab->title('first tab')->fields(function(FormField $field) {
$field->input('text', 'test_input');
});
})->tab(function (Tab $tab) {
$tab->title('second tab')->fields(function(FormField $field) {
$field->input('number', 'price');
});
});
Если добавлять табы каждый раз используя функцию tab вот так ->tab(function (Tab $tab){})->tab(function (Tab $tab){})->tab(function (Tab $tab){})..., то табы добавляются как надо. Но я хочу не писать каждый раз эту функцию, а примерно так:
$form->url('store')->method('post')->tab(function (Tab $tab) {
$tab->title('first tab')->fields(function(FormField $field) {
$field->input('text', 'test_input');
});
$tab->title('second tab')->fields(function(FormField $field) {
$field->input('number', 'price');
});
$tab->title('third tab')->fields(function(FormField $field) {
$field->input('search', 'search_term');
});
});
Но так, в массив с табами добавляется только последний таб third tab. Как сделать что бы в массив с табами добавлялся новый обьект при каждом вызове
$tab->title('second tab')->fields(function(FormField $field) {
$field->input('number', 'price');
});