Как заставить работать цикл for так, как мне хотелось бы
Всем привет.
Имеется следующий код:
/*В данном цикле необходимо переменной $text присвоить значение LIMIT 100 и выполнять его повторно только после того, как массив из данного цикла был обработан следующими foreach циклами. В переменной $text хранится ID поста и сам текст.*/
for ($i = 0; ; $i = $i+100) {
$text = $this->db->query("SELECT text, id FROM tabler WHERE key = 0 (LIMIT 100, $i)")->getResultArray();
if (!empty($sql)) {
break;
}
}
/*Ниже мы объявляем переменную $tag, далее в цикле подготавливаем каждое ключевое слово к регулярке. После, во вложенном цикле проходимся всеми подготовленными регулярками по тексту новости для выборки всех возможных категорий. Такая реализация используется для того, что бы можно было использовать в БД ключевым словам/тегам * или .+, как пример*/
$insert = '';
$tag = $this->db->query("SELECT text, category FROM tags")
foreach ($tag as $tags) {
$tags_text = array($tags['text']);
$depregex = "/" . implode("|", $tags_text ) . "/i";
foreach ($text as $value) {
$lowervalue = mb_strtolower($value);
if (preg_match($depregex, $lowervalue, $matches)) {
$insert.= "('$tags['category'], $value['id']'),";
}
else {
//отдельный многострочный инсерт для тех новостей, где категория не была обнаружена
}
}
}
$insert = trim($insert, ',');
$this->db->query("INSERT INTO tabler (category, id) VALUES $insert ON DUPLICATE KEY UPDATE id = VALUES(id)");
Задумка такова, что я в цикле хотел бы получать по 100 элементов массива из БД (от 0 до 100, от 100 до 200 и т.д.), а дальше проверять через соседний цикл foreach наличие определенных тэгов (второй цикл написан и работает), а в случае, если массив пустой - прерывать работу цикла for.
Текущий цикл for не вложен в соседний цикл foreach, но они оба располагаются в одной функции.
Имею следующий вопрос:
- Как правильно реализовать цикл for, что бы он в переменной хранил массив ровно до того момента, пока его не обработает соседний цикл foreach?
Ответы (1 шт):
@sadkin а выборка из таблицы tags это выборка ключевых слов и категорий?
Зачем тогда цикл по ним? У вас их там вроде было штук 40 же? Запихните эту выборку в массив, где ключом будет ключевое слово, а значением - категория. Из ключей сделайте одно регулярное выражение, через |.
Зачем там кстати mb_strtolower? У вас UTF-8? Регулярное выражение вида /.../ui будет искать для юникода независимо от регистра.
Насколько я помню категория определяется по первому найденному ключевому слову?
Пример:
<?php
$kwds = [
'источник' => 1,
'PHP' => 2,
'базка' => 3,
'слов' => 4
];
$pattern = "/[^\b](" . implode("|", array_keys($kwds)) .")\b/umi";
$text = <<< EOT
видимо я не понимаю источник постов. Если пост вводится / редактируется
пользователем и сохраняется,
то у вас явно есть валидация и сохранение и привязку можно делать где-то
здесь. Собственно ~40 ключевых
слов вполне в регулярное выражение влезают и анализируются на порядок
вхождения (ну или не до конца
понимаю задачу). Если же вы откуда-то парсите / получаете или пакеты уже
готовых постов, то вы вполне
можете организовать очередь их обработки. В общем - явно не хватает
вводных данных для понимания.
Но в целом, на мой взгляд, базка всегда менее масштабируема, чем PHP-
приложение
EOT;
if (preg_match($pattern, $text, $matches)) {
echo "Найдено ключевое слово ". $matches[1]
. ", категория " . $kwds[$matches[1]] . PHP_EOL;
}
Если все же нужно искать все вхождения ключевых слов по порядку и привязывать к нескольким категориям, то:
if (preg_match_all($pattern, $text, $matches)) {
foreach($matches[1] as $kw) {
echo "Найдено ключевое слово ". $kw
. ", категория " . $kwds[$kw] . PHP_EOL;
}
}
Исходя из комментария про проблемы с циклом, попробуем так подойти к задаче:
<?php
/*
* Используем класс PDO для работы с базой
*/
// Коннект к базе, на примере MySQL
$dsn = 'mysql:dbname=<тут название базы>;host=<тут хост>';
$user = '<пользователь БД>';
$password = '<пароль к БД для пользователя>';
$dbh = new PDO($dsn, $user, $password);
// Формируем массив ключевых слов с категориями
$keywords = [];
$sql = "SELECT text, category FROM keywords"; // Запрос к таблице keywords, для получения ключевых слов
// как text и категорий, как category
if (($rows = $dbh->query($sql)->fetchAll(\PDO::FETCH_ASSOC))) {
foreach($rows as $row) {
$keywords[$row['text']] = $row['category'];
}
}
// Формируем шаблон для регулярного выражения, для поиска первого по порядку точного вхождения ключевого слова целиком
$pattern = $keywords? "/\b(" . implode("|", array_keys($keywords)) .")\b/umi" : false;
$sql = "SELECT id, text FROM tabler LIMIT %d, 100"; // Шаблон запроса для выборки постов из таблицы tabler(?),
// для получения id поста и текста (text). Порциями по 100 постов за раз.
// функция sprintf(string, ...) выполнит подстановку в шаблон числового
// значения $from на позицию %d
$from = 0; // Переменная offset отвечает за сдвиг в запросе
while(($rows = $dbh->query(sprintf($sql, $from))->fetchAll(\PDO::FETCH_ASSOC))) {
foreach($rows as $post) {
if ($pattern && preg_match($pattern, $post['text'], $matches)) {
echo "Пост id " . $post['id'] . " относится к категории " . $keywords[$matches[1]] . " по слову ".$matches[1] . PHP_EOL;
} else {
echo "Для поста id " . $post['id'] . " не нашли ключевых слов" . PHP_EOL;
}
}
$from+=100; // увеличиваем сдвиг для следующей порции чтения постов
}