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


Kirill.K 15.10.2018 в 21:16

ArticlesController:

...
if ($this->user->getRole() !== admin) {
            throw new Forbidden();
        }
...

Templates\errors\403:

<?php include __DIR__ . '/../header.php'; ?>
    <h1>Для добавления статьи нужно обладать правами администратора</h1>
<?php include __DIR__ . '/../footer.php'; ?>

Index:

catch (\MyProject\Exceptions\Forbidden $e) {
    $view = new \MyProject\View\View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', ['error' => $e->getMessage()], 403);
}
ivashkevich 15.10.2018 в 23:10

Хорошо, но в Templates\errors\403 стоит выводить переменную error в шаблоне, а не хардкодить текст ошибки.

А для проверки того, является ли юзер админом можно создать в модели User метод isAdmin, который будет это проверять:

if(!$user->isAdmin()) {
...
Kirill.K 16.10.2018 в 22:35

Так?:
User:

 public function isAdmin(): bool
    {
        return $this->role === admin;
    }

ArticlesController:

if(!$this->user->isAdmin()) {
            throw new Forbidden('Для добавления статьи нужно обладать правами администратора');
        }

Templates\errors\403:

<?php include __DIR__ . '/../header.php'; ?>
<?= $error ?>
<?php include __DIR__ . '/../footer.php'; ?>
ivashkevich 17.10.2018 в 00:39

Perfect!

Kirill.K 17.10.2018 в 19:43

Ещё хотел спросить - при отображении ошибки наша шапка с ником юзера слетает. Куки живы, но отсутствует объект $user, от наличия которого у нас зависит вывод. Как бы это исправить, не могу додуматься?

ivashkevich 19.10.2018 в 00:21

На странице с ошибкой не нужны данные о пользователе. Ошибка - это ошибка, больше ничего быть там не должно.

Kirill.K 19.10.2018 в 19:02

Хорошо) Но тогда нужно сделать отдельный HeaderForErrors:

<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title>Мой блог</title>
    <link rel="stylesheet" href="/styles.css">
</head>
<body>

<table class="layout">
    <tr>
        <td colspan="2" class="header">
            Мой блог
        </td>
    </tr>
    <tr>
        <td>

А то наш базовый предлагает войти или зарегистрироваться при выводе ошибки

ivashkevich 19.10.2018 в 21:55

Да, можно так.

andreskrip 15.02.2020 в 13:10

А нельзя просто передать во фронт-контроллере данные user и не делать новый шаблон?

 catch (\MyProject\Exceptions\ForbiddenException $e) {
    $view = new \MyProject\View\View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', ['error' => $e->getMessage(), 'user' => \MyProject\Services\UsersAuthService::getUserByToken()], 403);
}

У меня тогда всё отображается и в стандартном шаблоне

ivashkevich 18.02.2020 в 15:52

Не очень хорошо фронт-контроллеру обращаться к слою бизнес-логики. Он всё же должен решать архитектурные задачи.

tomsonst 20.12.2018 в 21:21
ArticlesController.php

if ($this->user->getRole !== 'admin') {
            throw new Forbidden();
        }

index.php

catch (\MyProject\Exceptions\Forbidden $e) {
    $view = new \MyProject\View\View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', ['error' => $e->getMessage(), 'user' => UsersAuthService::getUserByToken()], 403);
}

Создаем файл Forbidden.php и создаем шаблон 403.php

ivashkevich 22.12.2018 в 12:57

Хорошо

excent63 07.04.2019 в 11:41

Добрый день! д/з:

ArticlesController.php

