Этот урок набрал набрал достаточно большое количество комментариев и дальнейшее его комментирование отключено. Если вы хотели убедиться в правильности выполнения ДЗ или у вас возник вопрос по уроку, посмотрите ранее добавленные комментарии, кликнув по кнопке ниже. Скорее всего вы найдете там то, что искали. Если это не помогло - задайте вопрос в чате в телеграме - https://t.me/php_zone
ivashkevich 31.07.2018 в 17:33

Пример решения домашки:

    private function insert(array $mappedProperties): void
    {
        $filteredProperties = array_filter($mappedProperties);

        $columns = [];
        $paramsNames = [];
        $params2values = [];
        foreach ($filteredProperties as $columnName => $value) {
            $columns[] = '`' . $columnName. '`';
            $paramName = ':' . $columnName;
            $paramsNames[] = $paramName;
            $params2values[$paramName] = $value;
        }

        $columnsViaSemicolon = implode(', ', $columns);
        $paramsNamesViaSemicolon = implode(', ', $paramsNames);

        $sql = 'INSERT INTO ' . static::getTableName() . ' (' . $columnsViaSemicolon . ') VALUES (' . $paramsNamesViaSemicolon . ');';

        $db = Db::getInstance();
        $db->query($sql, $params2values, static::class);
        $this->id = $db->getLastInsertId();
        $this->refresh();
    }

    private function refresh(): void
    {
        $objectFromDb = static::getById($this->id);
        $reflector = new \ReflectionObject($objectFromDb);
        $properties = $reflector->getProperties();

        foreach ($properties as $property) {
            $property->setAccessible(true);
            $propertyName = $property->getName();
            $this->$propertyName = $property->getValue($objectFromDb);
        }
    }
Ilon 01.09.2018 в 14:10

чет сложна)

ivashkevich 01.09.2018 в 19:07

дебаггер в помощь)

Sparkqy 25.09.2018 в 18:19

Можно плиз краткое объяснение, как работает refresh()? :) потому что "чет сложна)" реально ахаха

ivashkevich 25.09.2018 в 22:12

Он берет версию объекта из базы, получает все его свойства.
Затем бежит в цикле по этим свойствам и:

  1. делает их публичными;
  2. читает их имя;
  3. в текущем объекте (у которого вызвали refresh) свойству с таким же именем задаёт значение из свойства, взятого у объекта из базы ($objectFromDb).
Drozdetskij 03.05.2022 в 17:05

Можно ли объекту $article присвоить данные полученные по id, который вернула функция getLastInsertId?

$article = Article::getById($article->getId());

public function add(): void {

    $author = User::getById(1);

    $article = new Article ();
    $article->setAuthor($author);
    $article->setName('Добавляем статью');
    $article->setText('Добавляем текст статьи');

    $article->save();

    $article = Article::getById($article->getId());

}
ivashkevich 17.05.2022 в 14:29

Можно. Но зачем?

excent63 24.03.2019 в 21:00

Немного не пойму, почему он числовые значения передаёт как строковые после добавления refresh();

object(MyProject\Models\Articles\Article)[6]
  protected 'name' => string 'Новая Статья' (length=23)
  protected 'text' => string 'Новый техт' (length=19)
  protected 'authorId' => string '1' (length=1)
  protected 'createdAt' => string '2019-03-24 20:57:08' (length=19)
  protected 'id' => string '3' (length=1)
ivashkevich 25.03.2019 в 11:34

Потому что из базы так возвращаются.

excent63 25.03.2019 в 13:38

Понял, спасибо!

ivashkevich 25.03.2019 в 13:45
excent63 25.03.2019 в 13:54

О спасибо! Обязательно прочту

ivan.tretiakov 20.03.2021 в 21:18

Я прочел, попробовал, работает. Нужно в файле Mvc\Services\Db добавить пару строк в конструкторе класса, где создаем подключение к БД. Установить два атрибута PDO.

