Будучи back-end разработчиком, я всеми фибрами своей души люблю микросервисные архитектуры, но еще больше, люблю разрабатывать микросервисы. При разработке, чего бы то ни было, я придерживаюсь одного простого принципа – минимализм. Под минимализмом я подразумеваю простую истину: код должен быть максимально «прозрачным», его должно быть минимум (идеальный код – код которого нет), а посему, я делаю ставку в пользу аннотаций.


В настоящей статье, я представлю вашему вниманию скелет для будущих приложений, в котором аннотации используются для решения следующих задач:



Такой скелет будет основан на следующих пакетах:



Также, такой скелет, будет основан на пакетах придерживающихся следующих PSR-рекомендаций:



В настоящей статье, я не стану рассказывать, что такое composer, про избитую "луковицу", и уж тем более о PSR, предполагается, что вам все это уже знакомо в той или иной степени.


Лень читать, что там?
composer create-project sunrise/awesome-skeleton app

wheel bike


Контроллеры


Как правило, вне зависимости от того, какие инструменты мы используем, у нас всегда маршрутизация отдельно, контроллеры отдельно, я сейчас не беру в счет Symfony Routing, это немного про другое.


Маршрутизация в контроллерах


Рассмотрим пример ниже:


declare(strict_types=1);
namespace App\Http\Controller;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * @Route(
 *   id="resource.update",
 *   path="/resource/{id<\d+>}",
 *   methods={"PATCH"},
 *   before={
 *     "App\Http\Middleware\FooMiddleware",
 *     "App\Http\Middleware\BarMiddleware"
 *   },
 *   after={
 *     "App\Http\Middleware\BazMiddleware",
 *     "App\Http\Middleware\QuxMiddleware"
 *   }
 * )
 */
class ResourceUpdateController implements MiddlewareInterface
{
    /**
     * {@inheritDoc}
     */
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler) : ResponseInterface
    {
        $response = $handler->handle($request);

        // some code

        return $response;
    }
}

Вы наверняка обратили внимание, что контроллер является промежуточным ПО, как и в Zend Expressive, более того, через аннотации можно указать какие промежуточные ПО будут запущены перед запуском настоящего контроллера, а какие после.


Аннотация @­Route может содержать следующие свойства:


  • id – ID маршрута
  • path – правило пути маршрута
  • methods – допустимые HTTP методы маршрута
  • before – промежуточные ПО которые запустятся перед запуском контроллера
  • after – промежуточные ПО которые запустятся после запуска контроллера

Путь маршрута содержит привычную для всех конструкцию {id}, однако для валидации атрибута необходимо задать регулярное выражение {id<\d+>}, а если необходимо сделать часть пути необязательной, ее достаточно взять в скобки /resource/{action}(/{id}).


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


Инъекция зависимостей в контроллерах


Рассмотрим пример ниже:


declare(strict_types=1);
namespace App\Http\Controller;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Psr\Log\LoggerInterface;

/**
 * @Route(
 *   id="resource.update",
 *   path="/resource/{id<\d+>}",
 *   methods={"PATCH"}
 * )
 */
class ResourceUpdateController implements MiddlewareInterface
{
    /**
     * @Inject
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * {@inheritDoc}
     */
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler) : ResponseInterface
    {
        $this->logger->debug('foo bar');

        $response = $handler->handle($request);

        // some code

        return $response;
    }
}

Нет ничего проще, чем получить из контейнера ту или иную зависимость...


Регистрация контроллера в приложении


Вам достаточно просто создать контроллер, остальное приложение сделает за вас, обнаружит такой контроллер, передаст его маршрутизатору, который запустит его при необходимости… Что может быть проще? Главное, что от вас требуется из коробки, создавать контроллеры в директории src/Http/Controller.


wheel bike


Модели


Если вы работали с Doctrine ORM и Symfony Validator, для вас ничего интересного, за исключением того, что все настроено из коробки, для остальных представлю некоторые примеры. Сразу необходимо обозначить, что модели должны создаваться в директории src/Entity и наследовать App\Entity\AbstractEntity.