public function add(): void
{
    if ($this->user === null) {
        throw new UnauthorizedException();
    }

    if ($this->user->getRole() !== 'admin') {
        throw new  ForbiddenException('У вас нет прав, за помощью обратитесь к администратору!');
    }
...

403.php

<?php include __DIR__ . '/../header.php'; ?>
    <strong><?= $error ?></strong>
<?php include __DIR__ . '/../footer.php'; ?>

index.php

...
 catch (\MyProject\Exceptions\ForbiddenException $e) {
    $view = new MyProject\View\View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', ['error' => $e->getMessage(), 'user' => \MyProject\Services\UsersAuthService::getUserByToken()], 403);
}
ivashkevich 08.04.2019 в 21:36

Отлично! У юзера можно завести отдельный метод:

public function isAdmin(): bool
{
    return $this->getRole() === 'admin';
}
excent63 08.04.2019 в 22:27

Вот дошёл уже до 31 урока, вроде задачи в домашках понятны, пока получается их решить))) Но вот не совсем доходит момент, когда нужно создать отдельный метод или какой тип этот метод должен отдать) Немного не понятно где создать тот или иной метод, видимо где то недочитал или недопонял) Надо как то оптимизировать своё обучение или начинать доводить блог до ума чтобы началось включение воображения, побольше практики или вернуться к началу и перечитать все по новой )))

ivashkevich 08.04.2019 в 22:33

Все придет с практикой, не переживай.

excent63 08.04.2019 в 22:35

Будем стараться) Главное что есть кому задать вопрос и получить на него правильный ответ! Спасибо за обучение!)

ivashkevich 09.04.2019 в 09:27

Пожалуйста)

Metey 25.07.2019 в 18:30

Вначале сделал, а затем учел некоторые рекомендации и немного переделал:
в index добавил ловлю эксепшнов:

catch (\MyProject\Exceptions\ForbiddenException $e) {
    $view = new \MyProject\View\View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', ['error' => $e->getMessage()], 403);
}

добавил метод isAdmin в User.php :

public function isAdmin(): bool
    {
        return $this->role === 'admin';
    }

и в метод ArticlesController add() :

if ($this->user === null) {
            throw new UnauthorizedException();
        }
        if (!$this->user->isAdmin()) {
            throw new ForbiddenException('Для доступа к данной странице необходимы права администратора!');
        }
........

сделал отдельно headerError.php и в нем изменил это :

<tr>
        <td colspan="2" style="text-align: right"> 
            <a href="/users/login">Войти как администратор</a> |
            <a href="/users/register">Зарегистрироваться</a>
        </td>
    </tr>
ivashkevich 25.07.2019 в 18:56

А для чего headerError.php? Не вижу, чтобы он где-то использовался.

Metey 25.07.2019 в 19:14

забыл сюда вставить шаблон 403.php

<?php include __DIR__ . '/../headerError.php'; ?>
    <h1><?= $error ?></h1>
<?php include __DIR__ . '/../footer.php'; ?>
ivashkevich 25.07.2019 в 19:17

Так ведь, то что прав нет, ещё не означает, что пользователя надо просить войти. Ну да ладно, это уже вопрос бизнес логики. В целом ок.

Metey 25.07.2019 в 19:19

понял)) спасибо, возьму на заметку

Iliusha99 03.08.2019 в 16:42
Articles Controller:
if ($this->user->getRole() !== 'admin'){
            throw new AccessForbidden('Forbidden', 403);
        }

User Model:
public function getRole(): string
    {
        return $this->role;
    }

index.php:
...
catch (AccessForbidden $e) {
    $view = new View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', ['error' => $e->getMessage()], 403);
}
ivashkevich 03.08.2019 в 20:36

Норм. Но проверку на то, что юзер админ стоит проверять на уровне модели. Для этого стоит завести в ней метод isAdmin(): bool

Moskva 07.08.2019 в 15:53

User.php

...
    public function IsAdmin(): bool
    {
        return $this->role === 'admin';
    }
...

ArticlesController.php

public function add(): void // добавление статьи в БД
    {
        if($this->user === null){
            throw new UnauthorizedException();
        }
        if(!$this->user->IsAdmin()){
            throw new ForbiddenException();
        }
...

index.php

...
} catch (\MyProject\Exceptions\ForbiddenException $e){
    $view = new \MyProject\View\View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', ['error' => $e->getMessage(), 'user' => \MyProject\Services\UsersAuthService::getUserByToken()], 403);
}