$this->pdo = new \PDO(...);
$this->pdo->exec('SET NAMES UTF8');
$this->pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, false); // раз
$this->pdo->setAttribute(\PDO::ATTR_STRINGIFY_FETCHES, false); // два

Теперь, INT(TINYINT) будет приходить из БД как INT, VARCHAR как STRING

ivashkevich 26.03.2021 в 17:28

Отлично что разбираетесь самостоятельно. Так держать!

Boodoo 24.04.2019 в 11:08

Тяжеловато вошло....

Metey 21.07.2019 в 16:06

А так можно делать??

public function insert(array $mappedProperties): void
    {
        $filteredProperties = array_filter($mappedProperties);

        $columns = [];
        $paramsNames = [];
        $params2values = [];
        foreach ($filteredProperties as $columnName => $value) {
            $columns[] = '`' . $columnName. '`';
            $paramName = ':' . $columnName;
            $paramsNames[] = $paramName;
            $params2values[$paramName] = $value;
        }

        $columnsViaSemicolon = implode(', ', $columns);
        $paramsNamesViaSemicolon = implode(', ', $paramsNames);

        $sql = 'INSERT INTO ' . static::getTableName() . ' (' . $columnsViaSemicolon . ') 
                    VALUES (' . $paramsNamesViaSemicolon . ');';

        $db = Db::getInstance();
        $db->query($sql, $params2values, static::class); 
        $this->id = $db->getLastInsertId();
        $this->refresh();
    }

    public function refresh(): void
    {
        $objFromDb = static::getById($this->id);

        $properties = get_object_vars($objFromDb);

        foreach ($properties as $key=>$value) {
            $this->$key = $value;
        }
    }
ivashkevich 21.07.2019 в 19:15

Отлично

EugeneGrigoryev 25.01.2020 в 01:32

