Чат Telegram
Группа ВКонтакте
Новый комментарий


ArtemijeKA 25.10.2018 в 10:32

stdClass - standart Class?

ivashkevich 26.10.2018 в 08:54

Да.

ArtemijeKA 25.10.2018 в 18:47

У меня главная работает а на статью перехожу такая ошибка:
Скриншот
Что это может быть?

Включил xdebug и решил проблему так:

// src/MVCExample/Controllers/ArticlesController.php
use \MVCExample\Models\Article;

и еще добавил туда Article::class в

public function view(int $articleId) 
{
        $result = $this->db->query(
            'SELECT * FROM `articles` WHERE id = :id;',
            [':id' => $articleId],
            Article::class
        );
...
}

А так-же конечно поменял метод вывода в шаблоне через геттер

getName();
getText();
// templates/articles/view.php
<?php include __DIR__ . '/../header.php'; ?>
    <h1><?= $article->getName() ?></h1>
    <p><?= $article->getText() ?></p>
<?php include __DIR__ . '/../footer.php'; ?>
ivashkevich 26.10.2018 в 08:55

Всё правильно сделал, так и надо было)

ilyaOrlov 29.11.2018 в 19:54

Подскажите, а нельзя ли выводить статью таким методом?

$result = $this -> db -> query('SELECT * FROM `articles` WHERE `id` = ' . $articleId . ';', [], Article::class);

Через конкатенацию?

ivashkevich 29.11.2018 в 21:29

Ни в коем случае. Почитайте о SQL-инъекциях.

AxLT 02.12.2018 в 22:49

Все работает, только имя автора не выводится

<?php

namespace MyProject\Controllers;

use MyProject\Services\Db;
use MyProject\View\View;
use MyProject\Models\Articles\Article;

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` WHERE id = :id;',
            [':id' => $articleId],
            Article::class
        );
        var_dump($result);
        if ($result === []) {
            $this->view->renderHtml('errors/404.php', [], 404);
            return;
        }

        $author = $this->db->query(
            'SELECT nickname FROM `users` WHERE id = :id',
            [':id' => $result[0]['authorId']],
            Article::class
        );
        var_dump($author);
        $this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' => $author]);
    }

}
ivashkevich 02.12.2018 в 23:01

Ну так его и нет в шаблоне сейчас =) Если хотите - добавьте.

2Folls 23.01.2020 в 20:53

//

virtual2018 02.01.2019 в 17:44

Первый screenshot в описании метода _set по-моему не на месте.
описание картинки
По тексту мы только добавили в класс Article метод _set, который просто выводит на экран Свойство и Значение, без назначения переменных, а на screenshot-е: правильно (отсутствуют свойства author_id, created_at - мы их только печатаем) и неправильно (свойствам authorId, createdAt уже присвоены правильные значения).

dnldcode 06.01.2019 в 02:18

Почему нельзя просто создать в классе переменный с таким же название как и в бд? Зачем создавать отдельную функцию?

ivashkevich 06.01.2019 в 10:45

Потому что в БД есть свои правила по именованию столбцов, а в PHP есть стандарты именования переменных PSR. И они разные) Преобразовывать имена полей - это нормально.

AxLT 08.02.2019 в 17:15

Когда пытаюсь вывести автора получаю Fatal error:Uncaught Error: Cannot use object of type MyProject\Models\Articles\Article as array in C:\OSPanel\domains\myproject.loc\src\MyProject\Controllers\ArticlesController.php on line 31

<?php
namespace MyProject\Controllers;
use MyProject\Models\Articles\Article;
use MyProject\Services\Db;
use MyProject\View\View;

class ArticlesController
{
    private $view;
    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` WHERE id = :id;',
            [':id' => $articleId],
            Article::class
        );
        var_dump($result);
        if ($result == false){
            $result = $this->view->renderHtml('errors/404.php', [], 404);
            return;
        }
        $author = $this->db->query(
            'SELECT nickname FROM `users` WHERE id = :id',
            [':id' => $result[0]['authorId']],
            Article::class
        );
        var_dump($author);
        $this->view->renderHtml('articles/view.php', ['article' => $result[0]]);
    }
}
ivashkevich 11.02.2019 в 11:15