Простой пример модели


Рассмотрим пример ниже:


declare(strict_types=1);
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 * @ORM\Table(name="resource")
 */
class Resource extends AbstractEntity
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     *
     * @var null|int
     */
    protected $id;

    /**
     * @ORM\Column(
     *   type="string",
     *   length=128,
     *   nullable=false
     * )
     *
     * @Assert\NotBlank
     * @Assert\Type("string")
     * @Assert\Length(max=128)
     *
     * @var null|string
     */
    protected $title;

    /**
     * @ORM\Column(
     *   type="text",
     *   nullable=false
     * )
     *
     * @Assert\NotBlank
     * @Assert\Type("string")
     *
     * @var null|string
     */
    protected $content;

    // setters and getters
}

Опять же, нет необходимости где бы то ни было регистрировать нашу модель, нет необходимости описывать где-то валидацию, или схему таблиц, все в одном месте, просто и понятно. Единственное, что необходимо сделать, чтобы таблица resource создалась, запустить из корня приложения следующий скрипт:


composer db:update

Настройки подключения к базе данных находятся в файле: src/config/environment.php


Простой пример использования модели в контроллере


declare(strict_types=1);
namespace App\Http\Controller;

use App\Entity\Resource;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * @Route(
 *   id="resource.create",
 *   path="/resource",
 *   methods={"POST"}
 * )
 */
class ResourceCreateController implements MiddlewareInterface
{
    /**
     * @Inject
     *
     * @var EntityManager
     */
    protected $entityManager;

    /**
     * {@inheritDoc}
     */
    public function process(
        ServerRequestInterface $request,
        RequestHandlerInterface $handler) : ResponseInterface
    {
        $data = (array) $request->getParsedBody();
        $response = $handler->handle($request);

        $resource = new Resource();
        $resource->setTitle($data['title'] ?? null);
        $resource->setContent($data['content'] ?? null);

        $violations = $resource->validate();
        if ($violations->count() > 0) {
            return $response->withStatus(400);
        }

        $this->entityManager->persist($resource);
        $this->entityManager->flush();

        return $response->withStatus(201);
    }
}

Аннотация @­Assert отвечает за валидацию, сама логика валидации описана в наследуемом моделью классе AbstractEntity.


Реализация несет демонстрационный характер, целью автора является сократить кол-во строк кода...


wheel bike


Настройки приложения


Файл Описание
config/cli-config.php Doctrine CLI
config/container.php PHP-DI
config/definitions.php Зависимости приложения
config/environment.php Конфигурация окружения приложения

Свои зависимости


Для добавления новой зависимости в приложение, достаточно открыть файл config/definitions.php, и добавить новую зависимость по аналогии с уже существующими, после чего она станет доступна через инъекции, как в примерах настоящей статьи.


Рекомендации


После установки скелета, рекомендуется добавить файл config/environment.php в .gitignore, а сам файл как пример продублировать с новым именем:


cp config/environment.php config/environment.php.example

Можно пойти другим путем, заполнив настройки окружения из .env задействовав пакет symfony/dotenv.


wheel bike


В игру «зачем писать это, когда есть это» можно играть бесконечно, но как бы там ни было, open-source все стерпит...


Для установки скелета воспользуйтесь следующей командой:


composer create-project sunrise/awesome-skeleton app

Для изучения исходного кода скелета воспользуйтесь ссылкой: sunrise/awesome-skeleton.




Отдельное спасибо хочется выразить Оскару Отеро за его вклад в open-source, в особенности за прекрасную подборку Awesome PSR-15 Middleware, часть из которой интегрирована в sunrise/awesome-skeleton.