403.php

<?php include __DIR__ . '/../header.php'; ?>
<h1>У вас нет прав администратора.</h1>
<?php include __DIR__ . '/../footer.php'; ?>
ivashkevich 07.08.2019 в 18:50
public function IsAdmin(): bool

Имена методов пишутся с маленькой буквы.

В остальном все хорошо.

Reechniy 02.09.2019 в 13:48
index:

 catch (\MyProject\Exceptions\ForbiddenException $e) {
    $view = new \MyProject\View\View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', ['error' => $e->getMessage()], 403);
}
 User:

 public function isAdmin(): bool
    {
        return $this->role === 'admin';
    }

AticleController:

        if(!$this->user->isAdmin()) {
            throw new ForbiddenException('Недостаточно прав, для добавления статьи');
        }

        $this->view->renderHtml('articles/add.php');
        return;
    }

Создал исключение ForbiddenException.php и 403.php как у всех
ivashkevich 02.09.2019 в 18:47

Отлично

artemship 05.09.2019 в 17:47

User:

    public function isAdmin(): bool
    {
        return $this->role === 'admin';
    }

ArticlesController:

    public function add(): void
    {
        if (!$this->user->isAdmin()) {
            throw new ForbiddenException('Статьи могут добавлять только администраторы');
        }
    ...

index.php:

} catch (ForbiddenException $e) {
    $view = new View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', [
        'error' => $e->getMessage(),
        'user' => UsersAuthService::getUserByToken()
    ], 403);
}

403.php:

<?php include __DIR__ . '/../header.php'; ?>
    <h1>Недостаточно прав</h1>
    <?= $error ?>
<?php include __DIR__ . '/../footer.php'; ?>
ivashkevich 05.09.2019 в 19:47

Супер

zeexo 10.12.2019 в 18:07

А как быть, если запрос через ajax и ответ нужно получить в json?

ArticlesController.php:

if(!$this->user->isAdmin()) {
    $this->view->displayJson(['error' => ['message' => 'У вас нет прав'], 403]);
    return;
}

Насколько это правильное решение?
Или лучше через исключение, но как тогда это реализовать?
И ещё вопрос, как сделать при ловле исключения UnauthorizedException редирект Header('Location: ...) ?

ivashkevich 11.12.2019 в 17:56

Это норм решение.

По поводу редиректа при исключении при работе с API - звучит во-первых странно. Во-вторых, ваш вопрос содержит ответ. При ловле исключения отправлять заголовок с помощью header'а location. Не знаю, что еще добавить.

zeexo 12.12.2019 в 21:05

Спасибо за подсказку.
Наверное стоило точнее объяснить.

С учётом того, что у нас index.php ловится(как в уроках) исключение:

catch (\App\Exceptions\UnauthorizedException $e) {
    $view = new \App\View\View();
    $view->renderHtml('errors/401.php', ['error' => $e->getMessage()], 401);
}

Пытаюсь сделать добавление новости через jquery ajax отправку формы.
Насколько правилен с точки зрения mvc такой подход и можно ли так работать с исключениями?

class ArticlesController extends AbstractController
{
    public function add()
    {
        try {
            $user = $this->user;
            if($user === null) {
                throw new UnauthorizedException('Вы не авторизованы!');
            }

            $report = Article::createFromArray($_POST, $this->user);
            $this->view->displayJson([
                'result' => ['message' => 'success']
            ]);

        } catch (UnauthorizedException $e) {
            $this->view->displayJson([
                'error' => ['message' => $e->getMessage()]
            ], 401);
        } catch (InvalidArgumentException $e) {
            $this->view->displayJson([
                'error' => ['message' => $e->getMessage()]
            ]);
        }
    }
}
ivashkevich 14.12.2019 в 15:23

Прям так не очень. Лучше сделать ещё отдельные исключения для API. Например, делаете ещё APIUnauthorizedException, и его ловите во фронт-контроллере, и там уже делаете:

            $view->displayJson([
                'error' => ['message' => $e->getMessage()]
            ], 401);

А в основном контроллере ловите доменное исключение, и преобразуете в исключение API:

        } catch (UnauthorizedException $e) {
            throw new APIUnauthorizedException($e->getMessage(), $e->getCode(), $e);
        }
