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


prognoz 31.08.2019 в 15:18

У меня вопрос, как сайт с подобной архитектурой загрузить на сервер провайдера? Допустим, тот же beget. Ничего не получается.
Там все грузится в папку public_html.
Вопрос, как переадресовать запрос в папку www.
Все что пишу в public_html/.htaccess не работает.
Варианты такие:
DirectoryIndex /web/index.php
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(.+) $1 [L]
RewriteCond %{DOCUMENT_ROOT}/web%{REQUEST_URI} -f
RewriteRule ^(.+) /web/$1 [L]

Не работает. Что делать?

ivashkevich 31.08.2019 в 21:03

Просто переименовать www в public_html. Вся остальная структура не изменится.

prognoz 01.09.2019 в 00:10

Если на OpenServer поменять название папки www на public_html, то все работает.

На хостинге ничего не работает.
Структура там такая prognoex.beget.tech и в нем папка public_html
Грузим наш проект в папку prognoex.beget.tech
Наша структура папок:
src
templates
public_html (бывший www)

В итоге ошибка 500.

Служба поддержки пишет следующее:
Здравствуйте!
Насколько я вижу, проблема возникает из-за некорректной работы php-скрипта. Прикладываю фрагмент лога ошибок:
[31-Aug-2019 23:05:33 Europe/Moscow] PHP Notice: Undefined index: route in /home/p/prognoex/prognoex.beget.tech/public_html/index.php on line 11

Что не так с путями? Подскажите, пожалуйста.

ivashkevich 01.09.2019 в 07:11

.htaccess загрузил хоть?) Если проблема не в этом, напиши в личку в ВК или в телеге.

V0yager 09.10.2019 в 15:42

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

Роут для страницы добавления коммента: /articles/1/comments/add
Контроллер: ArticlesController
Экшн: addComment

Просто получается так, что в случае возникновения ошибки, надо открывать страницу со статьёй, но добавляя туда переменную с этой ошибкой.
Была мысль записать в массив свойств view ($this->view->setVar('error', $excep->getMessage())), и уже при рендеринге страницы со статьёй вывести ошибку, но мне показалось, что это бредовато.

ivashkevich 09.10.2019 в 19:32

Да нет, вполне рабочее решение. В реальных проектах запрос отправляется через js на отдельный роут и если возвращается ошибка, то всплывает окошечко с ошибкой. Но здесь в учебном примере будет нормально так как ты предложил.

zeexo 01.12.2019 в 13:55

Артём, здравствуйте!
Подскажите, пожалуйста, касаемо архитектуры.
Есть UsersController(и модель его, как мы делали в уроках ранее).
Возник вопрос. Допустим есть различные таблицы с логами.
Как мне правильно вывести их в "Профиле"?
Создать метод profile в классе UsersController (Controllers/UsersController.php), затем в Models создать файлы с классами, которые наследуются от ActiveRecord и в методе profile класса UsersController сделать так(?):

Controllers/UsersController.php

public function profile()
{
    $user = $this->user;
    if($user === null) {
        header('Location: /');
    } else {
        $log = $user->getLogs($user);
        $log2 = $user->getLogs2($user);
        $log3 = $user->getLogs3($user);
        $this->view->renderHtml('user/profile.php', [
            'log' => $log,
            'log2' => $log2,
            'log3' => $log3
        ]);
    }
}

Models/Users/User.php

public static function getLogs($user)
{
    return \Application\Models\Logs\Log1::getById($user->id);
}

public static function getLogs2($user)
{
    return \Application\Models\Logs\Log2::getById($user->id);
}

public static function getLogs3($user)
{
    return \Application\Models\Logs\Log3::getById($user->id);
}

Models/Logs/Log1.php

namespace Application\Models\Logs;
use Application\Models\ActiveRecordEntity;

class Log1 extends ActiveRecordEntity
{
    protected static function getTableName(): string
    {
        return 'log1';
    }
}

На сколько правильный такой способ реализации? Или лучше иначе, и как?

ivashkevich 01.12.2019 в 17:02

Мне непонятно что это за логи, и почему их нужно выводить в профиле. Опишите чуть подробнее, пожалуйста.

zeexo 01.12.2019 в 17:56

Есть таблица users(пользователи).
Допустим, есть таблицы логов:
таблица log_users (id, user_id, action) - логи действий юзера
таблица calls_log (id, user_id, call_id, call_description) - логи звонков
После авторизации пользователя по логину и паролю, делаю переход на страницу профиля юзера.
Но сам профиль в роутах я сделал так:

'~^profile$~' => [\MyApp\Controllers\UsersController::class, 'profile']

То есть создал метод profile в UsersController.
И на странице профиля пользователя мне нужно вывести ДВЕ таблицы(html) с логами:
Лог действий пользователя(авторизовавшегося):

SELECT * FROM log_users WHERE user_id = 'id_аккаунта_из_users'

Лог звонков(авторизовавшегося):

SELECT * FROM calls_log WHERE user_id = 'id_аккаунта_из_users'