src/MyProject/Models/ActiveRecordEntity.php
Примерно понимал как сделать, но добиться нужного результата не получилось, поэтому подсмотрел в готовые решения :(

private function insert(array $mappedProperties): void
    {
        $columns2params = [];
        $params2values = [];
        foreach ($mappedProperties as $column => $value) {
            if ($value === null) continue;
            $columns2params[] = "{$column} = :{$column}";
            $params2values[":{$column}"] = $value;
        }
        $sql = 'INSERT INTO ' . static::getTableName() . ' SET ' . implode(', ', $columns2params);
        $db = Db::getInstance();
        $db->query($sql, $params2values, static::class);
        $this->id = $db->getLastInsertId();
        $this->refresh();
    }
    private function refresh(): void
    {
        $objectFromDb = static::getById($this->id);
        $reflector = new \ReflectionObject($objectFromDb);
        $properties = $reflector->getProperties();

        foreach ($properties as $property) {
            $property->setAccessible(true);
            $propertyName = $property->getName();
            $this->$propertyName = $property->getValue($objectFromDb);
        }
    }
ivashkevich 25.01.2020 в 14:00

Главное чтобы в итоге это решение было вам понятно и вы его запомнили, точнее, могли реализовать в дальнейшем.

andreskrip 04.02.2020 в 14:58

Спасибо за урок!

private function insert(array $mappedProperties): void
    {
        $filterProperties = array_filter($mappedProperties);
        $columns = [];
        $values = [];
        $params = [];

        foreach ($filterProperties as $column => $value) {
            $columns [] = '`' . $column . '`';
            $valueName = ':' . $column;
            $values[] = $valueName;
            $params[$valueName] = $value;
        }

        $columnsViaCommas = implode(', ', $columns);
        $valuesViaCommas = implode(', ', $values);
        $sql = 'INSERT INTO `' . static::getTableName() . '` (' . $columnsViaCommas . ') VALUES (' . $valuesViaCommas . ');';
        $db = Db::getInstance();
        $db->query($sql, $params, static::class);
        $this->id = $db->getLastInsertId();
        $this->refresh();
    }

    private function refresh(): void
    {
        $objectFromDb = static::getById($this->id);

        foreach ($objectFromDb as $property => $value) {
            $this->$property = $value;
        }

    }

Можно ли так упростить функцию refresh? Или могут быть случаи, когда перебор задаст неправильные значения?

ivashkevich 06.02.2020 в 03:07

В базе имена столбцов именуются с подчеркиваниями. В коде - camelCase. Так что нет, нельзя.

andreskrip 11.02.2020 в 17:55

Но разве в ActiveRecord прописанный магический метод __set, не занимается переименовыванием свойств в надлежащий вид?

ivashkevich 12.02.2020 в 13:08

А, сорян. Да, можно

OneMoreTime 11.03.2020 в 00:40

1. В методах insert и update по сути бОльшая часть методов содержит один и тот же код(преобразование одного массива в два), за исключением очистки массива свойств, строки запроса, ну и заключительной части в методе insert из этого урока. Можно ли как-то унифицировать эти медоды, чтобы не было повторяющегося кода в разных методах?

2.

Например, в поле createdAt должна появиться строка с датой.

Для чего нужно получать эту информацию кроме id, где и как ее использовать? Не учитывая наработку практических навыков конечно.

3. Сложность решения задачи - в первую очередь из-за не знания моря(!) встроенных функций. Сам принцип получения этой информации(решения задачи) понятен, а вот реализация - посредством чего можно сделать - по аналогии с английским языком - вроде и конструкция предложения понятна/знакома, а нужные слова не знаешь.

ivashkevich 13.03.2020 в 17:16
  1. Ну если он одинаковый, то можно вынести его в отдельный метод.
  2. Чтобы отобразить дату создания записи?
  3. Учите понемногу английский.
OneMoreTime 13.03.2020 в 17:38

Учите понемногу английский.

)) Английский - это просто аналогия. А вопорс в том, что в языке очень много встроенных функций, которыми не приходилось пользоваться и даже неизвестно о их существовании. Например, дойдя уже до этого урока многие вещи просто не опробованы(из тех же операций со строками, массивами. как раз пример из этого урока: array_filter), поэтому многие вопросы решаются посредством костылей и полотнами кода. При этом, тоже не будеьтупо подряд по списку изучать все функции из документации. На это пол жизни уйдет, и не успеешь на работу устроиться))

ivashkevich 13.03.2020 в 17:40

Не переживайте. Если вы вместо array_filter напишите foreach, хуже не станет.

Dimitry 05.04.2020 в 07:33
private function insert(array $mappedProperties): void
    {
        $filterProperties = array_filter($mappedProperties);
        $columns = [];
        $values = [];
        $params = [];

        foreach ($filterProperties as $column => $value) {
            $columns [] = '`' . $column . '`';
            $valueName = ':' . $column;
            $values[] = $valueName;
            $params[$valueName] = $value;
        }

        $columnsViaCommas = implode(', ', $columns);
        $valuesViaCommas = implode(', ', $values);
        $sql = 'INSERT INTO `' . static::getTableName() . '` (' . $columnsViaCommas . ') VALUES (' . $valuesViaCommas . ');';
        $db = Db::getInstance();
        $db->query($sql, $params, static::class);
        $this->id = $db->getLastInsertId();
        $this->refresh();
    }

    private function refresh(): void
    {
        $objectFromDb = static::getById($this->id);

        foreach ($objectFromDb as $property => $value) {
            $this->$property = $value;
        }

    }

Домашка

ivashkevich 05.04.2020 в 19:18

Отлично!

Alexann 14.04.2020 в 23:12

Почему-то два раза отправилось одно и то же - удалил.

[email protected] 14.04.2020 в 23:27

Article

public function getCreatedAt() : string
  {
    return $this->createdAt;
  }