Комментарии (55)


  1. Psih
    08.01.2019 18:46

    Всё бы ничего, но где репозиторий и сервис? Писать в контроллер обновление модели — это то, чего делать не стоит. Давайте не лениться и давать людям скелеты, которые подходят для реальных приложений, а не CRUD на 5 страничек.


    1. fenric Автор
      08.01.2019 20:28

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


  1. a-tk
    08.01.2019 20:08

    Как-то я из статьи не понял, кто и на каком этапе должен прожевать эти аннотации.


    1. fenric Автор
      08.01.2019 20:40

      Если говорить о том, что "прожевывает" аннотации, или точнее сказать "разбирает" их, то это doctrine/annotation. Если говорить о зонах ответственности, то за инъекции отвечает PHP-DI, за маршрутизацию Sunrise Router, за валидацию свойств моделей Symfony Validator, а за работу с БД и моделей в целом Doctrine ORM.


      1. a-tk
        08.01.2019 20:58

        После разбора что получается и куда оно идёт дальше?


  1. dzsysop
    08.01.2019 22:13

    Давно ищу информацию по чистым аннотациям как можно меньше всего завязанных на конкретный фрэймворк.
    Вы пишите:

    Аннотация @­Route может содержать следующие свойства:

    А где можно почитать подробную документацию по этой аннотации по всем свойствам которые она поддерживает. А так же какие еще есть аннотации.

    Когда я попытался разобраться, это оказалось не так просто. Файлы аннотаций встроены в пакеты Symfony Components и слабо документированы. Не могли бы вы дать пару ссылок на подробную документацию по аннотациям?


    1. progit
      08.01.2019 22:36

      Конкретно работа с Doctrine Annotations описана достаточно хорошо в офф доке — https://www.doctrine-project.org/projects/doctrine-annotations/en/latest/index.html


      1. dzsysop
        08.01.2019 22:43

        А что насчет @­Route?

        И даже по вашей ссылке — нет там списка всех параметров и их форматов.
        То что я вижу на странице по вашей ссылке очень далеко от «достаточно хорошо».


        1. porn
          09.01.2019 02:52

          А что насчет @­Route?
          habr.com/post/435434/#comment_19593018
          нет там списка всех параметров и их форматов
          Ну вот же там ссылка: Read more about custom annotations.


        1. progit
          09.01.2019 10:11

          А вас что именно интересует? Как использовать свои аннотации? Или список всех параметров уже описанных кем-то аннотаций?


          Если речь идет про Route из статьи, то вот ее исходник, а документация доступна тут. Большим, к сожалению, не владею =)


          Для примера хорошей аннотации, имхо: Route из Symfony. Можно посмотреть список всех доступных параметров прямо в коде и есть хорошее описание в официальной доке Symfony


    1. fenric Автор
      09.01.2019 05:08

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


  1. garex
    08.01.2019 23:12
    +2

    Кода у вас меньше не стало, он просто уехал в phpdoc. Минусы аннотаций — программирование конфигов, не всегда есть поддержка IDE из-коробки, повышение связанности слоёв.


    Модели почему что-то знают о персистировании себя? Это — задача ОРМа из слоя инфраструктуры. Аннотации могут замарать слой бизнес-логики.


    Хотя с другой стороны конфиг, который используется вот только для этого экшена контроллера крайне удобен рядом с экшеном. Ок, допустим. Но тогда конфиг ли это? Я хочу разеюзать ваш код в другом проекте и для того, чтобы поменять что-то в конфиге мне надо лезть в… код! Как-то не реюзабельно получается. М.б. это имеет право на жизнь только в малых проектах, которые точно не реюзабельны?


    ps: У меня лично на аннотации аллергия ))


    1. dzsysop
      08.01.2019 23:46
      +1

      Я вижу проблему несколько под другим углом. Аннотации прекрасно работают внутри фрэймворков. Зачастую фрэймфорки могут сами генерировать код PHP, читая какие-то конфиги, насколько я понимаю.

      Для меня основная проблема это использование этой фичи в самописных фрэймворках и проектах. Что-то у меня пока не получается прикрутить аннотации без того чтобы мне было всасывать тот же Doctrine в проект. Вот хочу я юзать Route, но я не вижу документации, я не понимаю, где я могу прочесть весь список того что эта аннотация поддерживает и кто ее поддерживает. Все примеры построены на том что все зависимости уже втянуты и состыкованы между собой магическим образом.


      1. garex
        09.01.2019 00:08

        См. конструктор класса Route — там всё есть.


        https://github.com/sunrise-php/http-router/blob/6c537b045908e9f37c6ca9deeab41d51902d8cd7/src/Route.php


        Правда не понятно, почему нету use Sunrise\Http\Router\Route. Это уже магия нехорошая.


        1. dzsysop
          09.01.2019 00:55

          Посмотрел:

          /**
          	 * Constructor of the class
          	 *
          	 * @param string $id
          	 * @param string $path
          	 * @param string[] $methods
          	 */
          	public function __construct(string $id, string $path, array $methods)
          	{
          		$this->setId($id);
          		$this->setPath($path);
          		foreach ($methods as $method)
          		{
          			$this->addMethod($method);
          		}
          	}


          И ничего не увидел. Я спрашивал:
          но я не вижу документации, я не понимаю, где я могу прочесть весь список того что эта аннотация поддерживает и кто ее поддерживает


          Не вижу как это конструктор отвечает на мой вопрос.


          1. garex
            09.01.2019 01:01

            Это уже к автору поста/пакета пишите иссую на гитхаб.


          1. fenric Автор
            09.01.2019 05:18

            То, что вы смотрите, не аннотация, а маршрут. Маршрутизатор из коробки не поддерживает аннотации, для их поддержки я написал отдельный пакет:
            https://github.com/sunrise-php/http-router-annotations-support
            А саму аннотацию вы можете увидеть здесь:
            https://github.com/sunrise-php/http-router-annotations-support/blob/master/src/Annotation/Route.php
            Я не сторонник мешать все все и вся, а посему такой пакет вынесен в отдельный репозиторий.


            1. garex
              09.01.2019 07:00

              Когда даётё ссылку на гитхаб, используйте клавишу "y", чтобы ссылка была абсолютная. Через ИКС лет там не факт, что будет тоже самое.


              https://github.com/sunrise-php/http-router-annotations-support/blob/fdaebf65bc65d208e573dce99f700ff38b987c08/src/Annotation/Route.php


        1. fenric Автор
          09.01.2019 05:15

          Отсутствие use это не магия, это недостаток текущей версии Doctrine Annotations, который обещают исправить, если я сейчас не ошибаюсь, в 3 версии. Вся "магия", как вы выражаетесь, заключается в том, что при сборке ридера, я ему скармливаю автозагрузчик классов, таким образом, ридер знает как связать аннотацию с классом. Таким образом, нам нет необходимости писать лишнее, и включать в каждом контроллере аннотацию вручную.


          1. garex
            09.01.2019 06:59

            Не соглашусь. А если я хочу свою Route добавить, которая вашу экстендит? Дописывать куда-то в автозагрузчик это? Или имена аннотаций д.б. уникальны в этом случае? Тоже как-то так себе.


            Это к тому, что если можно перебить класс аннотации, то конечному читателю кода эта магия опять же неочевидна будет.


      1. garex
        09.01.2019 01:03

        Другой вариант, что аннотации дёргают setter'ы, а не конструктор. Опять магия, что есть зло.



      1. pbatanov
        09.01.2019 15:30

        Сами по себе аннотации ничего не делают, по факту это лишь типизированный и структурированный кусок текста, у которого есть возможность задавать поля и некоторая их валидация. Список полей и валидация — все это можно узнать посмотрев в код конкретной аннотации, это простой PHP объект, сам по себе он не несет никакой логики, это по сути своей VO.

        Правила игры задает код (сервисы), который эти аннотации анализирует. Вы можете одну и ту же аннотацию обрабатывать разными сервисами и получать разный результат.

        Например есть роутер симфони, который в качестве одного из источника роутов может считывать свои аннотации с класса и методов контроллера. Все что он делает — это с помощью одного из загрузчиков считывает аннотации, преобразовывает во внутренний формат и конфигурирует роутер. Аналогично с мэппингами доктрины, валидатором симфони и других компонент. Есть аннотация которая задает структуру и есть код, который эту структуру загружает во внутреннюю конфигурацию компонента с помощью специального загручика. Чаще всего он может это делать и из других форматов.

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


    1. fenric Автор
      09.01.2019 05:37

      У Zend Expressive есть "трюк", как использовать экшены к контроллере, это легко повторяется в Sunrise Router, так как специфика контроллера ± схожа.


  1. kruslan
    09.01.2019 00:32
    +1

    /**
     * @Route(
     *   id="resource.update",
     *   path="/resource/{id<\d+>}",
     *   methods={"PATCH"},
     *   before={
     *     "App\Http\Middleware\FooMiddleware",
     *     "App\Http\Middleware\BarMiddleware"
     *   },
     *   after={
     *     "App\Http\Middleware\BazMiddleware",
     *     "App\Http\Middleware\QuxMiddleware"
     *   }
     * )
     */
    


    Сорри, но это жесть. Половина кода в комментах…


    1. fenric Автор
      09.01.2019 05:32

      Аннотации можно как любить, так и наоборот. Кто-то строит маршрутизацию на массивах, кто-то напрямую через API (Sunrise Router имеет API), а можно по средствам аннотаций, тут как говорится, на вкус и цвет.


      1. kruslan
        09.01.2019 12:23

        К аннотациям я отношусь достаточно спокойно. И использую их, как-раз для роутинга. Вот, например, из предыдущего проекта:

        /**
        	 * @route /backend/users/add --method=get --name=backend/users/add
        	 * @route /backend/users/edit/{id:\d+} --method[]=get --method[]=post --name=backend/users/edit
        	 * @throws NotFound
        	 */
        


        Но в вашем случае, в аннотации уже логика.


  1. rustacean137
    09.01.2019 05:19

    Аннтоации в PHP-DI удобны, в symfony/di неудобство начинается, когда необходимо внедрить скалярные параметры, либо когда необходимо добавить теги, на мой взглядь не помешало бы аннотации для них.
    (да, можно самому сделать в компайл тайм, но хотелось бы из коробки, + поддержку IDE)




    Жаль что rfc по аннотациям не приняли, пока неудобно писать свои аннотации, т.к. необходимо предусмотреть кеш, и поддержка IDE не будет.




    Кстати, IDE поддерживает аннотации в PHP-DI?


    1. fenric Автор
      09.01.2019 05:42

      На сколько мне известно, поддержки аннотаций в IDE у PHP-DI нету. Есть поддержка контейнера, но это другая история. Я задал вопрос Мэтью в гиттере, появится ли такая возможность, самому стало интересно.


  1. BuPy7
    09.01.2019 09:59

    Я, конечно, извиняюсь, но внедрение зависимостей через @Inject не клева, как минимум, это нетестируемо и нарушает инкупсуляцию. В тестах придется постоянно делать обертки над классом, а самим классах использовать модификатор доступа не ниже, чем protected. Можно, конечно, и private, чтобы большую часть времени тратить на простыни с рефлексией… И я не говорю уже о IDE, которая подсветит это свойство, как неопределенное, и чтобы разрешить эти предупреждения нам придется искать какой-то плагин… З а ч е м? Мое мнение, внедрять зависимости очевидным способом через конструктор — здорово. А лучше вообще хранить конфиги отдельно от кода и начать дружить с принципом единственной ответственности.


    1. avengerweb
      09.01.2019 15:29

      Соглашусь, при таком подходе, искать по всему проекту, особенно если он не ваш, какой контроллер отвечает за конкретный адрес довольно не удобно. А Inject выглядить более-менее, если зависимость только 1, что неверно для большей части кода, в любом случае отсутсвие конструктора, выглядить всегда странно, иди потом объясни джуну что за магии тут твориться.


    1. Fantyk
      11.01.2019 03:56

      Тоже поддержу. Даже отойдя от темы аннотаций, видеть все зависимости класса явно — одно из условий «хорошего» кода. Причем это опять же «универсально» (если уж мы стремимся к поддержке psr), так как код с конструкторами получается фреймворк агностик.

      Зачем писать middleware тоже не понял. Очень удобно в каждом контроллере это копипастить и еще удобнее рефакторить (НЕТ!).


      1. a-tk
        11.01.2019 08:44
        +1

        Аспектно-ориентированное внедрение зависимостей тем и хорошо, что позволяет сократить визуальный шум.


        1. oxidmod
          11.01.2019 11:35

          Это было бы так, если бы аннотации были частью языка. Если бы эти условные inject подразумевали неявно объявленный конструктор. В PHP, к сожалению, это не так.


          1. a-tk
            11.01.2019 12:21

            В PHP аннотации суть комментарии, в языке же аннотаций, атрибутов и т.п. нет.
            Отчасти причиной является его динамическая природа, которая даже файлы загружает динамически. И рефлексия у него ограничивается по этой же причине достаточно примитивными вещами.


  1. BoShurik
    09.01.2019 12:33

    Почему используется именно sunrise/http-router?


    Мне кажется у вас ошибка в бенчмарках роутера. Вы тестируете скорость инициализации роутов (к примеру, у симфони роутинг компилируемый), таким образом матчинг роутов уходит на второй план.
    Плюс заявленную поддержку аннотаций можно таким образом приделать к любому роутеру.


  1. Khaperets
    09.01.2019 13:10

    Поддерживаю автора в пользу аннотаций, только примеры в статье не особо подходящие. И сеттинг данных из запроса можно делать аннотациями в DTO, Entity… Мое виденье.


  1. viirtus
    09.01.2019 13:14

    Если и использовать аннотации по-максимуму, то нужно как минимум не забыть про AOP, а именно Transactional аннотацию. Опыт использования в Spring исключительно положительный.


  1. rjhdby
    09.01.2019 13:21
    +1

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

    Поэтому давайте добавим в него магии! Вжух! Вот вам мешок как-бы аннотаций (которые, на самом деле, просто распарсенные комментарии)!.. Ну ладно, я пошел, а как оно работает — сами разбирайтесь.


  1. denis24
    09.01.2019 15:30

    Хотелось бы сказать спасибо автору. Узнал много нового.


  1. boblgum
    09.01.2019 15:30

    изыди!
    публично пороть надо за использование и тем более пропаганду таких "трюков" как аннотации


  1. danial72
    09.01.2019 17:38
    +3

    Т.е. по сути это декларативный код, который описан в комментариях?
    Не понимаю преимуществ над просто кодом.
    Слишком много магии получается, удобно, но не очень интуитивно.


    1. w0den
      09.01.2019 19:07

      Ну как же! Главное преимущество — написать правильный Hello World. Теперь с аннотациями.
      Ещё можно добавить в резюме: Уверенный пользователь «PHP Comments».


      1. dzsysop
        09.01.2019 19:13

        Я могу понять ваш сарказм. Но если девелопер сможет написать «Hello World» на PHP c нуля написав MVC свои классы, без внешних зависимостей, да еще и через аннотации за 2 часа на интервью — я его сразу порекомендую на синьора или даже лида в любой проект на PHP.


        1. t_kanstantsin
          09.01.2019 21:22

          Вспоминается знаменитый троллейбус.


          написав MVC свои классы, без внешних зависимостей, да еще и через аннотации за 2 часа на интервью

          Но зачем? По-моему, если предлагают такой хренью заниматься на собеседовании — лучше срау уходить.


          1. a-tk
            09.01.2019 22:49
            +1

            Смотря на какую позицию и смотря как это происходит.


        1. rjhdby
          10.01.2019 10:39

          А что тут сложного?


          1. dzsysop
            10.01.2019 14:25
            +1

            Если вам не сложно, потратьте 2 часа своего времени и выполните. Не в службу, а в дружбу. Положите на гитхаб. Я буду очень, очень, очень признателен. Мне реально очень помогло бы для моей работы.

            Возможно кто-то тут тоже поддержит мой запрос.

            Ключевое:

            1. Ноль внешних зависимостей.
            2. MVC
            3. Модели определяют свои поля через аннотации
            4. Контроллеры определяюит свои routes, action и их параметры через аннотации


            Это что-то, что я ожидал увидеть здесь, согласно заголовку. Но оказалось, к сожалению, что снова слишком много composer required чтобы разобраться в механизмах магии.

            Так что если для вас это «запросто, за 2 часа», то я был бы очень признателен.


            1. rjhdby
              10.01.2019 16:29

              С вас нормальное ТЗ, тогда можно будет начать обсуждать сроки (вы же понимаете, что за два часа это будет именно "Hello world"?) и оплату (да, мне жалко тратить время на не нужную мне вещь и реализовывать порочные, с моей точки зрения, практики, чтобы кому-то что-то доказать).
              На вскидку:
              Пункты 1, 3, 4 реализуются через наследование, token_get_all и, в зависимости от хотелок, рефлексию.
              По поводу пункта 2 только на хабре было множество статей, объясняющих "что же это такое на самом деле". И каждая по своему. Вам какой вариант больше нравится?


              1. dzsysop
                10.01.2019 17:38

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

                ТЗ на мой взгляд достаточное. Свобода у разработчика данного задания на собеседовании полная. Меня бы устроил любой вариант реализации.

                вы же понимаете, что за два часа это будет именно «Hello world»?


                Да я понимаю. И именно это я и имел в виду. И, извините, я подозреваю даже для вас, если вы и понимаете как это сделать архитектурно и в коде, 2 часа точно мало, а возможно и 4 мало.

                Так что моя просьба о помощи, скорее была в поддержку того, что задачка далеко не тривиальная. И ответ Вам: «а чего тут сложного». Сложно то что никто кроме Вас пока даже не заявил что это просто. А вы затребовали деньги и ТЗ.

                Скажу за себя, я бы смог наверное сделать это все на коленке но без аннотаций. И у меня было бы ноль магии.


                1. rjhdby
                  10.01.2019 18:05
                  +1

                  Я вас именно на слове пытался поймать

                  Ну вот не получилось :)

                  При полной свободе интерпретации ТЗ на написание уровня «фигак-фигак, здравствуй мир» пары часов должно хватить, плюс/минус. Задача, сама по себе, не подразумевает каких-то уникальных знаний и умений, но она, скажем так, объемная и мало что может показать в плане собеседования именно потому, что за 2 часа это будет именно «фигак-фигак».

                  PS Не скажу за весь остальной мир, но то, каким образом реализуют аннотации в PHP — это костыль в велосипедном колесе, бессмысленный и беспощадный.


                  1. dzsysop
                    10.01.2019 18:13
                    -2

                    Ну вот не получилось :)

                    Не согласен.
                    Пусть народ голосует:

                    если согласны со мной, что получилось и задача не тривиальная — голос за этот коммент

                    Если согласны с Вами, и что я ничего не показал, а задачка «не сложная» — голос за ваш предыдущий коммент

                    Спорить тут, согласен, особо не о чем. Все остались при своих мнениях.


  1. 96467840
    09.01.2019 18:09
    +4

    ИМХО!
    аннотации != «код которого нет»
    аннотации == «код который не понимает ни один редактор» (это все равно что взять блокнот и писать код в нем)

    как итог ни нормальной подсветки синтаксиса, ни подсказок и когда упадет будешь очень долго и нудно ползать по коментариям и разгребать


    1. mmasiukevich
      10.01.2019 15:03
      +1

      справедливости ради шторм их прекрасно понимание (с помощью плагина, но тем не менее) и с тем же автокомплитом проблем никаких нет.


  1. Mabusius
    09.01.2019 18:49
    +2

    «А здесь мы прикрутим аннотации, чтобы ты мог писать код, даже когда ты пишешь комментарии»