Ну переведите ошибку и всё станет понятно. В продвинутом курсе уже это надо самостоятельно делать.

Maxim 29.09.2019 в 19:50

Столкнулся с такой же проблемой. Не понимаю - где тут ошибка. Артём, помогите пожалуйста.

ivashkevich 30.09.2019 в 00:27

Написано, что объект класса Article нельзя использовать как массив. В $result объект! А вы ему $result[0]['authorId']]

Pro100Bah 06.10.2019 в 21:29

Та же ошибка вылазит, уже xDebug запускал, что-то не помогло.
var_dump() прогонял не пойму, что нужно исправить((
Читал комментарии, тоже до ответа не дошел((

$result[0]['authorId']]  //Что здесь не так?

view.php

<?php include __DIR__ . '/../header.php'; ?>
    <h1><?= $article->getName() ?></h1>        <!-- <h1><?//= $article['name'] ?></h1>  Это сменили в Lesson18 -->
    <p><?= $article->getText() ?></p>          <!-- <p><?//= $article['text'] ?></p> Это сменили в Lesson18 -->
    <p><i>Автор: <?= $author['nickname'] ?></i></p>      <!-- Homework 17 -->
<?php include __DIR__ . '/../footer.php'; ?>

ArticlesController.php

<?php

namespace MyProject\Controllers;

use MyProject\Services\Db;
use MyProject\View\View;
use MyProject\Models\Articles\Article;

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` WHERE id = :id;', [':id' => $articleId]
        );

        if ($result === []) {
            $this->view->renderHtml('errors/404.php', [], 404);  // Здесь обрабатываем ошибку
            return;
        }

        $resultAuthor = $this->db->query(
            'SELECT `nickname` FROM `users` WHERE id = :id',
            [':id' => $result[0]['author_id']]
        );

        $this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' => $resultAuthor[0]]);    //homework17
    }
}
ivashkevich 07.10.2019 в 08:37

Да потому что это объект! Как обращаются к свойствам объекта?
Подсказка: не через квадратные скобки.

Dram 17.05.2019 в 17:29

Где то вы уже объясняли, не могу найти - зачем комментарии типа
/* @var string /
Только для PhpStorm - что-то он там при этом правильно подсвечивает?

ivashkevich 17.05.2019 в 21:53

Да, после этого он знает тип этой переменной и может давать полезные подсказки.

prinzplanloser0514@gmail.com 12.10.2019 в 21:00

А почему у нас метод __set вызывается автоматом? underscoreToCamelCase понятно,он используется в другом методе,а __set почему.

ivashkevich 12.10.2019 в 22:01

Магический метод __set() - этот абзац читали?

teroni 17.12.2019 в 17:10
    public function __set($name, $value)
    {
        $camelCaseName = $this->underscoreToCamelCase($name);
        $this->$camelCaseName = $value;
    }

Артем, мы(__set) объявляем переменную $camelСaseName и присваеваем ей значение $name после переработки в методе, а после присваеваем этой же переменной новое значение $value, верно?! что _set дальше с этим делает($camelCaseName)?

ivashkevich 17.12.2019 в 18:46

а после присваеваем этой же переменной новое значение $value, верно?

нет. Обратите внимание на $this-> перед именем переменной!

Этим мы в свойство текущего объекта (свойство с именем, хранящимся в переменной $camelCaseName), записываем значение $value.

То есть если в переменной $camelCaseName будет лежать строка 'abc', то выполнится код:

$this->abc = $value;
teroni 17.12.2019 в 19:17

Спасибо, за скорость ответа. не обратил внимания на значок $ перед свойством и прочитал как $this->camelCaseName

ivashkevich 17.12.2019 в 19:48

Понятно)

zeexo 01.01.2020 в 23:59

А почему в начале класса нужно создавать свойства объектов, которые будут соответствовать полям в БД и можно ли их не создавать, а просто использовать геттеры/сеттеры для работы с свойствами(заранее НЕ объявляя их private $id, private $name и т.д.)?

ivashkevich 03.01.2020 в 03:55

А в чём прикол использовать неопределенные свойства? Работайте всегда с определенными. Иначе запутаетесь потом в именах.

andreskrip 28.01.2020 в 13:09

Спасибо за урок!
А почему для свойства id мы обозначили тип int, но для author_id - string?

Также попытался сделать вывод автора в одиночной статье:

public function view(int $articleId): void
    {
        $result = $this->db->query(
            'SELECT * FROM `articles` WHERE id=:id;', [':id' => $articleId], Article::class
        );
        if ($result === []) {
            $this->view->renderHtml('errors/404.php', [], 404);
            return;
        }

        $nickname = $this->db->query(
            'SELECT nickname FROM `users` WHERE id=:id;', [':id' => $result[0]->getAuthorId()], User::class
        );

        $this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' => $nickname[0]->getNickname()]);
    }

Для этого пришлось редактировать класс User, чтобы не записывать свойство $nickname в класс Article, так как оно из другой таблицы бд, но ощущение, что выглядит костылем

ivashkevich 28.01.2020 в 19:02

А почему для свойства id мы обозначили тип int, но для author_id - string?

Сорян, это я опечатался. Исправил, спасибо.

$nickname = $this->db->query(
            'SELECT nickname FROM `users` WHERE id=:id;', [':id' => $result[0]->getAuthorId()], User::class
        );

Нехорошо так делать. У вас должна сущность быть консистентной, а вы взяли и только одно поле заполнили. К тому же в переменной $nickname вовсе не никнейм теперь. А недопользователь какой-то. Возьмите и сфетчите пользователя полностью со всеми полями, потом возьмите у него никнейм. Более того, вы можете его в шаблон прямо как объект пользователя и закинуть, а в шаблоне уже запросить у него никнейм.

Для этого пришлось редактировать класс User, чтобы не записывать свойство $nickname в класс Article, так как оно из другой таблицы бд, но ощущение, что выглядит костылем

Не понял, почему это свойство nickname должно было записываться в Article?

andreskrip 28.01.2020 в 19:17

Понял, спасибо :)

Не понял, почему это свойство nickname должно было записываться в Article?

Ну просто в уроке мы модель пользователей не трогали, и поэтому выбор был класть либо в Article либо в stdClass. Ну и решил, что заполню класс User

andreskrip 28.01.2020 в 20:37

Исправляюсь :)

Изначально была мысль создать UsersController.php и пытаться через него передавать данные в шаблон, но в роутах данная вакансия занята ArticleController, поэтому оставил внутри него

ArticlesController.php

public function view(int $articleId): void
    {
        $result = $this->db->query(
            'SELECT * FROM `articles` WHERE id=:id;', [':id' => $articleId], Article::class
        );
        if ($result === []) {
            $this->view->renderHtml('errors/404.php', [], 404);
            return;
        }
        $user = $this->db->query(
            'SELECT * FROM `users` WHERE id=:id;', [':id' => $result[0]->getAuthorId()], User::class
        );

        $this->view->renderHtml('articles/view.php', ['article' => $result[0], 'user' => $user[0]]);
    }

templates/articles/view.php

<?php include __DIR__ . '/../header.php'; ?>
<h1><?= $article->getName() ?></h1>
<h2><?= $user->getNickname() ?></h2>
<p><?= $article->getText() ?></p>
<?php include __DIR__ . '/../footer.php'; ?>
ivashkevich 29.01.2020 в 06:24

Отлично

New 29.02.2020 в 13:08

По умолчанию это будут объекты класса stdClass – это такой встроенный класс в PHP, у которого нет никаких свойств и методов.

Этот класс используется чисто, как заглушка? Только для того, чтобы не возникла ошибка? А то я сразу кинулся прописать геттер в stdClass, а некуда прописывать)). Вроде и домашки не было, а код фактически не до конца работает. Но это и к лучшему, а то заметил, что даже просто прочитать и разобраться что как работает - мало - плохо запоминается/откладывается на подкорке, нужно самому что-то доделать, попробовать по другому сделать, в общем пропустить все через себя не только в теории, но и на практике.
Сделал так:
ArticlesController.php

public function view(int $articleId) {
        $result = $this->db->query('SELECT * FROM `articles` WHERE id = :id;', [':id' => $articleId], Article::class);
        if(empty($result)) {
            $this->view->renderHtml('errors/404.php',[], 404);
            return;
        }
        else {
            $articleAuthor = $this->db->query('SELECT nickname FROM users  WHERE id = :id;', [':id' => $result[0]->getAuthorId()], User::class);
            $this->view->renderHtml('articles/view.php', ['article' => $result[0], 'author' => $articleAuthor[0]]);
        }
    }

templates/articles/view.php

<?php include __DIR__ . '/../header.php'; ?>
    <p>Автор:<?= $author->getNickname(); ?></p>
    <h1><?= $article->getName(); ?></h1>
    <p><?= $article->getText(); ?></p>
<?php include __DIR__ . '/../footer.php'; ?>

класс User

<?php

namespace MyProject\Models\Users;

class User
{

    /** @var string */
    private $nickname;

    public function getNickname (): string
    {
        return $this->nickname;
    }
}

В метод fetchAll() мы передали специальную константу - \PDO::FETCH_CLASS, она говорит о том, что нужно вернуть результат в виде объектов какого-то класса. Второй аргумент – это имя класса, которое мы можем передать в метод query().

Мне кажется, тут было бы лучше для понимания сказать, что второй аргумент - это класс, объект которого будет создаваться и, со свойствами которого будут ассоциироваться данные, получаемые посредством fetchAll(). Во всяком случае, мне, как начинающему/изучающему так понятнее))

Задачей посложнее почему-то оказалось вывод автора в шаблон со всеми статьями, и кажется мне, решение какое-то корявенькое. Автор кочует в объект Article через объект User, да и смущают абсолютно одинаковые запросы в ДБ за никнеймом, присутствующие как в главном контроллере так и в контроллере статей... Костыль короче как мне кажется какой-то получился..

MainController.php

public function main()
    {
        $articles = $this->db->query('SELECT * FROM `articles`;', [], Article::class);
        for ($i=0; $i<count($articles); $i++) {
            $articleAuthor = $this->db->query('SELECT nickname FROM users  WHERE id = :id;', [':id' => $articles[$i]->getAuthorId()], User::class);
            $articles[$i]->setAuthor($articleAuthor[0]->getNickname());
            }
        $this->view->renderHtml('main/main.php', ['articles' => $articles]);
    }

В класс Article добавил сеттер и геттер для автора:

public function setAuthor ($author): void
    {
        $this->author = $author;
    }
    public function getAuthor (): string
    {
        return $this->author;
    }

В шаблоне main.php со всеми статьями просто запросил автора из объекта Article

<?php include __DIR__ . '/../header.php'; ?>

<?php foreach ($articles as $article): ?>
    <p><?= 'Автор статьи: ' .$article->getAuthor(); ?></p>
    <h2><a href="/articles/<?= $article->getId() ?>"><?= $article->getName() ?></a></h2>
    <p><?= $article->getText() ?></p>
    <hr>
<?php endforeach; ?>
<?php include __DIR__ . '/../footer.php'; ?>
ivashkevich 04.03.2020 в 18:35

По коду - всё у вас отлично. От костылей в дальнейших уроках избавимся)

Логические задачи с собеседований