ActiveRecordEntity

    $article = self::getById($this->id);
    $this->createdAt = $article->getCreatedAt();
ivashkevich 15.04.2020 в 11:13

Решение должно быть гибким и касаться всех полей, а не только createdAt, приведенного в качестве примера.

Общий объект ActiveRecordEntity ничего не должен знать о статьях!

Alexann 15.04.2020 в 08:05

Файл ActiveRecordEntity.php:

...
private function insert(array $mappedProperties): void
    {
   ...
        $this->id = $db->getLastInsertId();
        $object = static::getById($this->id);
        $this->createdAt = $object->getCreatedAt();
    }

И в Article.php добавить геттер getCreatedAt().

ivashkevich 15.04.2020 в 11:34

Решение должно быть гибким и касаться всех полей, а не только createdAt, приведенного в качестве примера.

Alexann 15.04.2020 в 13:11

Идея была обновить все поля, но компактного решения не нашел, поэтому вот так (наверное самое оптимальное):

...
private function insert(array $mappedProperties): void
    {
...
 $this->refresh();
    }

    private function refresh(): void
    {
        $object = static::getById($this->id);
        foreach ($object as $property => $value) {
            $this->$property = $value;
        }
    }
ivashkevich 15.04.2020 в 17:30

Ок, а благодаря чему стало возможным вот так итерировать объект?

        foreach ($object as $property => $value) {
            $this->$property = $value;
        }
Alexann 15.04.2020 в 22:23

Если я правильно понял вопрос, то потому что foreach позволяет пройти по тем свойствам объекта (как по элементам массива), которые являются видимыми и доступными. Если копнуть глубже, то с помощью интерфейса Traversable, который определяет является ли класс обходимым с использованием foreach. Я правда очень смутно это понимаю (пока что).

ivashkevich 16.04.2020 в 06:59

Отлично. Этот интерфейс позволяет... да что я вам буду рассказывать, вы можете прочитать о нем в документации. Там же есть примеры.

Fill 29.04.2020 в 05:06
    private function insert(array $mappedProperties): void
    {
        ...
        $this->id = $db->getLastInsertId();
        $this->refresh();
    }

    private function refresh(): void
    {
        $lastInsertedObject = static::getById($this->id);
        $reflector = new \ReflectionObject($lastInsertedObject);
        $properties = $reflector->getProperties();

        foreach ($properties as $property) {
            $propertyName = $property->getName();
            $this->$propertyName = $lastInsertedObject->$propertyName;
        }
    }
ivashkevich 29.04.2020 в 19:17

Отлично

studentDev 11.05.2020 в 12:50
private function insert(array $mappedProperties): void
        {
            $filteredProperties = array_filter($mappedProperties); //

            $columns = [];
            $paramsNames = [];
            $params2values = [];
            foreach($filteredProperties as $columnName => $value) {
                $columns[] = '`' . $columnName . '`';
                $paramName = ':' . $columnName;
                $paramsNames[] = $paramName;
                $params2values[$paramName] = $value;
            }

            $columnsViaSemicolon = implode(', ', $columns);
            $paramsNamesViaSemicolon = implode(', ', $paramsNames);

            $sql = 'INSERT INTO ' . static::getTableName() . ' (' . $columnsViaSemicolon . ' ) VALUES (' . $paramsNamesViaSemicolon . ')';
            $db = Db::getInstance();
            $db->query($sql, $params2values, static::class);
            $this->id = $db->getLastInsertId();
            $this->refresh();
        }

        public function refresh(): void
        {
            $objects = static::getById($this->id);

            foreach($objects as $obj => $value) {
                $this->$obj = $value;
            }
        }

?

ivashkevich 12.05.2020 в 07:59

Отлично!

OneMoreTime 11.05.2020 в 18:15

1.
Почему в этом уроке название таблицы и названия столбцов в обратных апострофах, а в прошлом -нет?