zeexo 14.12.2019 в 16:24

Понял) Спасибо!
Но то, что содержимое методов контроллера ArticlesController(add, edit, view) сразу идёт в блоке try/catch, то есть полностью построены на исключениях, как в моём примере выше - это нормальная практика?

ivashkevich 14.12.2019 в 18:27

Да, обрабатывать в контроллере исключения уровня модели - это абсолютно нормально.

zeexo 25.12.2019 в 02:40
        } catch (UnauthorizedException $e) {
            throw new APIUnauthorizedException($e->getMessage(), $e->getCode(), $e);
        }

Допустим!
Но как разруливать ситуацию, если в разных контроллерах может быть три типа действий при ловле исключения UnauthorizedExpection:
1.

$view->renderHtml('errors/401.php', ['error' => $e->getMessage()], 401);

2.

$view->displayJson([
                'error' => ['message' => $e->getMessage()]
            ], 401);

3.

header('Location: /'); //то есть просто редирект

Тогда лучше убрать ловлю исключения UnauthorizedException из index.php ?

ivashkevich 26.12.2019 в 19:04

Для НЕ API можно бросать другое исключение, которое будет обрабатываться по-другому.

        } catch (UnauthorizedException $e) {
            throw new AppUnauthorizedException($e->getMessage(), $e->getCode(), $e);
        }
andreskrip 15.02.2020 в 13:13

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

ArticlesController.php

    public function create(): void
    {
        ...
        if (!$this->user->isAdmin()){
            throw new ForbiddenException();
        }
        ...
    }

index.php

}  catch (\MyProject\Exceptions\ForbiddenException $e) {
    $view = new \MyProject\View\View(__DIR__ . '/../templates/errors');
    $view->renderHtml('403.php', ['error' => $e->getMessage(), 'user' => \MyProject\Services\UsersAuthService::getUserByToken()], 403);
}

templates/errors/403.php

    <h1>У вас не достаточно прав</h1>
    <p>Создавать статьи могут только пользователи с правами администратора</p>
ivashkevich 18.02.2020 в 15:52

Отлично

New 21.03.2020 в 22:39

Можно было и функционал добавления статей в домашку отправить). Как-то легко пошел этот урок.
Но вопрос таки есть:

header('Location: /articles/' . $article->getId(), true, 302);

Для чего тут явно было указано true и код? По умолчанию же те же параметры?

ivashkevich 22.03.2020 в 06:49

Где вы увидели 302 по умолчанию?

New 22.03.2020 в 11:36

По умолчанию в данном случае)). В первую очередь практически проверил, не указав ни параметр replace ни код. При выполнении данной функции в коде- проверил через инспектор кода в части обмена заголовками. Получаем код 302, хотя это не было указано в параметрах функции. Это же редирект/код 302? Код 201, 3хх ранее не устанавливали.

Ну и из документации:

Другим специальным видом заголовков является "Location:". В этом случае функция не только отправляет этот заголовок браузеру, но также возвращает ему код состояния REDIRECT (302), если ранее не был установлен код 201 или 3xx.

Необязательный параметр replace определяет, надо ли заменять предыдущий аналогичный заголовок или заголовок того же типа. По умолчанию заголовок будет заменен

У нас же в коде явный редирект?

Я не совсем понял этот момент, поэтому и вопросы.

Не очень понятны ситуации, когда будет использован параметр false.

Описание функции читал несколько раз, примеры пользователей тоже, но пока не въехал.

ivashkevich 22.03.2020 в 17:44

Ок, не знал что при передаче в заголовке Location будет автоматически передан код 302.

false может передаваться когда нужно вернуть в ответе несколько заголовков с одним именем, но разными значениями. Для чего так делать - не знаю, на практике ни разу не сталкивался.

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