Этот урок набрал набрал достаточно большое количество
комментариев и дальнейшее его комментирование отключено.
Если вы хотели убедиться в правильности выполнения ДЗ или у вас возник вопрос по уроку,
посмотрите ранее добавленные комментарии, кликнув по кнопке ниже. Скорее всего вы найдете там то, что искали.
Если это не помогло - задайте вопрос в чате в телеграме - https://t.me/php_zone
Долго провозился с использованием переменной в запросе
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
$author = $this->db->query('SELECT nickname FROM users WHERE id = "'.$result[0][1].'"');
if ($result === []) {
$this->view->renderHtml('errors/404.php');
return;
}
$this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' =>$author[0][0]]);
}
В экшне ArticlesController::view() после получения статьи, добавьте ещё один запрос на получение автора этой статьи из таблицы users. Выведите nickname автора в шаблоне.
С помощью Join соединил две таблички и без лишних обращений к базе забрал себе пользователей, дополнительно в списке статей тоже вывел авторов. Курс по БД прошел не зря=)
//MainController.php
public function main()
{
$articles = $this->db->query('SELECT * FROM `articles` a JOIN `users` u ON a.author_id = u.id');
$this->view->renderHtml('main/main.php', ['articles' => $articles]);
}
//ArticlesController.php
public function view(int $articleId)
{
$result = $this->db->query('SELECT * FROM `articles` a JOIN `users` u ON a.author_id = u.id WHERE a.id = :id;',[':id' => $articleId]);
if ($result === []) {
$this->view->renderHtml('errors/404.php',[],404);
return;
}
$this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
}
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
if ($result === []) {
$this->view->renderHtml('errors/404.php', 404);
return;
}
$author = $this->db->query(
'SELECT nickname FROM users WHERE id = :id',
[':id' => $result[0][1]]
);
$this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' => $author[0][0]]);
}
И есть один вопрос, View на вход принимает $articleId, так вот мне не совсем понятно каким образом эта переменная задается ив какой именно момент она получает свои значения "1" "2"
Я тоже задался этим же вопросом и возможно мы такие не одни)
Через дебаггер все встало на свои места:
Значения "1" или "2" или любое другое View получает благодаря нашей настройке роутинга.
В route.php мы прописываем роуты в формате "паттерн" => "класс контроллера, экшн", а затем уже в index.php мы foreach-ем перебираем паттерны для определения подходящего.
Т.к. паттерн для статей у нас был с маской (\d+), то в массив совпадений $matches после проверки, помимо полного совпадения по паттерну (нулевой элемент), еще попадет значение маски, т.е. всё то, что идет после 'articles/' в адресной строке (собственно в нашем случае "1" или "2" или любое другое).
Ну и в конце index.php мы удаляли ненужный 0 элемент из массива $matches, определяли название контроллера и название экшна, которые необходимо вызвать по данному роуту, и собственно подходим к главному:
$controller = new $controllerName();
$controller->$actionName(...$matches);
Определив нужный контроллер (в нашем случае ArticlesController), мы создаем его экземпляр и вызываем необходимый экшн (в нашем случае view) и аргументом передаем оставшийся элемент массива $matches, значение маски (1, 2 и т.д.)
А переменная $articleId задается внутри метода view (грубо говоря, какой аргумент в метод придет - тот и будет называться $articleId).
Надеюсь кому-то моя простыня поможет, если что исправьте)
$articles = $this->db->query('SELECT A.id,A.name,A.text,B.nickname FROM `articles` A INNER JOIN `users` B ON A.`author_id` = B.`id`;');/*Изменил запрос в MainController*/
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT A.id,A.name,A.text,B.nickname FROM `articles` A INNER JOIN `users` B ON A.`author_id` = B.`id` WHERE A.id = :id;',
[':id' => $articleId]
);/*так же в ActiveController*/
<p>Автор: <?= $article['nickname'] ?></p><!-- добавил автора в main.php и view.php -->
Для коллекции решений, автора получим в основном запросе выборкой из двух баз и дополнительно электронную почту автора , отдельным запросом с выводом в отдельную переменную:
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT a.author_id,a.name,a.text,u.nickname FROM `articles` a, `users` u WHERE a.author_id = u.id and a.id = :id;',
[':id' => $articleId]
);
if ($result === []) {
$this->view->renderHtml('errors/404.php', [], 404);
return;
}
$result_users = $this->db->query(
'SELECT email FROM `users` WHERE id = :id;',
[':id' => $result[0]['author_id']]
);
$this->view->renderHtml('articles/view.php', ['article' => $result[0], 'mail_to' => $result_users[0]['email']]);
}
Мы столько учили классы и наследования, можем ли мы тут их применить, как это к примеру сделал я?
<?php
namespace MyProject\Controllers;
class ArticlesController extends MainController
{
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
if ($result === []) {
$this->view->renderHtml('errors/404.php');
return;
}
$author = $this->db->query(
'SELECT * FROM `users` WHERE id = :author_id;',
[':author_id' => $result[0]['author_id']]);
$this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' => $author[0]]);
}
}
этим мы вроде как слегка оптимизировали код, убрали
use MyProject\Services\Db;
use MyProject\View\View;
/** @var View */
private $view;
/** @var Db */
private $db;
public function __construct()
{
$this->view = new View(__DIR__ . '/../../../templates');
$this->db = new Db();
}
если будет много контроллеров, сделать абстрактный класс, со всеми этими VIew и подклечениями к бд, и от него уже наследоваться. Хотя я может просто бегу впереди паровоза))
Не надо так. Можно просто завести переменную $nickname в самом начале метода со значением 'Автор не найден'. Если после запроса он есть, то переопределять эту переменную. И в renderHtml передавать её.
С помощью комментариев получилось добиться рабочего кода, но где то я что недопонял видимо и теперь немного не понимаю как происходит вывод статей, попробую проходить дальше, если так же не будет доходить, придётся назад возвращаться и перечитывать по новой)
//ArticlesController.php
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id',
[':id' => $articleId]
);
if ($result === []) {
$this->view->renderHtml('errors/404.php', [], 404);
return;
}
$user = $this->db->query(
'SELECT `nickname` FROM `users` WHERE id = :id',
[':id' => $result[0]['author_id']]
);
if ($user === []) {
$user[0]['nickname'] = 'не известно';
}
$this->view->renderHtml('articles/view.php', ['article'=> $result[0], 'nickname' => $user[0]['nickname']],200);
}
//view.php
<?php include __DIR__ . '/../header.php'; ?>
<h1><?= $article['name'] ?></h1>
<p><?= $article['text'] ?></p>
<p>Имя автора: <?= $nickname ?></p>
<?php include __DIR__ . '/../footer.php'; ?>
public function view()
{
echo 'Здесь будет получение статьи и рендеринг шаблона';
}
Все нормально по адресу http://localhost/articles/1 я вижу "Здесь будет получение статьи и рендеринг шаблона".
Стоит изменить эту функцию на
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
var_dump($result);
}
И я снова получаю ту ошибку, о которой писал ранее:
( ! ) Fatal error: Uncaught ArgumentCountError: Too few arguments to function MyProject\Controllers\ArticlesController::view(), 0 passed in C:\OSPanel\domains\localhost\index.php on line 32 and exactly 1 expected in C:\OSPanel\domains\localhost\src\MyProject\Controllers\ArticlesController.php on line 22
( ! ) ArgumentCountError: Too few arguments to function MyProject\Controllers\ArticlesController::view(), 0 passed in C:\OSPanel\domains\localhost\index.php on line 32 and exactly 1 expected in C:\OSPanel\domains\localhost\src\MyProject\Controllers\ArticlesController.php on line 22
Вы говорили использовать дебаг, но в каком файле - теперь то их куча. Попробовал поставить красную точку в начале каждого файла и перезапускать страницу - ничего не дало.
P.S. и еще у меня проблема с обратными слешами. Приходиться извращаться например так чтобы все работало
public function __construct()
{
$this->view = new View('C:\OSPanel\domains\localhost\src\templates');
$this->db = new Db();
}
и так
public function renderHtml(string $templateName, array $vars = [])
{
extract($vars);
ob_start();
include $this->templatesPath . '\\' . $templateName;
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;
}
Проблема в парсинге регулярки ноута, скорее всего. Не приходит второй аргумент. Напишите в личные сообщения в ВК или телеграме. Что-то много у вас проблем для решения в комментариях.
Оба решения вполне годные. Я бы предпочел второй вариант.
Но только назовите не article2, а nickname. Имя переменной должно отражать суть значения, которое в ней лежит.
Проверять есть ли автор, если есть статья я думаю не стоит, если не прав поправьте
и подумал что стоит получить все данные автора. Вдруг мы захотим еще что либо выводить на странице поста.
Е еще я где то пропустил почему нужно писать $user[0] а не $user?
Это чтоб выбирать по первому ключу?
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
if ($result=== []){
$this->view->renderHtml('errors/404.php', [], 404);
return ;
}
$user = $this->db->query(
'SELECT * FROM `users` WHERE id = :id;',
[':id' => $result[0]['author_id']]
);
$this->view->renderHtml('articles/view.php', [
'article' => $result[0],
'users' => $user[0]
]
);
}
для вьюхи
<?php include __DIR__ . '/../header.php'; ?>
<h1><?= $article['name'] ?></h1>
<p><?= $article['text'] ?></p>
<p><?= $users['nickname'] ?></p>
<?php include __DIR__ . '/../footer.php'; ?>
$query = $this->db->query('SELECT nickname FROM `users`
WHERE `id` IN ( SELECT author_id FROM `articles` WHERE id = :id );',
[':id' => $articleId]
);
Зачем второй раз делаете запрос статьи? У вас уже есть id пользователя в $result.
// $this->view->renderHtml('articles/view.php',
Не присылайте бесполезные комментарии в ДЗ. В рабочем коде их быть не должно.
if ($query === []) {
$this->view->renderHtml('errors/404.php', [], 404);
return;
}
То, что автор не найден, не означает, что на сайте нет статьи, и что нужно показывать 404 ошибку. Придумайте корректное поведение, которое позволит пользователям читать статьи на сайте, даже если автора найти не удалось.
Так я знаю что в articles есть id, и думал зачем ещё один запрос, но в ДЗ было написано чтобы сделать ещё один запрос для вывода автора. Проста из-за этого не так понял
Не понял вопроса. Говоришь, что с запросом всё понятно. Что с передачей в шаблон всё понятно. Непонятно только что происходит после запроса. Но после запроса идёт передача в шаблон и между ними ничего нет. И вообще код отличный. В чем проблема?)
Не полностью осилил задание,сам запрос я написал нормально,только вот смотрю,как люди делают,и немного не понимаю вот эту часть [':id' => $result[0]['author_id']] мы этой частью как-бы передаём в массиве номер автора,по которому отправляем запрос, например автор 1- admin,автор 2-user?
$result = $this->db->query(
'SELECT a.*, u.nickname FROM `articles` a INNER JOIN `users` u ON a.author_id = u.user_id WHERE a.article_id = :id;',
[':id' => $articleId]
);
Должна, но выводится без тегов. Хотя раньше все ок было. МОжет опять же проблема из-за дебагера который отключен и текст выводится как есть, а не с разметкой.
А также вопрос: не вызовет ли путаницы в будущем тот факт, что у нас и файл класса View называется View.php и шаблон для статей тоже называется view.php?
Если автора не будет (в $author[0]['nickname'] лежит NULL), то присвоим $nickname пустую строку ''. В противном случае присвоим содержимое $author[0]['nickname'].
Я думал, я помню эту конструкцию и смогу со смартфона, не влезая в phpstorm ответить, но увы...
Когда прочитал теорию и вроде разобрался, а потом, не закрепив на практике, попытался вспомнить:
if (isset($foo)) {
$bar = $foo;
} else {
// присваиваем $bar значение 'default' если $foo равен NULL
$bar = 'default';
}
теперь можно: $bar = $foo ?? 'default';
...
public function view(int $articleId)
{
$sql = 'SELECT * FROM `articles` AS a INNER JOIN `users` AS u ON a.author_id=u.id WHERE a.id = :id;';
$result = $this->db->query($sql, [':id' => $articleId]);
...
И эта регулярка формирует строку вида 'articles/2'(например), которая передается как параметр в функцию view. И приходится еще одной регуляркой выдергивать именно номер, т.к. в таком виде к корректному int она, по умолчанию, не преобразовывается. А вот здесь, для запроса к БД в функции view, нам нужен int.
$result = $this->db->query(
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
);
Может я где-то что-то упустил, но что именно и где найти не могу.
Если вы про съехавшие фигурные скобки в функции, то похоже это происходит при копипасте текста почему-то, сам только внимание на это обратил. В IDE все нормально. А в остальном вроде с форматированием нормально(стандартный отступ в 4 пробела и пустые строки между логическими блоками). Или я чего то не замечаю? Alt+Ctrl+L пустые строки убирает, что мне не очень нравится.
Похоже понял о чем вы.
if(){
}
if()
{
}
Вы про это? Привычка из прошлого) Мне удобнее так, вложенность визуально более выделяется. Или стандарт строго не рекомендует так делать?
Артем, подскажите, пожалуйста, у меня в файле main.php - ide сообщает, что $articles не определена.
Это странно, так как ошибок - нет и все уведомления включены, да и работает все.
Думаю, что так у всех, так как я шагал по урокам с вами.
Скажите, допустимо ли вообще, чтобы что-то было неопределено, т.е. можно ли на это закрыть глаза, если все работает?
Вот код:
<?php include __DIR__ . '/../header.php' ?>
<?php foreach ($articles as $article):?>
<h2><a href="/articles/<?=$article['id']?>"> <?= $article['name']?></a></h2>
<p><?= $article['text']?></p>
<hr>
<?php endforeach; ?>
<?php include __DIR__ . '/../footer.php'; ?>
Если написать в условии цикла:
$articles ?? null - то ошибка исчезает.
Привет. То, что IDE ругается - это нормально. Она же не знает что эта переменная прилетает в шаблон из другого места. Чтобы ей в этом помочь, можно добавить специальные аннотации phpDoc:
<?php
/**
* @var array $articles
*/
?>
<?php include __DIR__ . '/../header.php' ?>
<?php foreach ($articles as $article):?>
...
Что мы в курсе для начинающих говорили про нейминг переменных? camelCase.
Для чего приписка _result?
if ($author_result == []) {
$author_result[0]['nickname'] = 'неизвестен';
}
Так лучше не делать. Лучше завести отдельную переменную $nickname, и в случае если массив не пустой, положить в неё значение. И уже эту переменную прокидывать в шаблон для вывода.
'SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]
:id - двоеточие обязательно, id любая придуманная нами псевдопеременная
далее запятая,
потом массив где псевдопеременной присваивается реальная переменная
<?php
namespace MyProject\Controllers;
use MyProject\Services\Db;
use MyProject\View\View;
class ArticlesController
{
/** @var View */
private $view;
/** @var Db */
private $db;
public function __construct()
{
$this->view = new View(__DIR__ . '/../../../templates');
$this->db = new Db();
}
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` as a join `users` as b on a.author_id=b.id WHERE a.id = :id',
[':id' => $articleId]
);
if ($result === []) {
$this->view->renderHtml('errors/404.php', [],404);
return;
}
$this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
}
}
Приветствую. Так правильно или стоит по другому делать? ArticlesController.php
public function view(int $articleId)
{
$result = $this->db->query('SELECT * FROM `articles` WHERE id = :id;',
[':id' => $articleId]);
if ($result === [])
{
$this->view->renderHtml('errors/404.php', [], 404);
return;
}
$author = $this->db->query('SELECT u.nickname, a.name FROM users AS u INNER JOIN articles AS a ON u.id=a.author_id WHERE a.id = :id;',
[':id' => $articleId]);
$this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' => $author[0]]);
}
Приает, Артём!
Подскажи при твлем подходе, варианте реализации представления и шаблона возможно следующее.
Что у меня вот например неоьходимо реализовать так что в нутри файла есть разные подшаблоны файлы.
Например для меню, таблицы контекста.
Каким образом можно внутри шаблона снова вызвать рендеринг вложенного в него подшаблона?!
То есть например, внутри шаблона вывода контента различной структуры вызвать реедеринг подшаблона что подобие таким образом
$this->view->renderHtml('main/main_сontent.php',['content' => $contet]);
А у же в этом файле подшаблона
Вывод контента соответсвующим оьразом как в данной статье.
Большое спасибо!
Убедительно прошу только понять меня правильно, что я задаю вопросы здесь и в чате телеграмма только для того чтобы все максимально разобраться, применять, и если найдены ошибки их помочь исправить.
В частности проблема как писал ранее в чате или в комментариях есть в пути /.. /src/ пришлось заменить на /src/.
И есть другие еще моменты, которые предоставлю, для исправления/обсуждения в конце прохождения курса.
И если не против, то готов стать соавтором, соредактором проекта. Цель самое главное взаиморазвитие, взаимопомощь.
public function view(int $articleId)
{
$result = $this->db->query(
'SELECT * FROM `articles` AS a
INNER JOIN `users` AS u
ON a.author_id = u.id
WHERE a.id = :id;',
[':id' => $articleId]
);
if ($result === []) {
$this->view->renderHtml('errors/404.php', [], 404);
return;
}
$this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
}
Хорошо, только не нужно никнейм в несуществующего пользователя запихивать, лучше отдельную переменную под это это дело завести. И вардампа не должно быть здесь
Долго провозился с использованием переменной в запросе
Автора стоит получать только после того, как проверили что массив не пустой.
В экшне ArticlesController::view() после получения статьи, добавьте ещё один запрос на получение автора этой статьи из таблицы users. Выведите nickname автора в шаблоне.
С помощью Join соединил две таблички и без лишних обращений к базе забрал себе пользователей, дополнительно в списке статей тоже вывел авторов. Курс по БД прошел не зря=)
Хорошо, так тоже можно)
Хороший пример!
Явно не зря, еще в селекте нужные столбцы прописать, чтобы алиас для никнейма сделать, типа такого:
Чтобы в шаблоне статьи можно было выводить $article['author'], для лучшей понятности. И вообще идеальное решение задачи
А почему использовали LEFT JOIN?
Да как-то так придумалось) Неверно?
Нужно понимать разницу между разными типами JOIN-ов - прочитайте о них. Конкретно здесь должен быть INNER JOIN.
Хорошо!
ArticlesController
view
Отлично!
на участке:
renderHtml должен принимать на вход два аргумента, и при таком коде у меня ошибка, исправил на:
Вопрос почему у вас работает иначе)?
А можно увидеть функцию renderHtml ? второй аргумент должен иметь дефолтное значение, ощущение что у Вас он не задан, но могу ошибаться)
Привет! Вот код:
Второй аргумент по умолчанию равен пустому массиву.
Да действительно упустил
Спасибо
Сделал так
И есть один вопрос, View на вход принимает $articleId, так вот мне не совсем понятно каким образом эта переменная задается ив какой именно момент она получает свои значения "1" "2"
Норм сделал. То что и нужно было.
Там снизу еще вопрос есть)
Не понял вопроса. Напиши по нему лучше в личку в телеге.
Я тоже задался этим же вопросом и возможно мы такие не одни)
Через дебаггер все встало на свои места:
Значения "1" или "2" или любое другое View получает благодаря нашей настройке роутинга.
В route.php мы прописываем роуты в формате "паттерн" => "класс контроллера, экшн", а затем уже в index.php мы foreach-ем перебираем паттерны для определения подходящего.
Т.к. паттерн для статей у нас был с маской (\d+), то в массив совпадений $matches после проверки, помимо полного совпадения по паттерну (нулевой элемент), еще попадет значение маски, т.е. всё то, что идет после 'articles/' в адресной строке (собственно в нашем случае "1" или "2" или любое другое).
Ну и в конце index.php мы удаляли ненужный 0 элемент из массива $matches, определяли название контроллера и название экшна, которые необходимо вызвать по данному роуту, и собственно подходим к главному:
Определив нужный контроллер (в нашем случае ArticlesController), мы создаем его экземпляр и вызываем необходимый экшн (в нашем случае view) и аргументом передаем оставшийся элемент массива $matches, значение маски (1, 2 и т.д.)
А переменная $articleId задается внутри метода view (грубо говоря, какой аргумент в метод придет - тот и будет называться $articleId).
Надеюсь кому-то моя простыня поможет, если что исправьте)
Отличная простыня)
ArticlesController.php
view.php
Лучше не засовывать автора внутрь статьи. Пусть пробрасывается отдельной переменной.
Ок)
В предыдущих уроках header и footer лежали тут:
а в этом переехали в
Для коллекции решений, автора получим в основном запросе выборкой из двух баз и дополнительно электронную почту автора , отдельным запросом с выводом в отдельную переменную:
Отлично!
ArticlesController.php
view.php
Так можно решить?
Это не очень правильно, потому что у $article не должно быть nickname и других полей пользователя.
Мы столько учили классы и наследования, можем ли мы тут их применить, как это к примеру сделал я?
этим мы вроде как слегка оптимизировали код, убрали
если будет много контроллеров, сделать абстрактный класс, со всеми этими VIew и подклечениями к бд, и от него уже наследоваться. Хотя я может просто бегу впереди паровоза))
Да. Отлично! Если уверен, что все контроллеры будут содержать этот код - то твой вариант правильный.
ArticlesController
view
Не надо так. Можно просто завести переменную $nickname в самом начале метода со значением 'Автор не найден'. Если после запроса он есть, то переопределять эту переменную. И в renderHtml передавать её.
С помощью комментариев получилось добиться рабочего кода, но где то я что недопонял видимо и теперь немного не понимаю как происходит вывод статей, попробую проходить дальше, если так же не будет доходить, придётся назад возвращаться и перечитывать по новой)
Прочитайте мой ответ выше. Аналогичные пожелания.
view.php
Отлично
ArticlesController.php
view.php
Отлично!
Отлично
Все нормально по адресу http://localhost/articles/1 я вижу "Здесь будет получение статьи и рендеринг шаблона".
Стоит изменить эту функцию на
И я снова получаю ту ошибку, о которой писал ранее:
Вы говорили использовать дебаг, но в каком файле - теперь то их куча. Попробовал поставить красную точку в начале каждого файла и перезапускать страницу - ничего не дало.
P.S. и еще у меня проблема с обратными слешами. Приходиться извращаться например так чтобы все работало
и так
Проблема в парсинге регулярки ноута, скорее всего. Не приходит второй аргумент. Напишите в личные сообщения в ВК или телеграме. Что-то много у вас проблем для решения в комментариях.
Решение №1, быдлокод :))) просто оно мне первое в голову пришло...
+ в view.php
Говнокод №2 :)) мне кажется опять не правильно... ну как неправильно - данные то выводит, но вероятно не по стандартам написано
+ в view.php
прошу критики...
Оба решения вполне годные. Я бы предпочел второй вариант.
Но только назовите не article2, а nickname. Имя переменной должно отражать суть значения, которое в ней лежит.
Ух ты! Спасибо, не ожидал! Начинает получаться значит :))
Видимо)
Проверять есть ли автор, если есть статья я думаю не стоит, если не прав поправьте
и подумал что стоит получить все данные автора. Вдруг мы захотим еще что либо выводить на странице поста.
Е еще я где то пропустил почему нужно писать $user[0] а не $user?
Это чтоб выбирать по первому ключу?
user[0] - потому что из query тебе вернётся массив записей.
Тут должен быть $user, потому что он там один.
А в остальном - всё супер.
Спасибо, теперь понял!
Controller:
VIEW:
Отлично
Долго мучался, но вроде разобрался)
ArticlesController.php
view.php
Отлично!
Ошибка здесь:
Сможете найти?
не не нашел, а что здесь не так?
Ищете пользователя по id. Вместо id пользователя передаёте id статьи.
Зачем второй раз делаете запрос статьи? У вас уже есть id пользователя в $result.
Не присылайте бесполезные комментарии в ДЗ. В рабочем коде их быть не должно.
То, что автор не найден, не означает, что на сайте нет статьи, и что нужно показывать 404 ошибку. Придумайте корректное поведение, которое позволит пользователям читать статьи на сайте, даже если автора найти не удалось.
Так я знаю что в articles есть id, и думал зачем ещё один запрос, но в ДЗ было написано чтобы сделать ещё один запрос для вывода автора. Проста из-за этого не так понял
Ну так запрос для получения пользователя всё равно нужен. Непонятно, зачем вы внутри него снова за статьей идёте.
ArticlesController.php:
articles/view.php:
Отлично! Образцовая домашка.
Отлично
ArticlesController.php
templates/articles/view.php
Отлично
Отлично!
Рабочий получилось сделать, но немного с логикой запутался. Поправьте , если мыслю не совсем верно.
Создаем переменную $resultAuthor. Аргументы у нас на входе запрос($sql) и массив(params=[]).
Дальше не понимаю , что происходит((( .
Не понял вопроса. Говоришь, что с запросом всё понятно. Что с передачей в шаблон всё понятно. Непонятно только что происходит после запроса. Но после запроса идёт передача в шаблон и между ними ничего нет. И вообще код отличный. В чем проблема?)
Не полностью осилил задание,сам запрос я написал нормально,только вот смотрю,как люди делают,и немного не понимаю вот эту часть [':id' => $result[0]['author_id']] мы этой частью как-бы передаём в массиве номер автора,по которому отправляем запрос, например автор 1- admin,автор 2-user?
Всё,разобрался,что-то я тупанул,как запрос будет знать,какой id из массива мы запрашиваем,если мы этого не указываем) под вечер уже мозги кипят.
Бывает)
view.php
ArticlesController.php
Отлично
А если я сделал запрос такого вида,как мне подставить нужный параметр в users.id ?
Запрос некорректный в принципе.
ArticlesController.php
View.php
nl2br - статья по идее уже с тегами должна быть. В остальном ок.
Должна, но выводится без тегов. Хотя раньше все ок было. МОжет опять же проблема из-за дебагера который отключен и текст выводится как есть, а не с разметкой.
Дебаггер тут не при чём. Разбирайтесь в какой момент пропадают теги.
src/MyProject/Controllers/ArticlesController.php
templates/articles/view.php
Вопрос: Зачем мы пишем ':id' с ':', если без него 'id' тоже работает
Отлично. Мы пишем с двоеточием, потому что именно так говорится в документации. Почему работает без него - не знаю.
Спасибо за урок! Пришлось плотно засесть, чтобы во всём разобраться, но мне понравилось)
ArticlesController.php:
templates/articles/view.php:
А также вопрос: не вызовет ли путаницы в будущем тот факт, что у нас и файл класса View называется View.php и шаблон для статей тоже называется view.php?
Отлично. Нет, не вызовет)
Домашка
Отлично
view.php
articleController.php
Пришлось повозиться конечно, чтоб извилинами шевельнуть. Это читается так просто, а как до дела доходит, так время больше уходит гораздо)
Так делать не стоит. Лучше заведи отдельную переменную $nickname и туда складывай либо это значение, либо результат из запроса.
Файл ArticlesController.php:
Файл view.php:
Супер!
ArticlesController.php
view.php
Слеши в другую сторону пишите, иначе потом будут проблемы на линуксе. В остальном всё отлично
Зачем в $this это складывать?
Почему двойные кавычки?
и другое подобное пишется в одну строку:
Нет смысла заводить для этого переменные.
ArticlesController.php
templates/articles/view.php
Лучше завести отдельную переменную nickname и писать имя автора в неё. Её же передавать в шаблон.
Так, просто для читабельности?
Если автора не будет, то вот тут возникнет ошибка:
Вы сможете объяснить, что тут написано? Прочитайте для начала об операторе ?? и конструкции isset.
Если автора не будет (в $author[0]['nickname'] лежит NULL), то присвоим $nickname пустую строку ''. В противном случае присвоим содержимое $author[0]['nickname'].
Я думал, я помню эту конструкцию и смогу со смартфона, не влезая в phpstorm ответить, но увы...
Когда прочитал теорию и вроде разобрался, а потом, не закрепив на практике, попытался вспомнить:
А скобки зачем?
так очевидней, что это не несколько разных элементов :) Пока изучаю, так легче воспринимается.
/templates/articles/view.php
src/MyProject/Controllers/ArticlesController.php
Зачем туда статью передавать?
Конечно незачем, скопировал лишнего.
Возможно есть решение попроще, но я сделал так:
\src\MyProject\Controllers\ArticlesController.php
\templates\articles\view.php
Всё отлично, только вот здесь не нужны пробелы:
Спасибо, исправил
Теперь норм!
?
Как это оказалось в контроллере?
Мне пришлось прописывать данный запрос, так как у меня автоматически не подключалась БД.
Сегодня просмотрел код ещё раз...
В итоге решил проблему.
Как решил?
Эта ошибка была глупой, я написал имя ключа dbName за вместо dbname в классе Db. Итог просто ошибся регистром :D
Ок. А вообще такому коду самое место в классе Db, если вдруг решите его когда-то вновь написать.
Хорошо)
ArticlesController.php
View.php
Отлично
Запрос автора статьи и передача никнейма в рендер
Вывод никнейма в шаблоне
Это что такое? Сделайте роутинг нормальный, как в предыдущих уроках.
Вроде делал все как в уроке. Но получается так, что роут выглядит вот так
И эта регулярка формирует строку вида 'articles/2'(например), которая передается как параметр в функцию view. И приходится еще одной регуляркой выдергивать именно номер, т.к. в таком виде к корректному int она, по умолчанию, не преобразовывается. А вот здесь, для запроса к БД в функции view, нам нужен int.
Может я где-то что-то упустил, но что именно и где найти не могу.
Пересмотрите урок по роутингу. Там выдергиваются только группы из регулярки (то, что в скобочках)
Разобрался. При изучении регулярок не до конца понял смысл скобок, в итоге сделал без них, оттуда ноги и растут. Спасибо.
Отлично, жду исправленное решение
Для шаблона ничего не изменилось
Упс)
почему 400?
Сначала взяли значение из массива queryResult и только потом проверили его на пустоту. Тут закралась ошибка
Кажется все поправил.
Ок. Только проблема с форматированием. Делайте отступы как в уроках. Для этого в шторме можно нажать Ctrl+Alt+L
Если вы про съехавшие фигурные скобки в функции, то похоже это происходит при копипасте текста почему-то, сам только внимание на это обратил. В IDE все нормально. А в остальном вроде с форматированием нормально(стандартный отступ в 4 пробела и пустые строки между логическими блоками). Или я чего то не замечаю? Alt+Ctrl+L пустые строки убирает, что мне не очень нравится.
Похоже понял о чем вы.
Вы про это? Привычка из прошлого) Мне удобнее так, вложенность визуально более выделяется. Или стандарт строго не рекомендует так делать?
Да, есть стандарт PSR, которого все придерживаются
А как решили проблему TypeError - у меня тоже id возвращает как string, а не как int...
Такой вариант имеет право на существование? (Публикую только метод, который поменялся)
view.php
Не надо вместо автора пихать текст ошибки. Обрабатывайте лучше в шаблоне отсутствие автора.
ArticlesController.php:
view.php
Отлично
ArticlesController.php
view.php
Что-то с отступами. Не могу прочитать даже из-за этого :) Как поправите - напишите ответ на этот коммент. Проверю.
view.php
Проверка наличия статьи в базе происходит уже после того, как мы словили кучу ошибок
я уже убежал вперед, и код этого урока изменен, я правильно понял, что правильное решение вот такое?
Да
ArticlesController.php
view.php
Если статьи не будет, произойдет необработанная ошибка
Я так понимаю, нужно сделать проверку на то, что статья найдена, до того момента, когда начинается передача данных в объект $resultUser
ArticlesController.php
До того момента, как начинает использоваться несуществующий результат, если быть точнее.
Привет!
ДЗ.
Контроллер:
view.php
Артем, подскажите, пожалуйста, у меня в файле main.php - ide сообщает, что $articles не определена.
Это странно, так как ошибок - нет и все уведомления включены, да и работает все.
Думаю, что так у всех, так как я шагал по урокам с вами.
Скажите, допустимо ли вообще, чтобы что-то было неопределено, т.е. можно ли на это закрыть глаза, если все работает?
Вот код:
Если написать в условии цикла:
$articles ?? null - то ошибка исчезает.
Привет. То, что IDE ругается - это нормально. Она же не знает что эта переменная прилетает в шаблон из другого места. Чтобы ей в этом помочь, можно добавить специальные аннотации phpDoc:
Спасибо большое, двигаюсь дальше!
ArticlesController
view
Что мы в курсе для начинающих говорили про нейминг переменных? camelCase.
Для чего приписка _result?
Так лучше не делать. Лучше завести отдельную переменную $nickname, и в случае если массив не пустой, положить в неё значение. И уже эту переменную прокидывать в шаблон для вывода.
MainControllers.php
ArticlesController.php
main.php
templites/articles/views.php
Отлично
Добрый день, прошу пояснить запись вида
мне непонятен кусок - :id;',
[':id' => $articleId]
Что это? Даже не знаю как описать... и не переменная и не кусок массива, как понять такую запись?
Я в своем говнокоде привык писать так,
Мне кажется в разы читабельнее, нет? Можно ли использовать мой код и если нет, то почему?
Это называется параметризованный запрос, и он автоматом защищает от SQL-injection.
https://www.php.net/manual/ru/pdo.prepare.php
Спасибо, правильно я понял -
:id - двоеточие обязательно, id любая придуманная нами псевдопеременная
далее запятая,
потом массив где псевдопеременной присваивается реальная переменная
Правильно понял?
Да
Мое решение - изменить запрос на
В шаблоне добавить
Годится
ArticlesController.php
templates/articles/view.php
Отлично
Приветствую. Так правильно или стоит по другому делать?
ArticlesController.php
view.php
Всё просто отлично!)
Запрос в ArticlesController::view()
Шаблон
Отлично
Приает, Артём!
Подскажи при твлем подходе, варианте реализации представления и шаблона возможно следующее.
Что у меня вот например неоьходимо реализовать так что в нутри файла есть разные подшаблоны файлы.
Например для меню, таблицы контекста.
Каким образом можно внутри шаблона снова вызвать рендеринг вложенного в него подшаблона?!
То есть например, внутри шаблона вывода контента различной структуры вызвать реедеринг подшаблона что подобие таким образом
$this->view->renderHtml('main/main_сontent.php',['content' => $contet]);
А у же в этом файле подшаблона
Вывод контента соответсвующим оьразом как в данной статье.
Большое спасибо!
Можно сделать статический метод для такого, например. Сделайте класс Renderer и у него статический метод render(string $pathToTemplate, array $vars)
Домашняя работа.
ArticlesXontroller.php содержит теперь:
А в шаблоне C:\OpenServer\domains\phpzone2\templates\articles\view.php
Решил просто поставить над загооловком статьи
В идеале наверное как-то так нужно было сделать SQL запрос
SELECT * FROM
articles
INNER JOIN users ON (articles.author_id=:id1)WHERE(articles.id=:id2)Да нет, прошлый вариант ок
Хотелось бы просто еще больше тренироваться и понимать на практике сложные SQL запросы.
Вместо print_r используйте var_dump
https://php.zone/post/krasivyy-vyvod-var-dump-openserver
В целом ок, единственное, запихивать никнейм в статью - как-то не очень. Лучше отдельным параметром его в рендерилку передать
Да, спасибо большое!
Обязательно учту. Это просто старая привычка у меня осталась.
Скоро от нее принтов окончательно избавлюсь.
Скажите, это вообще что? Не могу понять. И откуда берется?
Это подстановка. На её место встанет значение, переданное в параметрах с этим ключем.
В файле templates/main/main.php вместо
Заработал код
Точно ли все в порядке с путями?!
Ну так в уроке вроде так и написано, нет?
templates/main/main.php
Зайдём в корень нашего сайтика и увидим, что теперь мы можем переходить по каждой статье отдельно.
Аа, в самом конце уже. Спасибо, исправил) Странно, что в начале урока всё правильно было.
Убедительно прошу только понять меня правильно, что я задаю вопросы здесь и в чате телеграмма только для того чтобы все максимально разобраться, применять, и если найдены ошибки их помочь исправить.
В частности проблема как писал ранее в чате или в комментариях есть в пути /.. /src/ пришлось заменить на /src/.
И есть другие еще моменты, которые предоставлю, для исправления/обсуждения в конце прохождения курса.
И если не против, то готов стать соавтором, соредактором проекта. Цель самое главное взаиморазвитие, взаимопомощь.
Да конечно, я только за! Напиши в личку в телеге.
Отлично
Добрый день!
Домашнее задание
ArticlesController.php
view.php
Хорошо, только не нужно никнейм в несуществующего пользователя запихивать, лучше отдельную переменную под это это дело завести. И вардампа не должно быть здесь
Пытаюсь в MainController добавить автора, выдает везде admin, дело в foreach(е), не пойму в чем конкретно
main.php
Дело не в foreach. Воспользуйтесь дебаггером.
ArticlesController.php
view.php
Ок
ArticlesController.php
view.php
Лучше использовать именованные ключи. Почему используется пустая строка, если значения нет?
Почему автор запрашивается, если authorId может быть пустой строкой?
В шаблон передается не никнейм, а сам автор, некорректное название.
Некорректная обработка ситуации, когда статья найдена, а автор - нет.
вроде понял, надеюсь правильно все, спасибо за обратную связь) от души душевно в душу))
view.php
Теперь норм