2.
Почему в одном уроке запрос в БД с синтаксическим сахаром, в другом - нет? Должно же быть однообразно во всем проекте? И вообще, приемлемо ли его использование в контексте стандартов и чистого кода в PHP?

3.
В примере решения вопроса из домашки использовано получение значения через метод getValue()

$this->$propertyName = $property->getValue($objectFromDb);

Но ведь можно напрямую обратиться к свойству объекта без встроенного геттера:

$this->$propertyName = $objectFromDb->$propertyName;

В чем разница между такими способами получения значения?

ivashkevich 12.05.2020 в 08:13
  1. Можно и так и так. Это просто моё настроение, не более того)
  2. К единообразию следует стремиться. Но всё равно не получится, особенно если на проекте более одного человека. У меня вот, как видите, и в одиночку не получается, просто прошла неделя между выпуском уроков. А про какой именно сахар речь?
  3. Да, так тоже можно. У меня была логика именно в единообразии, раз начал через неё работать, значит и заканчивать через неё)
OneMoreTime 12.05.2020 в 09:51

А про какой именно сахар речь?

INSERT INTO `table` (column1, column2)  VALUES (:param1, :param2);

vs

INSERT INTO `table` SET (column1=:param1, column2=:param2);
ivashkevich 13.05.2020 в 07:13

Ок, спасибо за ответ

Timurik 14.05.2020 в 11:25
    private function insert(array $mappedProperties): void
    {
        ...
        $this->refrech();
    }

    public function refrech(): void
    {
        $objFromDb = static::getById($this->id);
        foreach ($objFromDb as $property => $value) {
            $this->$property = $value;
        }
    }
ivashkevich 14.05.2020 в 15:04

refrech - опечатка в слове

В остальном ОК!

Timurik 15.05.2020 в 15:54

Спасибо, исправил на refresh

[email protected] 14.05.2020 в 18:34

Пробегаем по свойствам объекта, смотрим какие из них не установлены, делаем заброс в бд по нужному свойству и, если получаем ответ, записываем в свойство объекта полученное значение.

private function insert(array $mappedProperties)
{
    $columns = [];
    $params = [];
    $params2values = [];
    $index = 1;
    $filteredProperties = array_filter($mappedProperties);
    foreach ($filteredProperties as $column => $value) {
        $param = ':param' . $index;
        $columns[] = $column;
        $params[] = $param;
        $params2values[$param] = $value;
        $index++;
    }
    $sql = 'INSERT into ' . static::getTableName() . ' (' . implode(',', $columns) . ') VALUES(' . implode(',', $params) . ');';
    $db = Db::getInstance();
    $db->query($sql, $params2values, static::class);
    $this->id = $db->getLastInsertId();

    foreach ($this as $property=>$value){
        if($value === null){
            $underscoredProperty = $this->camelCaseToUnderscore($property);
            $sql = 'SELECT `'.$underscoredProperty.'` FROM `'.static::getTableName().'` WHERE id = :id';
            $queryResult = $db->query($sql, [':id' => $this->id]);
            if($queryResult != null) {
                $this->$property = $queryResult[0]->$underscoredProperty;
            }
        }
    }
}
ivashkevich 15.05.2020 в 18:22

Решение рабочее, но слишком сложное. Очень много лишних запросов. Можно обойтись одним SELECT-ом. Если не получится, посмотрите другие решения в комментариях.

[email protected] 16.05.2020 в 00:02

