За последние 24 часа нас посетили 18089 программистов и 1609 роботов. Сейчас ищут 1369 программистов ...

Учебные мысли, про создание простого блога

Тема в разделе "Laravel", создана пользователем Dimon2x, 19 авг 2018.

  1. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    Мне надо расписать, всё подробно, как я учусь создавать проект, правильно ли я всё думаю, где-нибудь я ошибся в тексте?

    Начало

    https://github.com/Div-Man/laravel-image

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

    Потом переименовал шаблон welcome в index, потом создал шаблон для вывода всех
    изображений и укаазал шаблонизаторские метки для это шаблона, что бы он
    подкдючался в файл index

    Потом создал контроллер для этих изображений с помощью композера,
    сделал его ресурсным, что бы автоматически прописались названия методов,
    первый метод называется index, в нём я использовал построитель запросов,
    что бы вывести весь список из базы и создал роут для этого метода

    Потом создал метод для открытия страницы созданя изображения и указал его в роуте

    Потом заполнял метод store для создания изображения
    и сделал шаблон формы для этого метода, во внутрь формы обязательно надо было
    записать токен {{csrf_field()}} а то работать не будет

    Потом после отпраки, все данные попадают в объект Request
    и из него я вытащил изображене и сразу сохранил в нужную папку, которую указал в конфиге
    после сохранеия изображения, в переменную возвращается его название и уже его сохранил в базу
    и сделал перенапрввление на главную страницу

    Потом сделал редактирование
    Сначала шаблон для открытия формы
    когда загружается форма редактирования, отрабатывется метод edit, в него
    попадает аргумент кликнутого id

    Надо сделать запрос в базу по этому id, что бы подставить изображение для
    отображения и id для формы

    Потом в роуте прописал /update и в фигурных скобках id, для того, что бы в метод
    update, автоматически попадал этот id в этом методе опять ищу в базе все данные
    об этом изображении по idчто бы узнать название изображения, что бы его удалить

    Когда оно удалиться, то загружаю новое $fileName = $image->store('upload');
    и в эту переменную возвращается сгенерированное имя, его и записываю в базу
    потом когда всё сделал, льшь бы работало, создал класс для изображения,
    что бы убрать весь лишний код из контроллера, для того, что бы он проще
    читался, ведь в дальнейшим, у него будет ещё и валидация и тогда кода,
    в одном месте будет очень многои это неприятно читать

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

    ///////////////////////////////////////////

    Рефакторинг

    https://github.com/Div-Man/laravel-image-eloquent

    1) Начал изменять вывод всех статей, метод index. Заменил Query Builder на Eloquent.
    Что бы выводить все статьи, с помощью Eloquent, унаследовал класс Image от Model.
    Теперь можно выводить все статьи, $this->imageClass::paginate(2).
    Метод paginate, автоматически захватит имя используемого класса, сделает из него множественное число,
    и из получившегося названия, сделает запрос, на поиск такой таблицы (класс Image, будет искать таблицу images)
    и выберет все записи из этой таблицы, и разделит на части, по аргументу. Метод all() просто выведет все записи,
    без деления.

    2) Теперь начал создавать категории, для этого создал миграцию 2018_08_15_143441_create_categories_table, добавил в неё
    $table->string('name'); и запустил, в базу добавилась таблица categories. Добавил вручную категории в phpmyadmin.
    В контроллере, в методе index, добавил запрос на вывод всех категорий и добавил в массив, для вывода вида,
    в виде сдела цикл, что бы открывать каждую категорию, для этого указал адресс /category/ и id из цикла.

    3) Переделал просмотр изображения show($id). Раньше искал нужную запись в базе, с помощью
    созданного метода one, но с использованием eloquent эта функция больше ненужна и я её удалил.
    За место неё, теперь будет использоваться готовый метод find из коробки eloquent, который
    будет искать так же запись по id. Больше ничего менять не пришлось.

    4) Пришло время переделывать создание записи, но так как я хотел, что бы
    изображения можно было помещать в разные категории, для начала создал промежуточную таблицу
    category_image, через миграцию и добавил поля $table->integer('image_id'); $table->integer('category_id');,
    модель для этого создавать не надо.

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

    Для этого создал модель Category, которая наследуется от класса Model.
    И вней метод article, который будет искать, к какой категории относится статья.

    Этот метод article() можно вызывть, как метод, так и как свойство.

    Если указать нужную категорию и article, как свойство, то выведет коллекцию всех записей.

    Но этот способ мне не подходит, потому что надо ещё сделать пагинацию.
    Для этого надо article указывать не как свойсто, а как метод, и выведет класс BelongsToMany
    и после этого надо указать ещё пагинацю Category::find($id)->article()->paginate(2);
    тогда получится класс LengthAwarePaginator, в котором будут разделены запросы.

    5) Теперь когда всё работает, можно делать добавление в базу.

    Что бы можно было выбрать категории для добавления, в методе create сделал запрос на вывод всех категорий
    и вывел их мультиселекте.

    После отправки формы, идёт валидация, которая проверяет все поля.

    Описание, должно быть обязательно и его длина минимум 4 символа.
    Изображение должно быть обязательно и оно должно быть имено изображением и в допустимых форматах.

    Присланные категории решил сделать массивом, что бы проще это обработать, будет проверка
    на массив.

    Сделал описание сообщений ошибок. Указывал через точку, что бы не перезаписать
    дефолтные сообщения, что бы они относились именно к моим проверкам.

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

    После того, как это сохранилось, дальше обрабатываю присланные категории.

    Решил из массива категорий сделать коллекцию и перебрать каждый элемент коллекции, с помощью метода
    each, можно перебрать так же методом map, но разницу пока не понял.

    При каждом цикле, будет идти вставка в базу, это я решил сделать построителем.

    В image_id $id будет браться из только что новой вставленной записи в images,
    после отработки функции save(), а category_id, то что указал пользователь.

    6) У функции редактирования, изменил метод one, на коробочный find;

    7) Осталось изменить удаление.

    Так как теперь данные записи появляются в дополнительной таблице,
    нужно получить все данные у этой удаляемой записи и потом удалить изображение
    и эту запись.
    И удалить следы этой записи в пивотной таблице (deleteImage)
     
  2. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.854
    Симпатии:
    748
    Адрес:
    Татарстан
    Не лень было столько писать?
    --- Добавлено ---
    не очень понятно , запросы в цикле? Это зло.... Переделай на вменямое
     
  3. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @ADSoft так я лучше начинаю понимать, очень часто из-за этого узнаю про подводные камни.
     
  4. nospiou

    nospiou Старожил

    С нами с:
    4 фев 2018
    Сообщения:
    3.400
    Симпатии:
    510
    Ну не всем же быть мкрамерами. Нам простым смертным приходится страдать. Я он и текст до конца не осилил:(
     
    Taktreba нравится это.
  5. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    PHP:
    1. $this->imageClass::aginate(2)
    Где ты такие вызовы откопал? С учётом того, что $this->imageClass у тебя не строка, а объект класса. Я бы не додумался. Это какая-то недокументированная возможность php, а скорее баг, так что пиши лучше нормально статические вызовы. Но да, на данный момент вот этот бред срабатывает:
    PHP:
    1. <?php
    2. class A { static public function b() {echo "D"; }}
    3. function f() { return new A;}
    4. $a = new A;
    5. $a::b();
    6. f()::b();
    7. ?>
    Хотя выглядит чрезвычайно странно.
     
  6. nospiou

    nospiou Старожил

    С нами с:
    4 фев 2018
    Сообщения:
    3.400
    Симпатии:
    510
    @mkramer А как в ларке хелперы сделаны?:)
     
  7. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @mkramer нашёл в доке

    PHP:
    1.  $users = App\User::paginate(15);
    Подставил свой класс, всё просто.
    --- Добавлено ---
    @nospiou пока глубокго это не изучал.
    --- Добавлено ---
    @mkramer у меня же при создание класса, сначала вызывается конструктор, в котором создаётся этот класс, и записывается в свойство, вот и обратился к пагинации, то же самое, что и как в доке.
     
  8. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    @Dimon2x, ну так сравни, что у тебя слева от ::, и что в доке.

    @nospiou, ну там же не вызывают статическую функцию по экземпляру класса? Вот основные хелперы:
    https://github.com/laravel/framework/blob/5.6/src/Illuminate/Foundation/helpers.php

    Что-то я там такого бреда не наблюдаю. Как и здесь: https://php.ru/manual/language.oop5.paamayim-nekudotayim.html. Написано, что слева может быть переменная, если в ней строка.

    paginate() ты вызываешь как статический метод, т.е. ему не нужен экземпляр класса.
    --- Добавлено ---
    Поигрался со своим бредовым кодом, если слева экземпляр класса, то работает как строка с именем класса. Может и можно где-то применить, но слишком уж странно выглядит
    --- Добавлено ---
    Нашёл в доке использование экземпляров класса для статических вызовов. Ну ОК, "Только знаю одно: ничего я не знаю! —Вот моих размышлений последний итог." сказал великий поэт. Для меня выглядит очень странно использование экземпляра для статического вызова.
     
  9. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @mkramer если не экземпляр то что?
     
  10. ADSoft

    ADSoft Старожил

    С нами с:
    12 мар 2007
    Сообщения:
    3.854
    Симпатии:
    748
    Адрес:
    Татарстан
    Ну вроде бы обычно ->paginate(15)
     
  11. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @ADSoft в доке, через точки
     
  12. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    @Dimon2x, статические методы вызываются через имя класса, самый нормальный вызов. Имя класса можно также записать в строковую переменную. Также, как я вчера выяснил, в переменной может содержаться экземпляр класса, тогда php берёт просто имя класса из экземпляра (только имя класса, данные экземпляра в статический метод автоматически не передаются, на то он и статический. Видимо ввели для статического полиморфизма PHP, это его личная фишка. Но я у тебя впервые встретил это, даже в исходниках не встречал).
    Ты хоть разобраться пытался, что они в PHP означают, эти два двоеточия?

    Это магия Laravel, можно и так и так вызывать:
    PHP:
    1. $users = User::paginate(15);
    2. $users = User::query()->paginate(15);
    3. // И если нужно добавить условие
    4. $users = User::where("active", 1)->paginate(15);
    Ещё не разбирался, как это устроено
     
  13. Dimon2x

    Dimon2x Старожил

    С нами с:
    26 фев 2012
    Сообщения:
    2.210
    Симпатии:
    185
    @mkramer так я же и вызвал, через имя класса, у меня же это имя сохраняется в свойство класса и потом его вызываю, через this. А этот объект создаётся при вызове конструктора.
     
  14. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Нет. Фасад в Laravel это не более, чем обертка для удобного обращения. Фасад получает объект из контейнера и переадресует static на него, превращая в нормальный вызов метода. Собственно такое можно провернуть с чем угодно, если по аналогии, положить это в контейнер и добавить свой фасад.

    PHP:
    1.  
    2. // Illuminate\Support\Facades\Facade
    3.    /**
    4.      * Handle dynamic, static calls to the object.
    5.      *
    6.      * @param  string  $method
    7.      * @param  array   $args
    8.      * @return mixed
    9.      *
    10.      * @throws \RuntimeException
    11.      */
    12.     public static function __callStatic($method, $args)
    13.     {
    14.         $instance = static::getFacadeRoot();
    15.  
    16.         if (! $instance) {
    17.             throw new RuntimeException('A facade root has not been set.');
    18.         }
    19.  
    20.         return $instance->$method(...$args);
    21.     }
     
  15. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.108
    Симпатии:
    1.243
    Адрес:
    там-сям
    написал много букв, потом подумал добавил ещё букв чтобы Дима понял.
    потом ещё добавил. а потом удалил. ибо у него дислексия и большие тексты он не воспринимает. эх!
    --- Добавлено ---
    @romach до сих пор в этой теме не упоминались фасады.

    фасад это очень особый случай. фасад сука неявно "на лету" добывает экземпляр класса. А то что творит димон это не фасад, а карточный домик из ложных предположений.
     
  16. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    А причём тут фасад, если мы говорим о моделях Eloquent? Если я пишу
    Код (Text):
    1. MyEloquentModel::paginate(15)
    - это не фасад, хотя там тоже через __callStatic, я подозреваю, делается. Через . Но это же не отменяет тот факт, что вызывается как статический метод.
    Но @Dimon2x умудряется сначала создать экземпляр класса, потом через экземпляр дёргать статический метод через двойное двоеточие. Я, честно говоря, даже не знал, что так можно, но выглядит очень странно.
     
  17. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Принцип ровно тот же. Создается объект и дергается его метод. И нет, paginate не вызывается как статический метод, потому что его там вообще нет )

    Схематично, процесс выглядит так:

    PHP:
    1. class Baz
    2. {
    3.     public function bar($string)
    4.     {
    5.         echo $string;
    6.     }
    7. }
    8.  
    9. class Foo
    10. {
    11.     public function __call($method, $args)
    12.     {
    13.         return (new Baz)->$method(...$args);
    14.     }
    15.    
    16.     public static function __callStatic($method, $args)
    17.     {
    18.         return (new static)->$method(...$args);
    19.     }
    20.    
    21. }
    22.  
    23. Foo::bar('paraparapam');
    Где Foo - это модель, а Baz - Builder
     
  18. keren

    keren Новичок

    С нами с:
    15 ноя 2017
    Сообщения:
    513
    Симпатии:
    42
    new static - это объект?
     
    #18 keren, 20 авг 2018
    Последнее редактирование: 20 авг 2018
  19. nospiou

    nospiou Старожил

    С нами с:
    4 фев 2018
    Сообщения:
    3.400
    Симпатии:
    510
    Я уже объяснял. Создания экземпляра класса это более трудоемкий процесс чем просто обращение к статическому методу
    Статический метод на то и статический что может работать без данных которые добавляются в класс при его создании ($this self)
    Такая вот простая логика. Если б это был синглтон который у тебя в любом случае создается тогда ладно. Плюс к статику после создания ты можешь обратится и через :: и через ->. Вообщем создавать экземпляр ради статика это трата ресурсов.
     
  20. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    что смущает?
     
  21. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    @romach, ну вызов псевдостатического метода через магию PHP - всё равно статический. Нет? Т.е. если я хочу дёрнуть MyModel::findOrFail(12) (хотя findOrFail вообще даже близко нету в этом классе, но я и Builder не создаю), то я могу не создавать сначала MyModel, а то что он на самом деле создаётся внутри где-то - это моего кода не сильно касается. Короче, @Dimon2x и так не сильно понимает, о чём я говорю :) Так что не будем путать ещё больше.

    Всё равно, код от ТС выглядит достаточно странно. Ты же с этим спорить не будешь?
     
  22. keren

    keren Новичок

    С нами с:
    15 ноя 2017
    Сообщения:
    513
    Симпатии:
    42
    У тебя в примере создаются два разных объекта (по вардампам), два обращения к классу перегрузки Foo, тк new static это тоже самое что new Foo, и аргументом передается лишь строка с названием метода, те это не дерганье статически не статического метода.
     
  23. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.583
    Симпатии:
    1.761
    @keren, @romach такой пример сделал, потому что псевдометод Model::рaginate() на самом деле создаёт Builder и вызывает его метод paginate(). Мы же в контенте Eloquent говорили
     
  24. artoodetoo

    artoodetoo Суперстар
    Команда форума Модератор

    С нами с:
    11 июн 2010
    Сообщения:
    11.108
    Симпатии:
    1.243
    Адрес:
    там-сям
    Колдунство eloquent ещё более дремучее, чем у фасадов.