И два вопроса:

  1. Правильно ли делать "профиль" пользователя через UsersController? Или правильней ProfileController создавать?
  2. Можно ли вывести html таблицы на странице "профиля" создав модели(в директории MyApp\Models\Logs) для каждой из вышеуказанных таблиц логов(log_users и calls_log) и в контроллере UsersController(или ProfileController?) в методе profile получать объекты с данными логов авторизовавшегося юзера способом, как я описывал в предыдущем сообщении?
    А если нет, то как правильно?
ivashkevich 01.12.2019 в 21:14

Понятно, спасибо за детали.

  1. Да можно и так и так, смотря что есть профиль. Если пользователь, по сути, это и есть профиль, то можно в этом же контроллере. Если же сущность пользователя это вообще другое, то лучше отдельный контроллер.
  2. Да, вполне нормальное решение)
zeexo 01.12.2019 в 23:01

Спасибо, понял!
Подскажите, пожалуйста, насчёт ещё пары моментов:

  1. Если у меня в модели Models/Users/User.php нужно сделать дополнительную функцию, например я получил геттером поле со временем последней авторизации юзера в виде timestamp, и мне нужно конвертировать это в просто понятную для человека дату, допустимо ли добавить функцию конвертации сюда же, в модель User наследуемую от ActiveRecordEntity?
  2. Если не только в контроллере UsersController, но и в других контроллерах я хочу сделать методы, к которым клиент будет обращаться POST запросом через ajax, как лучше сделать проверку на это с точки зрения архитектуры, чтобы не делать в каждом нужном методе проверку if($_POST && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') { ... }, а вынести это в отдельную функцию? Куда, в какую модель выносить подобного рода функции?
ivashkevich 05.12.2019 в 14:41
  1. Да. Хоть прямо в геттере/сеттере выполняйте приведение.
  2. В роутниге по-хорошему разруливать тип запроса и в зависимости от типа вызывать разные экшены. То есть помимо просто роута в конфиге появляется еще тип запроса.
andreskrip 19.02.2020 в 18:07

Подскажите, пожалуйста, верной ли я дорогой вообще иду:
1) т.к. мы создаем для комментариев отдельную таблицу, то согласно ORM необходимо создать класс(модель) Comment. Я создал его в неймспейсе MyProject\Models\Articles (я посчитал, что комментарии — сущность, зависимая от статьи, и положил туда, но возможно надо было отдельную директорию создавать)?
2) Для вывода одиночной статьи, а также вывода комментариев к ней используется один и тот же роут, с одним и тем же экшеном (ArticlesController->view()), соответственно вся обработка данных от пользователя и передача в модель будет находиться тут? Если да, то каким образом передавать новые переменные во View (есть мысль использовать setVar, но в абстрактном контроллере он занимается передачей пользователя)

Заранее спасибо за внимание!

ivashkevich 19.02.2020 в 19:25
  1. Правильнее будет отдельный неймспейс завести
  2. Что мешает просто передать эти новые переменные в рендерер?
andreskrip 19.02.2020 в 20:48

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

public function view(int $articleId): void
    {
        $article = Article::getById($articleId);

        if ($article === null) {
            throw new NotFoundException();
        }
        //вывод всех комментариев относящихся к определенной статье
        $comments = Comment::getCommentsByArticleId($articleId);

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

public function addComment(): void
    {
        if (!empty($_POST)) {
            try {
                $comment = Comment::add($_POST, $this->user);
            } catch (InvalidArgumentException $e) {
                $this->view->renderHtml('articles/view.php', ['error' => $e->getMessage()]);
                return;
            }
            header('Location: /articles/' . $_POST['articleId'] . '#comment' . $comment->getId(), true, 302);
            exit();
        }
    }
ivashkevich 20.02.2020 в 04:27

Не понял про какой fatal error вы говорите, но по коду вообще все отлично

andreskrip 20.02.2020 в 12:41

когда в методе addComment ловится ошибка, то рендерится статья, но из-за отсутствия $article и $comments в переданных переменных (которые прописаны в методе view) выходит фатал еррор. Можно, конечно продублировать код метода view сюда, но мне кажется это плохое решение
ссылка на скрин

P.S. решил таким способом:

public function addComment(): void
    {
        if (!empty($_POST)) {
            try {
                $comment = Comment::add($_POST, $this->user);
            } catch (InvalidArgumentException $e) {
                $this->view->setVar('error', $e->getMessage());
                $this->view($_POST['articleId']);
                return;
            }
            header('Location: /articles/' . $_POST['articleId'] . '#comment' . $comment->getId(), true, 302);
            exit();
        }
    }

скрин
И эксепшн высвечивается, и комменты со статьей на месте. Единственное, не догадывался, что setVar не перезаписывает переменные, а добавляет к имеющимся (в сетваре же лежит информация о $user в абстрактном контроллере), но это уже прямой затык (взглянул бы сразу в класс View, то не было бы никаких догадок).

Такое решение проблемы допустимо?

ivashkevich 21.02.2020 в 06:28

Продублировать 2 строчки из view - самое простое и понятное решение. Это нормально, вам ведь нужно убедиться что статья существует, прежде чем добавлять к ней комментарий.

andreskrip 21.02.2020 в 13:29

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

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