Переделал в один запрос. Так лучше?

    private function insert(array $mappedProperties)
    {
        $columns = [];
        $params = [];
        $params2values = [];
        $index = 1;
        $filteredProperties = array_filter($mappedProperties);
        foreach ($filteredProperties as $column => $value) {
            $param = ':param' . $index;
            $columns[] = $column;
            $params[] = $param;
            $params2values[$param] = $value;
            $index++;
        }
        $sql = 'INSERT into ' . static::getTableName() . ' (' . implode(',', $columns) . ') VALUES(' . implode(',', $params) . ');';
        $db = Db::getInstance();
        $db->query($sql, $params2values, static::class);
        $this->id = $db->getLastInsertId();

        $undefinedProperties = [];
        $underscoredUndefinedProperties = [];
        foreach ($this as $property=>$value){
            if($value === null){
                $undefinedProperties[] = $property;
                $underscoredUndefinedProperties[] = $this->camelCaseToUnderscore($property);
            }
        }

        $sql = 'SELECT '.implode(',', $underscoredUndefinedProperties).' FROM `'.static::getTableName().'` WHERE id = :id';
        $db = Db::getInstance();
        $sqlResult = $db->query($sql,[':id' => $this->id]);

        if($sqlResult !== null) {
            for ($i = 0; $i < count($undefinedProperties); $i++) {
                $undefinedProperty =  $undefinedProperties[$i];
                $underscoredUndefinedProperty = $underscoredUndefinedProperties[$i];
                $this->$undefinedProperty = $sqlResult[0]->$underscoredUndefinedProperty;
            }
        }
    }
ivashkevich 16.05.2020 в 12:18

Только непонятно, для чего это. У вас же уже есть метод для получения объекта из базы.

[email protected] 16.05.2020 в 18:13

Мда, что-то я ударился в изобретание велосипеда. Думал, что тащить всю запись из БД не стоит. Теперь несколько строк всего получается)

$entity = self::getById($this->id);
foreach ($this as $property=>$value){
    if($value === null){
        $this->$property = $entity->$property;
    }
}

И можно ли вместо

if($value === null){
    $this->$property = $entity->$property;
}

писать

 $value ?? $this->$property = $entity->$property;
ivashkevich 17.05.2020 в 14:53

Некорректное использование null-coalesce оператора. Он используется для возврата значений в правой части в левую часть выражения. У вас же он применяется для побочного вызова кода в случае выполнения или невыполнения условия. Используйте в таких случаях if-else.

HardBass 27.06.2020 в 15:49

ActiveRecordEntity.php

...
        $this->refresh();;
    }

    private function refresh() : void
    {
        $objDb = static::getById($this->id);
        foreach ($objDb as $property => $value) {
            $this->$property = $value;
        }
    }
...
ivashkevich 27.06.2020 в 17:05

Отлично!

zeexo 05.08.2020 в 21:50

Как можно решить проблему, если я через сеттер в модели задаю значение = 0
У меня тогда ActiveRecordEntity просто не учитывает это в insert запросе(просто пропускает поле, значение которого = 0).
Хотя если значение 1, 2, 3 или любое текстовое - то всё ок.

ivashkevich 07.08.2020 в 17:55

Видимо значение отфильтровывается в array_filter. Вы дебажить пробовали?

zeexo 07.08.2020 в 19:11

Проблема возникает в ActiveRecordEntity, в строке:
$filteredProperties = array_filter($mappedProperties);
у метода insert, то есть функция array_filter удаляет элементы входящего массива, если у него значение = 0.
Проблему решил так(при этом null, false, пустая строка будут так же удаляться из массива):

$filteredProperties = array_filter($mappedProperties, 'strlen');

Возможно кому-то пригодится.

ivashkevich 11.08.2020 в 13:18

Я ожидал что вы всё-таки свой коллбэк напишите и будете сравнивать с null. Потому что в вашем варианте будут и пустые строки отфильтровываться.

ivan.tretiakov 06.03.2021 в 20:38
$filteredProperties = array_filter($mappedProperties, function($value){
                if($value === null){
                    return false;
                }
                else {
                    return true;
                }
            });
[email protected] 10.10.2020 в 21:30

Чтобы не отфильтровывались пустые строки и нули необходимо

private function insert(array $mappedProperties) : void {
    $columns = [];
    $paramsNames = [];
    $params2values = [];
    foreach ($mappedProperties as $columnName => $value) {
        if ($value!==null) {
            $columns[] = '`' . $columnName . '`';
            $paramName = ':' . $columnName;
            $paramsNames[] = $paramName;
            $params2values[$paramName] = $value;
        };
    };

?

ivashkevich 12.10.2020 в 07:38

Супер!

pixel 29.12.2020 в 22:19

Не знаю вроде верно вывел всю информацию после добавления. Но что-то сильно просто, другие в комментариях создавали функции, я же просто вызвал view передав значение id статьи. Такое решение верное?

    public function add(): void
    {
        $author = User::getById(1);

        $article = new Article();
        $article->setAuthor($author);
        $article->setName('Новое название статьи');
        $article->setText('Новый текст статьи');

        $article->save();

        $article = Article::getById($article->getId());
    }

Артём еще сделал такую штуку, где получаю свойства есть createdAt и id которые неопределенны и если я в чистом виде буду к ним обращаться мне пишет ошибка $createdAt must not be accessed before initialization
С id тоже самое.
Решил эту проблему добавив заполнение null для этих свойств, которые не определены $this->$propertyName ?? null;

    private function mapPropertiesToDbFormat(): array
    {
        $reflector = new \ReflectionObject($this);
        $properties = $reflector->getProperties();

        $mappedProperties = [];
        foreach ($properties as $property) {
            $propertyName = $property->getName();
            $propertyNameAsUnderscore = $this->camelCaseToUnderscore($propertyName);
            $mappedProperties[$propertyNameAsUnderscore] = $this->$propertyName ?? null;
        }

        return $mappedProperties;
    }
ivashkevich 03.01.2021 в 18:51
  1. Лучше после добавления редиректить на страницу просмотра, чем дублировать шаблон.
  2. Норм решение.
pixel 03.01.2021 в 20:49

Добавил редирект на главную страницу, спасибо:)

header('Location: http://myproject.loc/index.php');

Думал почему ошибка выходит, а это я автора с id 1 удалил

SkSeMi 18.01.2021 в 23:55

ArticlesController.php

...................
    public function insert(): void
    {

        $article = Article::getById(1);
        $article->id = null;

        if ($article === null) {
            $this->view->renderHtml('errors/404.php', [], 404);
            return;
        }

        $article->setName('Добавлени статья : название статьи');
        $article->setText('Новый текст добавленной  статьи');
        $article->setcreatedAt(date("Y-m-d H:i:s"));
        $article->setauthorId(1);

        $article->save();
    }

    public function add(): void
    {
        $author = User::getById(1);

        $article = new Article();
        $article->setAuthor($author);
        $article->setName('Новое название статьи');
        $article->setText('Новый текст статьи');
        $article->setcreatedAt(date("Y-m-d H:i:s"));

        $article->save();

        var_dump($article);
    }
....................

Article.php
```....................

public function setcreatedAt($date): string
{
    return $this->createdAt=$date;

}

....................


**ActiveRecordEntity.php**

.............
private function insert2(array $mappedProperties): void
{

    // var_dump($mappedProperties);

    $mappedPropertiesNotNull = array_filter($mappedProperties);

    // var_dump($mappedPropertiesNotNull);

    $columns2params = [];
    $params2values  = [];

    foreach ($mappedProperties as $column => $value) {

        if ($column=="id") continue;
        $columns2params[]   = $column;
        $params2values[] = ":".$column;
    }

    $sql = 'INSERT INTO ' . static::getTableName().' ('.implode(', ', $columns2params). ') VALUES ('. implode(', ', $params2values).');';

    // var_dump($sql);

    $db = Db::getInstance();
    // $db->query($sql, $params2values, static::class);
    $db->query($sql, $mappedPropertiesNotNull, static::class);

    var_dump($sql);
    // var_dump($params2values);
}

private function insert(array $mappedProperties): void
{
    $filteredProperties = array_filter($mappedProperties);

    $columns        = [];
    $paramsNames    = [];
    $params2values  = [];
    foreach ($filteredProperties as $columnName => $value) {
        if($value!==null)
        {
            $columns[] = '`' . $columnName. '`';
            $paramName = ':' . $columnName;
            $paramsNames[] = $paramName;
            $params2values[$paramName] = $value;
        }
    }

    $columnsViaSemicolon = implode(', ', $columns);
    $paramsNamesViaSemicolon = implode(', ', $paramsNames);

    $sql = 'INSERT INTO ' . static::getTableName() . ' (' . $columnsViaSemicolon . ') VALUES (' . $paramsNamesViaSemicolon . ');';

    $db = Db::getInstance();
    $db->query($sql, $params2values, static::class);

    $this->id = $db->getLastInsertId();
    $this->refresh();
}

private function refresh(): void
{
    $objectFromDb = static::getById($this->id);

    foreach ($objectFromDb as $property => $value) {
        $this->$property = $value;
    }

}

.............


insert2 то что пытался делать в прошлом 21ом уроке в домашнем задании.
insert то что смог собрать из урока и комментариев.
Понимание естьно не полное еще пока, что.
Особенно зачем вызывать в конце insert и как работает refresh метод?!
Чем отличаются методы insert и add между собой?
Спасибо!
ivashkevich 19.01.2021 в 19:15

Метод insert это метод модели должен быть, а не контроллера. В контроллере метод add, наполняющий модель данными и вызывающий у нее метод save. Если у модели id, нет, то у нее должен вызваться метод insert

SkSeMi 20.01.2021 в 22:38

Вроде понял. Пцтаница возникла, что в уроке где в домашнем задании предлагалось попробовать написать insert самомстоятельно не сразу понял.

Сейчас, что листинг кода предоставил это нормально?

ivashkevich 21.01.2021 в 06:22

Да, с кодом дела отлично

XXX 23.02.2021 в 21:02
 private function insert(array $mappedProperties): void
    {
        $filteredProperties = array_filter($mappedProperties);

        $columns = [];
        $paramsNames = [];
        $param2values = [];

        foreach ($filteredProperties as $columnName => $value) {
            $columns[] = '`' . $columnName. '`';
            $paramName = ':' . $columnName;
            $paramsNames[] = $paramName;
            $param2values[$paramName] = $value;
        }

        $columnsViaSemicolon = implode(', ', $columns);
        $paramsNamesViaSemicolon = implode(', ', $paramsNames);

        $sql = 'INSERT INTO ' . static::getTableName() . ' (' . $columnsViaSemicolon . ') VALUES (' . $paramsNamesViaSemicolon . ');';

        $db = Db::getInstance();
        $db->query($sql, $param2values, static::class);
        $this->id = $db->getLastInsertId();

        $tableRow = static::getById($this->id);
        foreach ($tableRow as $columnName => $value) {
            $propertyName = self::camelCaseToUnderscore($columnName);
            $this->$propertyName = $value;
        }
    }
XXX 23.02.2021 в 21:06

Почитав коментарии понял, что лучше вывести в отдельную функцию
В таком случае.

private function refresh(): void
    {
        $tableRow = static::getById($this->id);
        foreach ($tableRow as $columnName => $value) {
            $propertyName = self::camelCaseToUnderscore($columnName);
            $this->$propertyName = $value;
        }
    }
ivashkevich 28.02.2021 в 06:00

Ага, норм

Neo 14.07.2021 в 16:26

Привет всем, не могу понять ДЗ. Вопрос звучит так: Доработайте метод insert() таким образом, чтобы поля объекта обновлялись значениями из БД. Я правильно понимаю, что нужно вывести уже добавленные данные из БД? Так как с помощью array_filter убираются ненужные поля, а дата воспроизводится автоматически в БД и она в данный момент не видна.

ivashkevich 06.08.2021 в 19:39

Да, всё так

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