Двач.hk не отвечает.
Вы видите копию треда, сохраненную 28 июня 2016 года.

Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
33 Кб, 500x500
132 Кб, 1024x683
26 Кб, 650x384
3449 Кб, 1920x1080
Клуб изучающих PHP 77 #753595 В конец треда | Веб
Добро пожаловать в наш уютный тред. Тут мы изучаем язык PHP (а также JS/CSS/HTML/SQL), решаем задачки и даже делаем простые сайты! Зачем? Кто-то хочет научиться программировать, кто-то - делать сайты, кто-то - просто размять мозги и заняться чем-то полезным.

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

Это тред для начинающих. Не написал за свою жизнь ни одной программы? Ты наш человек.

Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Netbeans PHP или PhpStorm (с ним будет удобнее).

Предыдущий тред был тут: >>729430 (OP)

Что самое главное для программиста? Умение аккуратно оформлять код (читай второй пост прежде чем писать код).

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

Правила: ведем себя воспитанно, помогаем новичкам, постим ссылки на решения задачек, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.

У нас есть уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то надо начать с него. Он простой и понятный (по крайней мере в начале). Там есть задачи, их надо решать обязательно (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению.

Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.

Ты прошел весь учебник? Молодец, но это были лишь основы языка PHP, этого недостаточно. Вот что в идеале надо изучить еще: ООП, как работает веб-сервер, HTML/CSS, SQL, PDO, работа с таблицами в БД, работа с формами, MVC, git, composer, JS, фреймворки, автоматизированное тестирование.

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

- для начала прочти урок https://github.com/codedokode/pasta/blob/master/soft/web-server.md
- установи Апач + PHP (советы выше и ниже) и читай туториал http://php.net/manual/ru/tutorial.php
- Учи HTML/CSS и SQL, PDO, хотя бы основы
- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Yii2: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование
- Если ты все решил, переходи к Symfony 2/Doctrine 2
- Почитать про паттерны http://designpatternsphp.readthedocs.org/ru/latest/README.html (если ты не изучил ни одного фреймворка, то это будет рановато), тут с примерами кода http://designpatternsphp.readthedocs.org/ru/latest/README.html . Имей в виду что без примеров использования их учить бесполезно - не поймешь, хочешь увидеть примеры использования паттернов - ковыряй исходники Симфони, например Symfony Forms. Не заучивай паттерны - смотри код и думай, зачем тут они использованы.

Чтобы делать эти задания, тебе надо установить Апач + PHP (можно заодно сразу и MySQL) на компьютер. Вот полезные инструкции:

https://github.com/codedokode/pasta/blob/master/soft/php-install.md
https://github.com/codedokode/pasta/blob/master/soft/apache-install.md

Может тебе понадобится пользоваться командной строкой, вот гайд https://github.com/codedokode/pasta/blob/master/soft/cli.md

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

Также, у нас есть задачи которые позволят тебе изучить или подтянуть до нормального уровня знания JS/HTML/CSS/SQL. Решай их параллельно с задачами выше.

- HTML/CSS: https://github.com/codedokode/pasta/blob/master/html/html.md
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- SPA (сложно): https://github.com/codedokode/pasta/blob/master/js/spa.md
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://gist.github.com/codedokode/10539213

Что почитать

- Мануал по PHP — http://www.php.net/manual/ru/langref.php
- Сайт phptherightway (перевод на русский: http://getjump.me/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git: https://git-scm.com/book/ru/v1

Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
ОП, сделай за меня мою работу или домашнее задание? — Это конечно, хорошая идея, но нет.
Подскажи сайты для поиска работы, я не умею гуглить? — hh.ru, geekjob.ru, moikrug.ru (склеен с brainstorage.me), fl.ru, upwork.com (бывший одеск). Имей в виду, что кроме фриланса есть еще постоянная удаленная работа (remote job) когда тебе не надо тратить время на поиск заказов и переговоры с неадекватными заказчиками.
56 Кб, 500x644
70 Кб, 1022x575
87 Кб, 561x800
Важно! #2 #753597
Код нужно писать не как попало, а аккуратно и по правилам. Почему? Потому, что на неакуратно написанный код не хочется даже смотреть.

Если тебе лень выравнивать код руками, закачай его на http://beta.phpformatter.com/ и нажми «format». Робот исправит выравнивание и отступы в мгновение ока (да, прогресс не стоит на месте). Если ты используешь мощную IDE вроде PhpStorm, там тоже есть функция форматирования кода.

Горячие клавиши для форматирования кода в разных IDE: https://gist.github.com/codedokode/8759492

Вообще, в PHP долгое время не было единого стандарта оформления кода, все писали как попало и было много бардака, но сейчас дело лучше — есть стандарты PSR-1 и 2. Вот как надо оформлять код:

- переменные и функции пишутся с маленькой буквы, подчеркивание не используется, используется camelCase, пример: $x, $numberOfPeople, printResults()
- Название функции начинается с глагола, в стиле «сделайЧтоТо»
- не знаешь английский? Не беда, в 21 веке есть решение этой проблемы. Не пиши транслитом, открой лучше Гугл Транслейт или slovari.yandex.ru и найди название для переменной там
- в именах классов используется CamelCase, первая буква большая, «_» может использоваться
- мы предпочитаем подстановку переменных вместо конкатенации строк: "I am $age years old" — хорошо, 'I am ' . $age . ' years old' — плохо из-за обилия точек и кавычек
- мы используем для отступов 4 пробела (можно настроить редактор, чтобы при нажатии Tab он вставлял 4 пробела)

Вот ссылка на стандарты, где все это описано подробнее и даны примеры оформления:

PSR-1: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md

------------------

Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.

Давай удочку, а не рыбу

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

Будь доброжелателен

Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»

Не придирайся к знанию английского языка.

Объясняй

Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»

Не проповедуй

Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.

Не придирайся к знанию английского языка, анон пишет как умеет.

Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
56 Кб, 500x644
70 Кб, 1022x575
87 Кб, 561x800
Важно! #2 #753597
Код нужно писать не как попало, а аккуратно и по правилам. Почему? Потому, что на неакуратно написанный код не хочется даже смотреть.

Если тебе лень выравнивать код руками, закачай его на http://beta.phpformatter.com/ и нажми «format». Робот исправит выравнивание и отступы в мгновение ока (да, прогресс не стоит на месте). Если ты используешь мощную IDE вроде PhpStorm, там тоже есть функция форматирования кода.

Горячие клавиши для форматирования кода в разных IDE: https://gist.github.com/codedokode/8759492

Вообще, в PHP долгое время не было единого стандарта оформления кода, все писали как попало и было много бардака, но сейчас дело лучше — есть стандарты PSR-1 и 2. Вот как надо оформлять код:

- переменные и функции пишутся с маленькой буквы, подчеркивание не используется, используется camelCase, пример: $x, $numberOfPeople, printResults()
- Название функции начинается с глагола, в стиле «сделайЧтоТо»
- не знаешь английский? Не беда, в 21 веке есть решение этой проблемы. Не пиши транслитом, открой лучше Гугл Транслейт или slovari.yandex.ru и найди название для переменной там
- в именах классов используется CamelCase, первая буква большая, «_» может использоваться
- мы предпочитаем подстановку переменных вместо конкатенации строк: "I am $age years old" — хорошо, 'I am ' . $age . ' years old' — плохо из-за обилия точек и кавычек
- мы используем для отступов 4 пробела (можно настроить редактор, чтобы при нажатии Tab он вставлял 4 пробела)

Вот ссылка на стандарты, где все это описано подробнее и даны примеры оформления:

PSR-1: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/php-fig/fig-standards/blob/master/accepted/ru/PSR-2-coding-style-guide.md

------------------

Итак, ты зашел в тред и решил помочь какому-то анону, дав ему совет или подсказку. Спасибо! Но прочти сначала эти напоминания, чтобы твоя помощь действительно была полезной.

Давай удочку, а не рыбу

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

Будь доброжелателен

Не годится: «Ты мануал хоть раз в жизни открывал, обезьяна?»
Не годится: «В гугле забанили?»
Не годится: «Твой код плохой»
Хорошо: «Вот, как можно улучшить этот код: ...»
Хорошо: «Ты неправильно используешь функцию abc(). Вот ее описание: ссылка, и как видишь ей надо передать строку, а не массив»

Не придирайся к знанию английского языка.

Объясняй

Не очень хорошо: «сделай как в этом коде»
Хорошо: «если ты вставляешь текст от пользователя в SQL запрос, то получается SQl-инъекция, которая позволяет взломать твой сервер (ссылки). Чтобы этого избежать, надо вставлять данные с помощью плейсхолдеров (ссылки)»
Хорошо: «Помни, что код пишется для людей. Если писать такие большие функции, то в них становится трудно разобраться...»

Не проповедуй

Мы учим использованию самых распространненных подходов, стандартов, библиотеки фреймворков. Если ты не любишь ООП, пробелы в коде, jQuery, сам PHP, то рассказать об этом стоит в каком-нибудь другом треде.

Не придирайся к знанию английского языка, анон пишет как умеет.

Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
#3 #753602
Задача: regexr[точка]com/3dg71

Нужно распарсить строку с ETag по RFC. Правильные ответы: "s"d, fsdf" "sdf, sd"f2" "dsf"sdf, sdf345".
И они правильно матчатся, но первая подмаска хранит только последнее значение. Как сохранить все значения?
>>753635
#4 #753629
Здраститя я из соседнего треда, 3 месяца учил питон, сегодня читал доки джанги и охуел от сложноты, может еще не поздно и мне стоит перекатится? пхп и майскюл проще в обучении или тоже не сахар?
>>768314
#5 #753630
Перекат легитимный?
33 Кб, 747x650
#6 #753632
Сап, народ. Такое дело: будучи студентом, далек от программирования. Но возникла адская необходимость работы с BigData. Нашел подходящую БД, но по ссылкам скачивается SQL скрипт (пикрил). Собственно, вопрос: как мне из него получить нормальные данные?
>>768314
#7 #753635
>>753602
В общем, решил это так: http://ideone.com/cGoKyc
658 Кб, 510x2000
119 Кб, 1685x959
160 Кб, 1762x279
#8 #753660
Аноны, а особенно ОП и гуру верстки. Зацените мою новейшую ломовейшую работу. На этот раз я не поленился и сделал все настолько круто что мне самому почти все нравится.
http://w99953g4.bget.ru/evently/
Код: https://github.com/huyakhuyakivprodakshen/evently
Джипег макета в шакальем качестве: пик1. В нормальном: http://radikal.ru/lfp/s017.radikal.ru/i413/1605/9f/21d3cd8f22dd.jpg/htm . Исходных картинок в .psd не было.
+Верстка фулл респонсиве, от айфонных 320рх до фулл шд, при любом зуме, все тянется и перестраивается, ничего ниоткуда не торчит, по крайней мере у меня не получилось что-то сломать. В паре узких мест на границах брейкопинтов случается что-то впритык, это легко решается добавлением большего числа брейкпоинтов, скучно этим заниматься.
+Моднейшие свг-иконки и логосы, при любом зуме никакого мыла. Всем рекомендую, иконочные шрифты, base64 и png полное днище по сравнению С.
+На ретине картинки подменяются с двойной плотностью, в инспекторе все работает(пик 3), как на практике не знаю.
+Все модульно, реиспользуемо, любую менюшку, кнопку, инпут можно повторно вставить в любое место и они не сломаются.
+Как обычно повторяющиеся элементы - вопросы в фак, дни в расписание, посты в блог, чудаки в спикеры и пр. - добавляются изящно, например:
question('To be or not to be?','Answer'), post('subject','author','date','Lorem ipsum') вместо копипасты кусков html. Пример на пике 2 как выглядит исходник и скомпилированный результат.
+Все ссылки, кнопки нажимаются, листалки листаются, формы отправляются аяксом и даже валидируются, но правда очень примитивно, упор пока делаю на верстку. Но можно попробовать отправить пустую форму или инвалидное мыло или больше 3 сообщений подряд. Once again, пхп-скрипты там уровня hello world - лишь бы что-то отвечали.
+Все полностью самописное кроме плагинов для подмены стандартных скролбаров и детекта попадания элемента во вьюпорт.
+Черт, я даже нашел сервис с раскрашиванием стандартной гугл карты в цветовой гамме очень похожей на макет.
+Чтобы вам не было скучно я добавил в галерею ФОТО ОБНАЖЕННЫХ ДЕВИЦ И КОТИКОВ.
-В исходниках медиа запросы свалены в отдельные файлы. Сперва мне это показалось хорошей идеей и только когда закончил узнал что SASS умеет собирать несколько одинаковых запросов в один, а gulp их сортировать и добавлять в конец файла. Таким образом медиа-запросы можно инкапсулировать внутри компонентов что полностью соответствует идеологии бэм и вообще здорово. В следующей работе так и сделаю, тут уже лень переписывать.
-Кое-где кнопки плохо видны на фоне картинок - дизайн не мой, я просто разместил объяву. Также кнопка скролл даун тут явно ни к чему, но пусть уже.
-Кроссбраузерностью по-прежнему не занимаюсь. В последнем хроме, фф, эдже, опере у меня все ок. В старых ослах даже не хочу открывать и вообще не знаю как с этой темой совладать. Как можно запомнить какие из сотен разных правил/значений как себя ведут в десятках проблемных версий разных браузеров? Ладно еще прогнать автопрефиксером и то, на сколько последних версий ставить настройку? В общем пока с этим пробел.
-Скрипты слайдеров не модульные, не универсальные, привязаны к конкретной верстке и попросту нубские. Пока насилую верстку, когда возьмусь за фронтенд напишу пару каких-нибудь универсальных крутых плагинов для jquery. Для текущей цели считаю это оверкилом.
658 Кб, 510x2000
119 Кб, 1685x959
160 Кб, 1762x279
#8 #753660
Аноны, а особенно ОП и гуру верстки. Зацените мою новейшую ломовейшую работу. На этот раз я не поленился и сделал все настолько круто что мне самому почти все нравится.
http://w99953g4.bget.ru/evently/
Код: https://github.com/huyakhuyakivprodakshen/evently
Джипег макета в шакальем качестве: пик1. В нормальном: http://radikal.ru/lfp/s017.radikal.ru/i413/1605/9f/21d3cd8f22dd.jpg/htm . Исходных картинок в .psd не было.
+Верстка фулл респонсиве, от айфонных 320рх до фулл шд, при любом зуме, все тянется и перестраивается, ничего ниоткуда не торчит, по крайней мере у меня не получилось что-то сломать. В паре узких мест на границах брейкопинтов случается что-то впритык, это легко решается добавлением большего числа брейкпоинтов, скучно этим заниматься.
+Моднейшие свг-иконки и логосы, при любом зуме никакого мыла. Всем рекомендую, иконочные шрифты, base64 и png полное днище по сравнению С.
+На ретине картинки подменяются с двойной плотностью, в инспекторе все работает(пик 3), как на практике не знаю.
+Все модульно, реиспользуемо, любую менюшку, кнопку, инпут можно повторно вставить в любое место и они не сломаются.
+Как обычно повторяющиеся элементы - вопросы в фак, дни в расписание, посты в блог, чудаки в спикеры и пр. - добавляются изящно, например:
question('To be or not to be?','Answer'), post('subject','author','date','Lorem ipsum') вместо копипасты кусков html. Пример на пике 2 как выглядит исходник и скомпилированный результат.
+Все ссылки, кнопки нажимаются, листалки листаются, формы отправляются аяксом и даже валидируются, но правда очень примитивно, упор пока делаю на верстку. Но можно попробовать отправить пустую форму или инвалидное мыло или больше 3 сообщений подряд. Once again, пхп-скрипты там уровня hello world - лишь бы что-то отвечали.
+Все полностью самописное кроме плагинов для подмены стандартных скролбаров и детекта попадания элемента во вьюпорт.
+Черт, я даже нашел сервис с раскрашиванием стандартной гугл карты в цветовой гамме очень похожей на макет.
+Чтобы вам не было скучно я добавил в галерею ФОТО ОБНАЖЕННЫХ ДЕВИЦ И КОТИКОВ.
-В исходниках медиа запросы свалены в отдельные файлы. Сперва мне это показалось хорошей идеей и только когда закончил узнал что SASS умеет собирать несколько одинаковых запросов в один, а gulp их сортировать и добавлять в конец файла. Таким образом медиа-запросы можно инкапсулировать внутри компонентов что полностью соответствует идеологии бэм и вообще здорово. В следующей работе так и сделаю, тут уже лень переписывать.
-Кое-где кнопки плохо видны на фоне картинок - дизайн не мой, я просто разместил объяву. Также кнопка скролл даун тут явно ни к чему, но пусть уже.
-Кроссбраузерностью по-прежнему не занимаюсь. В последнем хроме, фф, эдже, опере у меня все ок. В старых ослах даже не хочу открывать и вообще не знаю как с этой темой совладать. Как можно запомнить какие из сотен разных правил/значений как себя ведут в десятках проблемных версий разных браузеров? Ладно еще прогнать автопрефиксером и то, на сколько последних версий ставить настройку? В общем пока с этим пробел.
-Скрипты слайдеров не модульные, не универсальные, привязаны к конкретной верстке и попросту нубские. Пока насилую верстку, когда возьмусь за фронтенд напишу пару каких-нибудь универсальных крутых плагинов для jquery. Для текущей цели считаю это оверкилом.
Анон #9 #753682
подписался
8 Кб, 991x210
32 Кб, 229x131
1431 Кб, 1881x794
#10 #753688
>>753660
Чего дропдаун не сверстал?

>В старых ослах даже не хочу открывать


Let me do this for you
IE 10, 11 нет иконок (теперь ты понимаешь, чому svg пока не в почете?)
С ИЕ9- сайт неюзабелен.

Третий пик - ИЕ 5.5 :3
>>753779
#11 #753774
>>753748

>Если у тебя задача матчить списки вида a, b, c то одним применением регулярки сделать это не получится.


Спасибо, сейчас пришел к такому решению - http://ideone.com/RGFQmU
Сначала тестирую строку на валидность, и только потом паршу.
>>773828
#12 #753779
>>753688

>Чего дропдаун не сверстал?


А че с ним не так? Вроде пашет. Или ты про то что опшены длиннее селекта? Ну да, там микрокостыль присутствует.

>IE 10, 11 нет иконок (теперь ты понимаешь, чому svg пока не в почете?)


Не понимаю. Старые ослы либо обучаются js-либой либо получают png через фолбек, это относительно несложно, но реально жаль времени, лучше освою побольше современных крутых штук :3
100 Кб, 612x612
#13 #753870
Кто нибудь общался с API gelbooru?
Хочу сделать костыль, который будет парсить теги к картинке и забивать их в базу (что-то на подобии http://gelbooru.iqdb.org/ ) Вот только как сделать запрос с поиском конкретной картинки я не знаю. Подскажете?
>>773828
55 Кб, 810x528
Игра #14 #753892
Найдите кнопку отказа от установки виндоуз 10
>>753895>>753907
63 Кб, 810x528
#15 #753895
>>753892
Где я могу забрать приз?
>>753902
#16 #753902
>>753895

Приза нет, но есть windows 10, не нужна? https://geektimes.ru/post/276318/ тут пишут что крестик теперь значит "да".
>>753907
#17 #753907
>>753902
>>753892
Охуенно, даунов наконец-то заставили обновиться.
Тем кто пользуется XP и старыми IE-офисами я бы вообще форматировал все жёсткие диски, пока они не догадаются обновиться.
>>753911
#18 #753911
>>753907

Ты можешь начать с форматирования своего диска. Я вижу, у тебя много свободного времени.
>>753916
#19 #753916
>>753911
Лучше поссу ещё разок тебе в ротеш :3
Как же майкрософт филигранно показал тебе твоё место у параши.
#20 #753925
Главная причина конечно не забота о пользователях, а забота о прибыли:

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

Отдельно хочу сказать про интеграцию с фейсбуком. В один прекрасный день скайп зачем-то встроил в свою главную страницу фейсбук, причем отображался он как я понимаю через виджет от ИЕ. Зачем делать копию браузера в скайпе я плохо понимаю, но на всякий случай продолжил сидеть на старой версии скайпа, пока они не поменяли протокол. После обновления я все же как-то от фейсбука избавился, не помню уже как, по моему просто включил многооконный режим.

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

Фейсбук тоже хорош, при регистрации требует пароль от почты и прячет ссылку для пропуска этого шага. А после того как ты зарегистрируешься, он начинает присылать каждый 2 дня спам вроде "вы наверно знаете этого негра из Зимбабве".

С другой стороны, аноны, делайте выводы. Если вы собираетесь выпускать какой-то свой продукт, возможно что без такой вот навязчивой дистрибуции никто ваш продукт и не купит. Вот, яндекс тоже свои программы хочет в телефоны предустанавливать, потому что так их никто не скачивает.
>>753987
#21 #753987
>>753925

>передает все данные в ЦРУ?


Я бы еще мог понять эту претензию от гражданина США, но кому ты нахуй нужен?
>>753992
#22 #753992
>>753987

Где гарантия что я через 10 лет нужен не стану? А тут уже досье накоплено. Чем меньше информации утекает тем лучше. Плюс, меня не устраивает, что информация со всего мира должна уходить в Вашингтон, а не в Москву или Пекин например. Или оставаться у владельца. Это несправедливо.
>>753995
#23 #753995
>>753992
то есть тебя устроила бы слежка от ФСБ, но не ЦРУ? Какая извращенная форма патриотизма
#24 #754335
>>753595 (OP)
Подскажите хорошуюпо PHP конечно же книгу на русском, после прочтения которой можно легко разобраться с версткой тем для WordPress.
>>754342
#25 #754342
>>754335
Библия, после нее очень легко со всем разбираться.
>>754344>>755839
#26 #754344
>>754342
Смешно, но я ведь серьёзно, знания HTML/CSS есть, изучаю JS, но сейчас есть в моём городе неплохая вакансия WordPress Developer и хотелось бы туда устроиться. Мне бы что-то такое, после прочтения чего я бы уловил суть что и как в WordPress, ведь там явно не весь PHP задействован, а дальше я сам справлюсь.
>>754568>>754606
#27 #754568
>>754344
http://scanlibs.com/cms/ - вот тут многое может пригодиться, если инглиш знаешь.
Ну или нагугли переводы, должны быть.
#28 #754606
>>754344

>WordPress Developer


Ты будешь пилить движок вместе с создателями цмс или клепать бложики для убогих?
>>754609
#29 #754609
>>754606
Обычно Wordpress Developer это макака, задача которой натягивание шаблона на цмс.
358 Кб, 406x587
#30 #754984
Как вам пикрелейтед?
Написав примитивную guestbook и испугавшись выкладывать её на Гитхаб, хочу приступить к изучению этого фреймворка.
Студенты и файлообменник отнимут слишком много времени, мне нужно до конца мая разобраться хотя бы в основах Yii2.
Может, посоветуете ещё каких-нибудь руководств или уроков?
Вот этот курс ещё хочу посмотреть: https://www.youtube.com/watch?v=R-yQux1S63w
Всё ли я правильно делаю?
>>755013>>755162
#31 #755013
>>754984

>мне нужно до конца мая разобраться


Из дому выгоняют? Жить не на что?

Если тебе интересно мнение, то вот как я вижу твой дальнейший расклад: на Yii ты научишься создавать примитивнейшие CRUD'ы, но писать что-то более сложное не сможешь ввиду недостатка знаний в области ООП. Код если и будет работать, то на уродливейших костылях. В лучшем случае ты забьёшь пока на фреймворки и начнёшь делать студентов как я, в худшем - просто забьёшь.

>Студенты и файлообменник отнимут слишком много времени


Слишком много времени они отнимут лишь у тех, у кого действительно низкий уровень знаний. А ты за фреймворки браться собрался.

И тема видеоуроков уже подымалась в предыдущем треде.
>>755025
#32 #755025
>>755013

>Из дому выгоняют? Жить не на что?


Да нет, в заднем проходе свербит собственный проект, который надо поднимать. Лето - самое время для этого, будет возможность.
Собираюсь заказывать модули необходимые у фрилансеров, самостоятельно интегрировать в систему.

>но писать что-то более сложное не сможешь ввиду недостатка знаний в области ООП


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

>Слишком много времени они отнимут лишь у тех, у кого действительно низкий уровень знаний. А ты за фреймворки браться собрался.


Знания разрознены у меня. Синтаксис хорошо разобрал и запомнил (благодаря ещё и куче просмотренных задач у братишек). Мне хочется просто понять принципы, на которых всё строится в Yii2, разобраться с разными важными штуковинами в нём, а дальше поднимать проект - хотя бы уже начать пытаться.

>И тема видеоуроков уже подымалась в предыдущем треде.


В одном из, да, я помню.
Ну а вдруг что более-менее хорошее посоветуют.
Я по книгам лучше учусь, правда, но видеокурсы помогают часто увидеть, как многое просто на самом деле.
Старый тред #33 #755118
Напомню себе позже проверить:

>>745461 https://github.com/fidnex/students/
>>746699 https://github.com/greenTea242/Student_List/compare/master@{20 day}...master
>>747172 https://github.com/nsdvw/TestHub
>>747423 https://github.com/foobar1643/filehosting
>>747986 https://github.com/applejacky/tmp
>>748292 https://github.com/TheSidSpears/Students

Всем остальным я ответил в прошлом треде, зайдите и посмотрите: >>755108

>>755108много задач с https://github.com/timrene/php-link-list
>>755109 greenTea242/StudentList
>>755110testhub
>>755113 задачи по регуляркам

Если я кого-то пропустил - напомните о себе здесь, в новом треде.
13 Кб, 480x267
#34 #755162
Позвали на собеседование пхп-разработчика. Те на yii работают, а я в жизни этого yii не видел. Слушаю сейчас курс что этот >>754984 анон принес, лол. Еще говорят код свой принести посмотреть, а мне кроме студентов и показать нечего. Вакансия по меркам моего мухосранска хорошая, волнуюсь немного.
>>755180
#35 #755180
>>755162
Ну, надеюсь, он тебе поможет, братишка.
Вроде многое понятно там для новичков - сужу по себе.
Вот еще Полное руководство по Yii 2.0: https://github.com/yiisoft/yii2/tree/master/docs/guide-ru
Или тебе по Yii1.0 надо? Там многое отличается, как я понял. Но явно всегда обновлённой версии надо отдавать предпочтение.
>>755217
#36 #755217
>>755180
Наверное все же второй. Видео да, там назначение папочек пояснили и уже как то уверенней себя чувствую, лол.
#37 #755299
А что это за хипстерня, называется composer?
Можно без него?
Пытался когда-то. Просто он мне как-то чуть не скачал 300 Мб каких-то библиотек. И испортил path. И поставил wget.
#38 #755315
>>755299

>хипстерня


Веди себя прилично.
Скорее всего ты скопипастил его с какого-то сайта. Читай лучше оф.документацию по нему https://getcomposer.org/doc/00-intro.md
#39 #755326
>>755299
Спешу тебя разочаровать: composer ставит только то, что ты ему указываешь. Он берёт на себя возню с зависимостями, облегчая программисту жизнь. И как можно жить без wget'а на линуксе?
>>755542>>756017
#40 #755332
>>755299

Его можно не устанавливать, а скачать в виде phar и положить в папку.
5786 Кб, Webm
#41 #755357
ООО ВЕКТОР
Я снова выхожу на связь . ОПушка прости меня пожалуйста, что без комментариев, я больше так не буду. поясни за клонирование объектов. Я перепробовал все комбинации из примеров, но все копии заменяют друг друга. Как делать не связанные с исходным объектом его клоны?
>>755360>>755460
#42 #755360
>>755357
забыл ссылку: http://ideone.com/oMBNen
#43 #755442
Зачем возиться с CSRF-токенами, если можно просто ставить определенный header и проверять его наличие на сервере?
>>755461
#44 #755460
>>755357

Напиши кратко код которым ты пытался клонировать и что не получилось.

> public function getCoffe()


>{


> return parent::getCoffe();


>}


В чем смысл? Методы и так наследуются сами по себе. Переопределять метод надо если ты хочешь что-то изменить в нем.

> public function getSalary()


>{


..

> $salary = $this->rate $factor $bossFactor;


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

> class Department


> public function __construct($employees, $departmentName)


Функция спроектирована плохо. Почему я должен в конструктор передавать какие-то данные в каком-то массиве в непонятном формате. У нас есть объект, представляющий работника - вот его и надо передавать.

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

То есть вместо общей, универсальной функции "добавить работника в департамент" ты сделал заточенную под конкретную задачу функцию.

> echo "Неправильно указан ранг: ";


> die($employee[1]);


В ООП используют исключения.

> if($employee->rank == 1)


> {


> $number[1]+=1;


> }


> elseif($employee->rank == 2)


> {


> $number[2]+=1;


А нельзя это как-то обобщить, а не писать по ветке на каждый ранг?

> foreach($number as $key => $value)


key и value ничего не значат. Надо выбрать более осмысленные названия.

> if($value == 0)


> {


> unset($number[$key]);


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

> public function fireEmployees($position, $boss, $quantity, $rank)


опять же, у тебя функция заточенная под одну задачу. А если завтра надо будет увольнять по другим критериям?

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

Каждый класс должен заниматься своим делом, а ты смешиваешь в одном классе несколько функций. Задача Департамента - вести учет сотрудников. А задача "уволить X% инженеров" это задача антикризисного комитета.

> return implode("", (array_merge(preg_split('//u', $q, 0, PREG_SPLIT_NO_EMPTY), array_fill(0, $w-mb_strlen($q), " "))));


Слишком длинно и слишком много скобок, это невозможно прочесть. Более того, ты тут перемудрил. Для заполнения строки пробелами есть str_repeat.

> foreach($company as $departments)


объясни как по твоему это работает
#44 #755460
>>755357

Напиши кратко код которым ты пытался клонировать и что не получилось.

> public function getCoffe()


>{


> return parent::getCoffe();


>}


В чем смысл? Методы и так наследуются сами по себе. Переопределять метод надо если ты хочешь что-то изменить в нем.

> public function getSalary()


>{


..

> $salary = $this->rate $factor $bossFactor;


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

> class Department


> public function __construct($employees, $departmentName)


Функция спроектирована плохо. Почему я должен в конструктор передавать какие-то данные в каком-то массиве в непонятном формате. У нас есть объект, представляющий работника - вот его и надо передавать.

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

То есть вместо общей, универсальной функции "добавить работника в департамент" ты сделал заточенную под конкретную задачу функцию.

> echo "Неправильно указан ранг: ";


> die($employee[1]);


В ООП используют исключения.

> if($employee->rank == 1)


> {


> $number[1]+=1;


> }


> elseif($employee->rank == 2)


> {


> $number[2]+=1;


А нельзя это как-то обобщить, а не писать по ветке на каждый ранг?

> foreach($number as $key => $value)


key и value ничего не значат. Надо выбрать более осмысленные названия.

> if($value == 0)


> {


> unset($number[$key]);


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

> public function fireEmployees($position, $boss, $quantity, $rank)


опять же, у тебя функция заточенная под одну задачу. А если завтра надо будет увольнять по другим критериям?

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

Каждый класс должен заниматься своим делом, а ты смешиваешь в одном классе несколько функций. Задача Департамента - вести учет сотрудников. А задача "уволить X% инженеров" это задача антикризисного комитета.

> return implode("", (array_merge(preg_split('//u', $q, 0, PREG_SPLIT_NO_EMPTY), array_fill(0, $w-mb_strlen($q), " "))));


Слишком длинно и слишком много скобок, это невозможно прочесть. Более того, ты тут перемудрил. Для заполнения строки пробелами есть str_repeat.

> foreach($company as $departments)


объясни как по твоему это работает
>>755539
#45 #755461
>>755442

Как ты на стороне браузера при отправке формы поставишь заголовок?
>>755473
#46 #755473
>>755499
#47 #755499
>>755473

То ради для твоего варианта надо отказаться от обычных форм и ссылок на всем сайте?

Также, что насчет кроссдоменного аякса? Отправки запросов через флеш?
#48 #755500
>>755499

>2016


>обычных форм


Совсем даун?
#49 #755504
>>755499

>кроссдоменного аякса


Same-origin policy

>Отправки запросов через флеш


Вот именно это - причина, почему нельзя так делать. Меня уже тыкнули в оригинальный вопрос на СО и слили репу.
>>755523
#50 #755508
>>755499

>Отправки запросов через флеш


Откуда флеш возьмёт куки, мань?
>>755523
#51 #755523
>>755504

Вот ты пишешь same-origin policy, а ты знаешь, что это значит? Это не запрет отправлять запросы на другие домены.

>>755508

Он же без кук хочет отправлять запросы. ну и я не разбираюсь особо в флеше, может там есть возможность отправлять запрос через браузер с добавлением кук?
>>756441>>756601
55 Кб, 604x341
#52 #755539
>>755460

>>Напиши кратко код которым ты пытался клонировать и что не получилось.


Уже разобрался, не заметил как переназначалась исходная переменная.

>>В классе Employee нет свойства rate, значит ты не можешь к нему обращаться. Класс не знает ничего о своих наследниках (так как их могут написать уже после тебя - вот например в твою программу можно дописать пару новых классов для новых профессий).


Нужно объявить поле $rate и оставить его пустым?

>>В ООП используют исключения.


Разве не нужно с исключениями использовать throw/catch?

>>объясни как по твоему это работает


Ну там компания состоит из департаментов и каждый цикл представляет каждый департамент.
>>755543
#53 #755542
>>755326
а прикинь, он в центоси новой из коробки не стоит, охуеть вообще

а в дебиане и убунте мейка нет из каробки, прихоидтся билд-эсеншиалз ставить. Я не понимаю, зачем это сделали. В серверной, блджад, версии!
#54 #755543
>>755539

> Нужно объявить поле $rate и оставить его пустым?


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

1) как человек который хочет уначледовать твой класс догадается что он обязан задать это свойство?

2) как проверить что он его не забыл задать?

Обе этих проблемы можно решить абстрактными методами.

> Разве не нужно с исключениями использовать throw/catch?


Ловить их ты не обязан. Этого разве нет в моем уроке по исключениям? Ты его читал? https://gist.github.com/codedokode/65d43ca5ac95c762bc1a

> >>объясни как по твоему это работает


> Ну там компания состоит из департаментов и каждый цикл представляет каждый департамент.


Если компания состоит из департаментов то почему у тебя 2 цикла, а не 1?

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

Попробуй сделать цикл по объекту Engineer и сдампь (var_dump) из чего он состоит.
>>755558
#55 #755546
Парни, особенно ОП.
Я, наверное, глупый вопрос задам, и срачегонный в перспекктиве.

Но может кто-то назвать, услонво, кол-во строк, после которого становится целесообразно юзать ООП?
Я не программер, но сейчас по работе много кодю, актически веду целый проеккт по продаже говна через интернет, с полноценным КРУДом-хуюдом, и ООП я юзаю только, так сказать, когда это предусмотрено разрабом модуля пеар. Или в mysqli например.

Я ей-богу не понимаю, что бы изменилось, если бы я преписал этот сервис в объектной парадигме?

Ну и что почитать по ооп в похапе.
>>755551
#56 #755547
>>753595 (OP)
ОП, ты мне нужен. Скажи, почему у PHP куча фреймворков, у JS куча фреймворков, а у питона только джанго и фласк? Объем изучения для змеебов меньше, чем для остальных? И там все интегрированнее?

>Тут мы изучаем язык PHP (а также JS/CSS/HTML/SQL)


А если я буду решать твои задачки на пистоне, ты бы смог подсказывать и давать советы какие-нибудь? Или ты в нем не шаришь? Ну хоть, может, по общим моментам каким.
>>755551
#57 #755551
>>755547

Я понимаю Питон, но возможно что твои задачки будут проверяться во вторую очередь после задачек на php.

Почему надо спросить у Питонщиков, я откуда знаю?

>>755546

А что другие люди говорят о твоем коде? Легко ли в нем разбираться и поддерживать?

Почитать - книги в ОП посте и главу по ООП из учебника.

И просто интересно, а что ты имеешь против ООП? Классы это часть языка и не использовать классы по моему это то же что принципиально не использовать цикл for или анонимные функции, записывая вместо них более сложный код. Возникает вопрос, а зачем?
#58 #755558
>>755543

>>Если компания состоит из департаментов то почему у тебя 2 цикла, а не 1?


Если ты о двойном цикле в функции вывода таблицы, то там я действительно недосмотрел и должен был использовать метод вместо второго цикла.
#59 #755561
>>755551
По-твоему ООП это использование классов?

>зачем?


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

мимопроходил
>>755564
#60 #755563
>>755551
да упаси говинда, ничего не имею, просто я ведь _ПОКА_ всё это могу процедунрно реализовать, пониаешь? И я не понимаю, какова причина использования ООП в данном контексте, то есть не ясно примерно какого масштаба должен быть проект, чтобы для того, чтобы проще его мэйнтейнить, надо было юзать ООП.
>>773828
#61 #755564
>>755561

>> чем написать стену процедурных инструкций в одном файле


узнал себя
#62 #755572
>>755551

>Почему надо спросить у Питонщиков, я откуда знаю?


Хуй знает, ты вроде во всем шаришь.

> но возможно что твои задачки будут проверяться во вторую очередь после задачек на php.


Спасибо, приду после сессии.
#63 #755591
https://github.com/someApprentice/Students/

https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php#L50
В задаче написано что множить сущности не желательно, это касается класса валидации для формы редактирования? Старый класс валидации всегда будет выдавать ошибку о том что такая почта уже занята, если её не поменять. Так же это касается паролей, даже если их заполнить теми же самыми данным, то всё равно сгенерируется новый хэш и токен, и авторизация сломается, потому что в куках находиться не актуальный токен. Как обойти обновление полей которые мы не хотим обновлять?

https://github.com/someApprentice/Students/blob/master/app/Controller/SearchAction.php#L15
Нужна ли валидация и список ошибок для формы поиска?

Как избавиться от $_GET['input'] в URL?

https://github.com/someApprentice/Students/blob/master/app/Controller/LoginAction.php#L52
Решил отказаться от залогинивания с помощью имени и фамилии. Слишком уж усложняется задача если использовать не уникальные данные. Главное что я понял что для каждого способа залогинивания должен быть свой метод.

https://github.com/codedokode/pasta/blob/master/student-list.md#Работа-с-формами

>После успешной регистрации или обновления данных об абитуриенте нам надо показать сообщение об этом. Проще всего для этого при редиректе (после успешной обработки формы мы делаем редирект, не забыл?) приписать дополнительный параметр в URL, то есть редиректить на адрес вида index.php?notify=registered, а уже в index.php проверять значение параметра notify.


А разве это не обязанность контроллера работать с $_GET данными?

https://github.com/codedokode/pasta/blob/master/student-list.md#Поиск-в-базе-данных

>Для поиска по всем колонкам можно применить оператор LIKE к соединенным через пробел значениям столбцов.


А можно простой пример такого запроса? У меня не получилось составить...

>name LIKE '%hello%'


А почему в примере без плейсхолдера написано? Это только в рамках простого примера?

https://github.com/codedokode/pasta/blob/master/student-list.md#Составление-url
Не совсем понимаю как этим пользоваться: Вот с ссылками для сортировки таблицы с результатами всё понятно, а как быть с формами? Допустим есть форма поиска с методом get и, насколько я знаю, её нельзя заставить отправлять этот запрос с помощью urlencode().
И еще не понятно какой класс должен заниматься этим. Свой собственный?

https://github.com/codedokode/pasta/blob/master/student-list.md#Постраничная-навигация

>Некоторые пытаются возложить на объект Pager лишние функции, например чтение параметров поиска из $_GET или подсчет числа записей в базе. Я не советую так делать, так как это явно должно быть в другом месте (например, работа с базой — в маппере).


Это касается всех $_GET запросов? Я бы на оборот сделал Pager контроллером который содержит метод, который на вход принимает результаты из БД, и затем из $_GET получал бы данные о номере страницы и сортировке, затем на их основе составлял таблицу с ссылками на страницы и сортировку. Он бы даже мог заниматься составлением ссылок для сортировки.
#63 #755591
https://github.com/someApprentice/Students/

https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php#L50
В задаче написано что множить сущности не желательно, это касается класса валидации для формы редактирования? Старый класс валидации всегда будет выдавать ошибку о том что такая почта уже занята, если её не поменять. Так же это касается паролей, даже если их заполнить теми же самыми данным, то всё равно сгенерируется новый хэш и токен, и авторизация сломается, потому что в куках находиться не актуальный токен. Как обойти обновление полей которые мы не хотим обновлять?

https://github.com/someApprentice/Students/blob/master/app/Controller/SearchAction.php#L15
Нужна ли валидация и список ошибок для формы поиска?

Как избавиться от $_GET['input'] в URL?

https://github.com/someApprentice/Students/blob/master/app/Controller/LoginAction.php#L52
Решил отказаться от залогинивания с помощью имени и фамилии. Слишком уж усложняется задача если использовать не уникальные данные. Главное что я понял что для каждого способа залогинивания должен быть свой метод.

https://github.com/codedokode/pasta/blob/master/student-list.md#Работа-с-формами

>После успешной регистрации или обновления данных об абитуриенте нам надо показать сообщение об этом. Проще всего для этого при редиректе (после успешной обработки формы мы делаем редирект, не забыл?) приписать дополнительный параметр в URL, то есть редиректить на адрес вида index.php?notify=registered, а уже в index.php проверять значение параметра notify.


А разве это не обязанность контроллера работать с $_GET данными?

https://github.com/codedokode/pasta/blob/master/student-list.md#Поиск-в-базе-данных

>Для поиска по всем колонкам можно применить оператор LIKE к соединенным через пробел значениям столбцов.


А можно простой пример такого запроса? У меня не получилось составить...

>name LIKE '%hello%'


А почему в примере без плейсхолдера написано? Это только в рамках простого примера?

https://github.com/codedokode/pasta/blob/master/student-list.md#Составление-url
Не совсем понимаю как этим пользоваться: Вот с ссылками для сортировки таблицы с результатами всё понятно, а как быть с формами? Допустим есть форма поиска с методом get и, насколько я знаю, её нельзя заставить отправлять этот запрос с помощью urlencode().
И еще не понятно какой класс должен заниматься этим. Свой собственный?

https://github.com/codedokode/pasta/blob/master/student-list.md#Постраничная-навигация

>Некоторые пытаются возложить на объект Pager лишние функции, например чтение параметров поиска из $_GET или подсчет числа записей в базе. Я не советую так делать, так как это явно должно быть в другом месте (например, работа с базой — в маппере).


Это касается всех $_GET запросов? Я бы на оборот сделал Pager контроллером который содержит метод, который на вход принимает результаты из БД, и затем из $_GET получал бы данные о номере страницы и сортировке, затем на их основе составлял таблицу с ссылками на страницы и сортировку. Он бы даже мог заниматься составлением ссылок для сортировки.
>>768205>>768312
#64 #755599
>>753595 (OP)
Бро, на кой хуй ты это делаешь, возишься тут с нами, ответы какие-то даёшь, копаешься в чужом говнокоде? Какие тебе с этого профиты? Поддерживаешь знания в актуальном состоянии, практикуешься так или всегда мечтал быть преподом?
>>755658
#65 #755604
>>755118
https://github.com/applejacky/tmp
Пока проверять не надо.
К завтрашнему вечеру запушу пару коммитов, очень многое поменяется.
>>759614
#66 #755658
>>755599

>хуй


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


Перечисление таких вещей больше говорит о тебе.
Люди совершенно не слышали о таких вещах как альтруизм, и я боюсь даже сказать о других высоких вещах. Надеюсь твоё невежество связанно лишь с юным возрастом, иначе тебе следует задуматься о ценностях в твоей жизни.
Хотя бы научись вести себя прилично и не материться. Ты не с быдлом в падике сидишь.
63 Кб, 660x422
#67 #755668
Есть ли простой способ взять переменную из unix config файла или нужно пердолиться со строками, читая файл?

Т.е. часто есть конфиги вида:

USER="SOMENAME"
DATABASE_NAME="NAME"

Неужели нет готовой функции внутри языка для считывания подобных файлов и записи переменных в массив?

$res = yobafunction('/etc/filename');
echo $res['USER']; // SOMENAME

Так вот, существует ли yobafunction?
>>755681
#68 #755677
>>755658
Прости за мат. Я как раз хотел спросить насчет альтруизма, не он ли это, но постеснялся выражаться. Ты же не ОП, а я хотел бы его ответа.

> Перечисление таких вещей больше говорит о тебе.


И психоаналитики не нужно.

> Люди совершенно не слышали о таких вещах как альтруизм, и я боюсь даже сказать о других высоких вещах


Реализация желания безвозмездно делать другим что-то хорошее приносит удовлетворение делающему. Значит, альтруизм - такое же действие ради СОБСТВЕННОЙ выгоды, пусть и нематериальной, как и любые другие. Своего рода хобби.
>>755801
#69 #755678
>>755658
Опять этот выблядок из одноклассников вылез.
Хомяки уже на дваче учат жизни питурдов.
Я уже говорил, что твоя мать шлюха?
#70 #755681
>>755668

Что такое unix config? Чем тебе ini файл не годится? Если ты про dotEnv то наверно есть библиотека, хотя я не сторонник этой штуки, считаю она неудачно спроектирована и неудобна, хоть и упоминается в 12 factor app.
>>755846
#71 #755801
>>755677

>Реализация желания безвозмездно делать другим что-то хорошее приносит удовлетворение делающему. Значит, альтруизм - такое же действие ради СОБСТВЕННОЙ выгоды, пусть и нематериальной, как и любые другие. Своего рода хобби.


Лежать в канаве под героином не имею ничего против героина тоже приносит удовольствие. Есть много вещей которые приносят удовольствие, разница в том какие из этих вещей приносят пользу другим или себе.
sage #72 #755839
>>754342
>>755658
Ты уже вытекаешь из треда. Худей, сука!

Не ведитесь на этого толстяка, и так половина постов всякой хуйни, мне потом скроллить это говно.
Если бы в разделе были нормальные модераторы, давно пожаловался бы флуд.
#73 #755846
>>755681
Никогда больше, никогда не отвечай на вопрос, смысл которого тебе не понятен.
#74 #755864
Drupal кун вкатывается в тред.
Вобщем есть модуль Node Hierarchy который настроен так чтобы новая продукция имела вид /категория/наименование. Не знаю может это устаревший способ но в данный момент я не могу использовать другой так как всё уже настроено.
Нужно как то профильтровать продукцию по url (берётся url категории, фильтруется, из него вырезается часть с названием категории, затем эта часть транслируется в представление (views) и как то нужно сделать чтобы фильтровались только те типы нод которые имеют в url этот "маркер" т.е. наименование категории). В итоге получается следующая картина: модуль Views фильтрует вначале все ноды по типу материала (продукция), затем берёт url страницы на которой представление выводится как блок, затем из этого url вырезается маркер и производится (контекстная?) фильтрация по наличию этого "маркера" в url продукта. Как результат я должен получить вывод в блоке на странице подкатегории списка дочерних нод. Как это реализовать? Куда хотя бы копать? Переписать иерархию и способ вывода материалов уже нереально, т.к. уже много проделано.
>>755865>>773828
#75 #755865
>>755864
p.s.
Как вариант, может быть как то реализовать фильтрацию url от слеша до слеша а потом сравнение с аналогичной фильтрацией url страницы на которой выводится блок views? Как это написать?
#76 #756017
Прошу прощения, больше не буду обижать проекты.
>>755326
штука в том, что я пользуюсь windows и у меня уже есть wget. Composer сохраняет библиотеки именно в текущую папку, или куда-то в "домашнюю папку"?
>>773828
#77 #756019

>Программист-стажер


>испытательный срок 3 месяца (возможно сокращение испытательного срока в связи с профессиональными успехами)


>Вознаграждение на испытательный срок:


>8 000 рублей/месяц


Я в отчаянии. Пойти туда, или ждать пока нормальная вакансия подвернется? Может скосят с 3ех месяцев до одного в связи с тем, что я не полный нуб?
>>756025
sage #78 #756025
>>756019
Тебе сложно что-то посоветовать. Чем они занимаются? Будут ли тебя бросать один на один с проектом или будут радушно протягивать руку помощи на любую просьбу? Каков твой уровень компетенции? Уверен, что сможешь приносить компании даже эти 8 тысяч в месяц? Почему не на фрилансе тогда?
>>756027
#79 #756027
>>756025

>Уверен, что сможешь приносить компании даже эти 8 тысяч в месяц? Почему не на фрилансе тогда?


Посмотрел тут вчера на апворке, может что приглянется. Все задачки связаны с вордпрессом, но самое охуенное - для подачи заявки на задание нужны некие коннекты, которые покупаются за деньги.
>>756071
#80 #756071
>>756027

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


Всё правильно сделали, нехуй бездумно спамить свое говно.
Их в месяц 60 штук дают бесплатно. На заявку нужно 2 коннекта, итого 30 заявок в месяц. Когда я в прошлом году искал фуллтайм-контракт, я их за 3 недели израсходовать не успел.
мимо проходил с руби-треда
#81 #756310
Где ОП?
#82 #756346
Подскажите нуфагу материала по шаблонизации и MVC. На словах я понимаю что это и зачем, но на деле нихуя не пойму как это реализовать, на примере той же задачки про студентов.
>>756365
#83 #756365
>>756346
В прошлых тредах вбрасывали, вродь годно: https://www.youtube.com/watch?v=Aw28-krO7ZM&list=PL7A20112CF84B2229
#84 #756441
>>755523

>Это не запрет отправлять запросы на другие домены.


Ничего кроме GET не сможешь отправить

>Он же без кук хочет отправлять запросы


Нихуя

>Cross-Site Request Forgery (CSRF) is a type of attack that occurs when a malicious web site, email, blog, instant message, or program causes a user's web browser to perform an unwanted action on a trusted site for which the user is currently authenticated.


Нужно чтобы ты был залогинен, и таким образом "POST bank.com/send-dengi-to-kulhatsker" с другого сайта сработало.
#85 #756490

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



ОП, объясни пожалуйста, что мне хранить в этом массиве то?
>>773828
#86 #756583
Это нормально начинающему пыхокодеру юзать нотепад++? Просто я пробовал крутые типа нетбинса и пхпшторма, но они слишком грудные и их функционала я вообще не понимаю.
>>756608>>756611
#87 #756601
>>755523
Ты вообще нулевой, я смотрю. Смысл лезишь к большим дядям?
#88 #756608
>>756583
Ты шутишь так?
Что непонятного в Шторме?
>>756615
sage #89 #756611
>>756583
Бери Sublime Text. Быстрый, из коробки умеет в автокомплит для переменных в текущем файле, множественные курсоры, уйма плагинов и так далее.
>>756615
#90 #756615
>>756608
Не то что непонятно. Просто нотепад оче быстро работает, а фичи пхпшторма я все равно не юзаю. Вот мне и интересно, нормальный ли у меня подход или лучше сразу же юзать больше среды разработки.
>>756611
Хорошо, попробую.
#91 #756755

>- Далее простая, но полезная задача сделать список студентов, в ней много полезных советов: https://github.com/codedokode/pasta/blob/master/student-list.md


Ананасы в вт сдача практики подобного задание. Есть ли у кого-нить исходники данного проекта?
>>773828
#92 #756770
Добавьте кто-то в уроки нормальный гайд по работе функций рхр с базами данных. В интернете по ссылкам везде лютый шлак.
>>756773
#93 #756773
>>756770
http://php.net/manual/ru/class.pdo.php Чем тебя не устраивает?
>>756810
#94 #756810
>>756773
Поясните нуфагу, чем PDO лучше функций MySQL?
>>756880
#95 #756880
Нет ли в шторме штуки, которая проверяет, используется ли где-то метод?
Например, я переписал кусок приложения, наверняка остались старые методы, которые нигде не используются, их надо бы удалить.

Вижу такую фишку, как find usages (alt + f7). Но это не надежно, например при использовании контейнера
$this->get('my_service')->doSmth()
метод doSmth не будет найден, потому что шторм не понимает, объект какого класса вернет get('алиас').
Поиск строкой только? Тоже не очень удобно, если имя неоригинальное типа save или create.

>>756810
Расширения mysqli ты хотел сказать? MySQL это система управления базами данных.
Слов "лучше/хуже, нормально/ненормально, правильно/неправильно" в программировании лучше избегать. У каждого решения есть свои преимущества и недостатки, нужно оценить их в зависимости от ситуации.

Преимущества pdo по сравнению с mysqli навскидку:
1. Автоматическая обработка ошибок (выбрасываются исключения), не нужно их обрабатывать вручную корявыми if (лажа) { выбросить исключение, ну или die('тупое сообщение'), как любят делать быдлокодеры }
2. Удобная работа с плейсхолдерами, экранирование без всяких real escape string. Впрочем в mysqli кажется тоже есть методы для работы с плейсхолдерами.
3. Внезапно mysqli поддерживает только субд MySQL.
Недостатков не вижу. Теоретически, может быть нативные функции для mysql быстрее, надо тестить.

https://habrahabr.ru/post/137664/
>>756907>>756952
#96 #756907
>>756880
Полагаю, проблема решается только костылями плагинами под каждый контейнер/фреймворк. Вот под Symfony: https://plugins.jetbrains.com/plugin/7219?pr=idea
#97 #756952
>>756880

>Расширения mysqli ты хотел сказать?


Да, точно.

>2. Удобная работа с плейсхолдерами, экранирование без всяких real escape string. Впрочем в mysqli кажется тоже есть методы для работы с плейсхолдерами.


Это ты про SQL - иньекции? Или как их там.
3. Внезапно mysqli поддерживает только субд MySQL.
Стоит ли ньюфагу пробовал другие субд? Или без разницы это все? Вообще, поясните чем они все друг от друга отличаются, если вкратце.
>>757067
#98 #757067
>>756952

>Стоит ли ньюфагу пробовал другие субд


Попробовать может быть и стоит, но запомни: всегда используй самые распространенные и обкатанные решения. Иначе сам будешь писать велосипеды.
#99 #757405
Спрошу тут, вроде по теме. Пытаюсь освоить MySQL, скачал Denwer, установил, вроде нормально всё, пытаюсь создать базу данных. Пишу следующее:

create database Sudents;

Выдает следующее:

ERROR 1044 (42000): Access denied for user ' '@'localhost' to database 'students'

Как я понимаю допуска какого то нету, или что то вроде того. Кто что подскажет? Вроде бы смотрел гайды, но решения проблемы там не нашел.
#100 #757413
>>757405
Ответ не совсем по сути от новичка, разобравшего недавно MySQL в общих чертах.
Сначала надо подключиться к MySQL - дать имя пользователя и пароль.
Я с самого начала послушался ОПа, поэтому удалил WAMPP и установил отдельно Apache, MySQL и PHP7.
Я запускаю MySQL в командной строке вот так:
mysql.exe -uroot -ppassword
Потом уже можно создавать или активировать использование баз данных.
Вообще в топку все эти сборки - совет тебе от новичка. Установить всё по отдельности - минут 10-15, зато не будет у тебя всякой ерунды там, самый новый РНР будет и так далее, сам себе хозяин.
#101 #757421
>>757405
Дак доступ-то к базе настрой:
GRANT ALL ON students.* TO 'yoba@localhost' IDENTIFIED BY 'etoti';
И подключайся потом юзером yoba и паролем etoti.
#102 #757423
>>757405

Первоначально ты заходишь под админом - имя root, пароль либо пустой либо задается при услановке mysql (как в сборках сделано, я не знаю). От рута можно создавать новых пользователей (рекомендую потренироваться), при желании у себя локально можно и под рутом работать, но лучше наверно для каждого проекта - своего пользователя с доустпом только к своей базе.
https://github.com/fidnex/students/ #103 #757628

>>745461


>>755118

https://github.com/fidnex/students/blob/master/app/Controller/Form.php#L45
Здесь код нелогичный: ты сначала залогиниваешь студента, а только потом вставляешь в БД. Это как-то нелогично, и есть шанс что например вставка не удастся. Надо делать в обратном порядке.

> $student->token = $authHelper->getToken();


> $tdg->update($student);


Непонятно зачем нужно обновлять токен.

В валидаторе мне не очень нравится, что у тебя смешаны в одном классе функционал валидации и результат валидации. Если уж ты так делаешь, то у тебя получился одноразовый валидатор (так как ошибки накапливаются в нем) и это тогда не сервис. Надо тогда переделать Pimple чтобы он кажды раз вовзвращал новый объект валидатора.

> class ValidateStudent


Имена классов это существительные. Не Validate, а Validator

https://github.com/fidnex/students/blob/master/app/Helper/FormHelper.php
Тут нет никаких белых списков. Пользователь может обновлять любые поля в объекте. В другом приложении (где у объектов есть какие-то поля которые должны быть недоступны пользователю) это будет уязвимость.

Также, тут ошибка в том, что обновляются вообще все поля объекта. В том числе например токен, который меняться не должен. И если кто-то завтра добавит новое поле, его тоже обнулит. Вообще, этот код неправильный. Все эти рассуждения неправильные:

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

Должен быть белый список обновляемых полей. Список соответствует набору полей в форме.

https://github.com/fidnex/students/blob/master/app/Helper/AuthHelper.php#L21
Кука удаляется установкой пустого значения + даты в прошлом. Также, ты не указал path для куки. В итоге получится что ты просто создашь вторую куку с таким же именем.

https://github.com/fidnex/students/blob/master/app/Helper/AuthHelper.php#L28
Непонятно зачем метод checkExistEmail() в класссе, отвечающем за авторизацию

https://github.com/fidnex/students/blob/master/app/Helper/PaginationHelper.php#L5
Поля принято объявлять каждое отдельной строкой.

https://github.com/fidnex/students/blob/master/app/Lib/Controller.php
Здесь не объявлено поле view

https://github.com/fidnex/students/blob/master/app/Lib/Validation.php#L7
abstract public function check(Model $model);
Не очень понятно почему валидация должна ограничиваться моделями. тут лучше было разрешить любой объект

> $error = $this->{$method[0]}(...array_merge(


> array($var),


> array_slice($method, 1)


Жутковатое какое-то выражение. Лучше было вынести часть значений в переменные.

https://github.com/fidnex/students/blob/master/app/View/main/index.php#L8
Я думаю, уведомлению не нужна кнопка закрытия. И странно, что кнопка сделана тегов ссылки, где здесь логика?

> <?php if($this->pagination->getCurPage() == $i) echo 'class="active"';?


Тут лучше было применить <?= ... ? ... : ... ?>. Не исопльзуй echo в шаблоне

https://github.com/fidnex/students/blob/master/app/View/form/index.php#L6

> required="true"


Тут надо писать просто required

https://github.com/fidnex/students/blob/master/app/View/form/index.php#L22
Пол не берется из модели при выводе формы

Так, в общем, хорошо сделано.
https://github.com/fidnex/students/ #103 #757628

>>745461


>>755118

https://github.com/fidnex/students/blob/master/app/Controller/Form.php#L45
Здесь код нелогичный: ты сначала залогиниваешь студента, а только потом вставляешь в БД. Это как-то нелогично, и есть шанс что например вставка не удастся. Надо делать в обратном порядке.

> $student->token = $authHelper->getToken();


> $tdg->update($student);


Непонятно зачем нужно обновлять токен.

В валидаторе мне не очень нравится, что у тебя смешаны в одном классе функционал валидации и результат валидации. Если уж ты так делаешь, то у тебя получился одноразовый валидатор (так как ошибки накапливаются в нем) и это тогда не сервис. Надо тогда переделать Pimple чтобы он кажды раз вовзвращал новый объект валидатора.

> class ValidateStudent


Имена классов это существительные. Не Validate, а Validator

https://github.com/fidnex/students/blob/master/app/Helper/FormHelper.php
Тут нет никаких белых списков. Пользователь может обновлять любые поля в объекте. В другом приложении (где у объектов есть какие-то поля которые должны быть недоступны пользователю) это будет уязвимость.

Также, тут ошибка в том, что обновляются вообще все поля объекта. В том числе например токен, который меняться не должен. И если кто-то завтра добавит новое поле, его тоже обнулит. Вообще, этот код неправильный. Все эти рассуждения неправильные:

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

Должен быть белый список обновляемых полей. Список соответствует набору полей в форме.

https://github.com/fidnex/students/blob/master/app/Helper/AuthHelper.php#L21
Кука удаляется установкой пустого значения + даты в прошлом. Также, ты не указал path для куки. В итоге получится что ты просто создашь вторую куку с таким же именем.

https://github.com/fidnex/students/blob/master/app/Helper/AuthHelper.php#L28
Непонятно зачем метод checkExistEmail() в класссе, отвечающем за авторизацию

https://github.com/fidnex/students/blob/master/app/Helper/PaginationHelper.php#L5
Поля принято объявлять каждое отдельной строкой.

https://github.com/fidnex/students/blob/master/app/Lib/Controller.php
Здесь не объявлено поле view

https://github.com/fidnex/students/blob/master/app/Lib/Validation.php#L7
abstract public function check(Model $model);
Не очень понятно почему валидация должна ограничиваться моделями. тут лучше было разрешить любой объект

> $error = $this->{$method[0]}(...array_merge(


> array($var),


> array_slice($method, 1)


Жутковатое какое-то выражение. Лучше было вынести часть значений в переменные.

https://github.com/fidnex/students/blob/master/app/View/main/index.php#L8
Я думаю, уведомлению не нужна кнопка закрытия. И странно, что кнопка сделана тегов ссылки, где здесь логика?

> <?php if($this->pagination->getCurPage() == $i) echo 'class="active"';?


Тут лучше было применить <?= ... ? ... : ... ?>. Не исопльзуй echo в шаблоне

https://github.com/fidnex/students/blob/master/app/View/form/index.php#L6

> required="true"


Тут надо писать просто required

https://github.com/fidnex/students/blob/master/app/View/form/index.php#L22
Пол не берется из модели при выводе формы

Так, в общем, хорошо сделано.
>>759401
#104 #757668
https://habrahabr.ru/company/mr_gefest/blog/247147/
Человек говорит, что в cloud9 можно посмотреть страницу в разных браузерах и разных устройствах.
Нимагу найти, как это делается.

Еще не разобрался как настроить виртуальный хост, чтобы он считал корнем папку web/.
У себя на убунте пишу хосты в /etc/apache2/sites-available. С облаком непонятно как это сделать, наверное через .htaccess, только не знаю что в него писать.
>>757695
#105 #757695
>>757668

> При разработке сайтов в данной IDE, их результат можно посмотреть в отдельном блоке интерфейса. Этот «preview» обладает одной необычной возможностью, которая заключается в том, что сайт можно виртуально проверить в разных браузерах и на разных устройствах. Данная технология предоставлена компанией «Sauce labs».



Судя по https://community.c9.io/t/saucelabs-previews-not-working/4391/5 там какие-то проблемы

тут http://sauceio.com/index.php/2014/07/announcing-cloud9-preview-instantly-preview-your-cloud9-project-in-any-browser-powered-by-sauce-labs/ есть скриншот как должно быть

Гугл: https://www.google.ru/search?q=cloud9+preview+saucelabs&newwindow=1&gbv=1&sei=8lRMV5D4EIqKsgH3yZ24DQ
>>757706
https://github.com/greenTea242/StudentList/ #106 #757698

>>746699


>>755118

на случай, если ты не видел ответ в старом треде, вот он:

----------

> А зачем ты вынес bootstrap из public? Ведь там идея что корень сервера в public и все, что за ним, недоступно через веб-сервер. Я имел в виду что бутстрап должен быть в исходном, неисправленном виде в своей папке внутри public.



>> А если пользователь при редактировании захочет очистить какое-то поле, эта проверка ведь его не пропустит?


> Можно удалять поля полностью и добавлять их в бд? Я про это не знал. Мои регулярки не пропускают пустые значения. Менять? Пользователь что, вообще может не заполнять ничего?


Я имел в виду, что если там есть необязательное поле (не помню есть ли оно в условиях), то тогда разумеется пользователь может очистить это поле чтобы сохранить пустое значение.

> Я не нарушаю логику отображения перенося ее из шаблона в методы из вспомогательных классов как ты советовал? В борьбе с копипастом создал их(методов) несколько.


Немножечко нарушаешь, так что лучше особо большие куски кода так не делать. Вообще, в нормальных шаблонизаторах вроде twig есть макросы, то есть "подшаблоны", и в них можно выносить куски кода и позже их вызывать. У нас их нет, так что надо либо куски выносить в отдельные файлы либо делать класс-помощник.

Но для борьбы с копипастом, я думаю, это приемлемо. Просто изолируй все такие функции в отдельном классе.

> [Конфигурация нашей базы данных]


В ini файлах так обозначают не комментарий, а название секции. Их лучше делать латинницей и короткими (или вообще не делать если файл маленький). Комментарий это строка, начинающаяся с точки с запятой.

> static function isInputChecked($genderOfAbiturient, $valueFromInput)


вообще тут можно было просто написать <?= $student->getGender() == Student::GENDER_MALE ? ' checked' : '' ?>. Но можно и функцию.

Остальное позже в новом треде напишу.

> Это нормально что я несколько раз отклонился от общего для кода стиля(камелкейс) для имени переменной и имени метода и использовал вариант с нижним подчеркиванием ("CSRF_token")? Мне показалось, что не очень красиво если будет "CSRFToken". Стоило ли тогда тоже самое делать с authToken для, не знаю как сказать, симметрии чтоли.


Нет, нехорошо. Лучше CSRFToken или csrfToken.

> Ну он у меня в бд попадал через модель. Сейчас после манипуляций с двумя токенами я его добавляю отдельно https://github.com/greenTea242/Student_List/blob/master/public/register.php#L31 . Ок?


Я думаю, не стоит ради токена делать лишний аргумент в setProperties. Его можно задать отдельной командой вроде

$student->setToken(...);

-----------

https://github.com/greenTea242/Student_List/blob/master/public/index.php#L39

> require_once __DIR__ . "/../templates/index.html";


тут явно должно быть не require_once, а просто require

https://github.com/greenTea242/Student_List/blob/master/src/Authorization.php#L12
очень странно. что раюотас CSRF в классе авторизации, и CSRF токен очищается при разлогинивании

> check_CSRF_token


не в том стиле название, должно быть checkCsrfToken

https://github.com/greenTea242/Student_List/blob/master/src/ini.php#L18
Имя БД лучше сделать меняемым через конфиг

https://github.com/greenTea242/Student_List/blob/master/src/ini.php#L31

> $authToken = isset($_COOKIE["authToken"]) ? strval($_COOKIE["authToken"]) : "";


лучше всю работу с кукой авторизации убрать в класс авторицации

https://github.com/greenTea242/Student_List/tree/master/src
тут 2 конфига осталось

https://github.com/greenTea242/Student_List/blob/master/templates/index.html#L4

> <p>Поздравляем с успешной регистрацией!</p>


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

https://github.com/greenTea242/Student_List/blob/master/templates/index.html#L26
Тут странно что в заголвке колонки сделано 2 отдельных ссылки - наверно лучше было одну.

Так, в общем, неплохо сделано.
https://github.com/greenTea242/StudentList/ #106 #757698

>>746699


>>755118

на случай, если ты не видел ответ в старом треде, вот он:

----------

> А зачем ты вынес bootstrap из public? Ведь там идея что корень сервера в public и все, что за ним, недоступно через веб-сервер. Я имел в виду что бутстрап должен быть в исходном, неисправленном виде в своей папке внутри public.



>> А если пользователь при редактировании захочет очистить какое-то поле, эта проверка ведь его не пропустит?


> Можно удалять поля полностью и добавлять их в бд? Я про это не знал. Мои регулярки не пропускают пустые значения. Менять? Пользователь что, вообще может не заполнять ничего?


Я имел в виду, что если там есть необязательное поле (не помню есть ли оно в условиях), то тогда разумеется пользователь может очистить это поле чтобы сохранить пустое значение.

> Я не нарушаю логику отображения перенося ее из шаблона в методы из вспомогательных классов как ты советовал? В борьбе с копипастом создал их(методов) несколько.


Немножечко нарушаешь, так что лучше особо большие куски кода так не делать. Вообще, в нормальных шаблонизаторах вроде twig есть макросы, то есть "подшаблоны", и в них можно выносить куски кода и позже их вызывать. У нас их нет, так что надо либо куски выносить в отдельные файлы либо делать класс-помощник.

Но для борьбы с копипастом, я думаю, это приемлемо. Просто изолируй все такие функции в отдельном классе.

> [Конфигурация нашей базы данных]


В ini файлах так обозначают не комментарий, а название секции. Их лучше делать латинницей и короткими (или вообще не делать если файл маленький). Комментарий это строка, начинающаяся с точки с запятой.

> static function isInputChecked($genderOfAbiturient, $valueFromInput)


вообще тут можно было просто написать <?= $student->getGender() == Student::GENDER_MALE ? ' checked' : '' ?>. Но можно и функцию.

Остальное позже в новом треде напишу.

> Это нормально что я несколько раз отклонился от общего для кода стиля(камелкейс) для имени переменной и имени метода и использовал вариант с нижним подчеркиванием ("CSRF_token")? Мне показалось, что не очень красиво если будет "CSRFToken". Стоило ли тогда тоже самое делать с authToken для, не знаю как сказать, симметрии чтоли.


Нет, нехорошо. Лучше CSRFToken или csrfToken.

> Ну он у меня в бд попадал через модель. Сейчас после манипуляций с двумя токенами я его добавляю отдельно https://github.com/greenTea242/Student_List/blob/master/public/register.php#L31 . Ок?


Я думаю, не стоит ради токена делать лишний аргумент в setProperties. Его можно задать отдельной командой вроде

$student->setToken(...);

-----------

https://github.com/greenTea242/Student_List/blob/master/public/index.php#L39

> require_once __DIR__ . "/../templates/index.html";


тут явно должно быть не require_once, а просто require

https://github.com/greenTea242/Student_List/blob/master/src/Authorization.php#L12
очень странно. что раюотас CSRF в классе авторизации, и CSRF токен очищается при разлогинивании

> check_CSRF_token


не в том стиле название, должно быть checkCsrfToken

https://github.com/greenTea242/Student_List/blob/master/src/ini.php#L18
Имя БД лучше сделать меняемым через конфиг

https://github.com/greenTea242/Student_List/blob/master/src/ini.php#L31

> $authToken = isset($_COOKIE["authToken"]) ? strval($_COOKIE["authToken"]) : "";


лучше всю работу с кукой авторизации убрать в класс авторицации

https://github.com/greenTea242/Student_List/tree/master/src
тут 2 конфига осталось

https://github.com/greenTea242/Student_List/blob/master/templates/index.html#L4

> <p>Поздравляем с успешной регистрацией!</p>


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

https://github.com/greenTea242/Student_List/blob/master/templates/index.html#L26
Тут странно что в заголвке колонки сделано 2 отдельных ссылки - наверно лучше было одну.

Так, в общем, неплохо сделано.
42 Кб, 579x413
#107 #757706
>>757695
На данный момент нельзя выбрать браузер, оно конечно отображается в каком-то безымянном, но непонятно в каком.
Ладно, короче когда починят будет круто.
#108 #757712
Переделал алгоритм прохождения тестов, роуты теперь содержат id сессии (попытки прохождения).
Выглядит намного лучше, но все равно мне кажется есть что улучшать.
https://github.com/nsdvw/TestHub

Прошлый тред смыло, ты мне там писал почитать про REST.
Почитал, мало что понял.
REST это всего лишь соглашение о семантичном url и уместном использовании http методов, правильно?
Допустим,
GET /book/123/page/456 - запрос на чтение 456 страницы 123 книги
POST /book/123/page/456 - запрос на добавление/изменение, возможно удаление соотв.ресурса

Вообще как-то размыто. Давным-давно все используют урлы типа /blog/post/123, это тоже REST?
RESTful api как я понимаю api с семантичными урлами?
Много мутной писанины, а по-сути можно выразить одним предложением.
#109 #757724
>>757712

> REST это всего лишь соглашение о семантичном url и уместном использовании http методов, правильно?


Это плебейский REST. Это то, что понимают под словом "REST" безграмотные индусы. Настоящему REST'у совершенно похуй на URL'ы. Настоящий REST - это https://en.wikipedia.org/wiki/HATEOAS

Вопрос "а нахуя в реальной жизни сдался этот настоящий REST?" остаётся открытым.
55 Кб, 640x369
#110 #757799
Скажите, для Yii2 точно пойдёт версия PHP7?
Или нужно обязательно ставить "не ниже 5.4"?
>>757802
#111 #757802
>>757799
Последняя stable версия фреймворка по большей части с седьмой версией работает нормально, так что можешь ставить.
>>757808
99 Кб, 880x607
#112 #757808
>>757802
Спасибо!
Подскажи ещё такую вещь: у меня хорошие знания синтаксиса, средние знания ООП, вполне нормальные знания MySQL.
Открыта вкладка с пространствами имён.
Открыта вкладка с MVC.
Есть ли шанс разобрать этот фреймворк с такой вот скромной базой?
Чувствую себя не вполне уверенно, обложился курсами и всякой ерундой, боюсь устанавливать сам фреймворк...
>>757816
#113 #757816
>>757808

Тебе уже по поводу Yii отвечали, иди пиши студентов.
>>757932
#114 #757819
Что такое фреймворк? Можно ли сказать что фреймворк - это готовое стандартное приложение? Мы включаем отдельные его участки и добавляем вычислительные функции. Транспорт данных во фреймворке регламентирован.
>>757823>>757842
#115 #757823
>>757819
И второй вопрос: "Можно ли назвать цмс высокоуровневым фреймворком? Ведь мы также добавляем модули и настаиваем их для перекачки данных туда-сюда, дописываем функционал.
>>757842
#116 #757842
>>757819
Фреймворк это готовый для повторного использования код. Большие фреймворки кроме собственно кода содержат инструменты разработчика: консольные команды, инструменты отладки, генерации кода и т.д.
Это не готовое приложение, это фрагменты исходного кода приложения. Фреймворки принято использовать ради стандарта (если в команду приходит новый человек, он уже знает как устроено приложение, если знает фреймворк) и ради избежания рутинной работы.

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

>Транспорт данных во фреймворке регламентирован.


Родился на улице Герцена. В гастрономе № 22.

>>757823
cms это не фреймворк, а примитивный crud для контент-манагеров.
Костыли вы дописываете, а не функционал.
>>757879
#117 #757866
Смотрите, анончики.

У меня есть база данных. В одной таблице есть куча данных.
Есть еще одна таблица, с 3 полями. Одно поле это айди, PK. Остальные поля - поля, аналогичные которым есть в первой таблице.

Я с помощью INNER JOIN ищу совпадения и вывожу одно из полей первой таблицы по обьединению общих полей со второй.

Для того, чтобы вывести все эти значения на страничке, нужен всего-лишь

if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "grup: " . $row["grup"]. "<br>";
}


Как сделать, чтобы $row["grup"] забивалось в html-овский insert ?
>>773828
#118 #757879
>>757842
Такое чувство что ты фреймворки и цмски в глаза не видел и не работал с ними.

>если в команду приходит новый человек, он уже знает как устроено приложение


По твоим словам выходит что фреймворк - это приложение.

>Большие фреймворки кроме собственно кода содержат инструменты разработчика: консольные команды, инструменты отладки, генерации кода и т.д.


Самопис тоже без этого не обходится.

>Фреймворк это готовый для повторного использования код.


Как о функции или либе сказал. Мысли шире. Фреймворк - это готовое приложение уже.

>Родился на улице Герцена. В гастрономе № 22.


Небыдло, да?

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


Мантра твоя?

Еще вопрос назрел. Можно ли сравнить программиста с рельсоукладчиком, который прокладывает пути для сигналов, строит депо?
>>757943
948 Кб, 880x587
#119 #757886
ООО ВЕКТОР
Оп, исправил все, о чем ты написал. Опять возникла проблема с клонированием: клоны перезаписывают оригинал с каждым использованием. И почему-то количество работников в норме, а вот зарплата, кофе, страницы меняются.
http://ideone.com/rOfeNX
>>773829
52 Кб, 604x474
#120 #757932
>>757816
Спасибо!
Но нет.
>>757996
#121 #757943
>>757879

>выходит что фреймворк - это приложени


Это каркас приложения, даун. Он всегда одинаковый в общем, но разный в деталях. А еще фрамевок - это билиотека готовых ходовых решений, но всегда можно запилить что-то свое в рамках идеалогии каркаса.
>>757974
#122 #757974
>>757943

>software providing generic functionality


Ты олигофрен или идиот, дурак или имбецил, кретин или балбес, балда или болван, дуралей или тупица?
>>758042
#123 #757996
>>757932

Почему ты не хочешь делать студентов?
>>758082
#124 #758042
>>757974
Да тыж обосрался, долбоеб, немогущий в ингишь.

> an abstraction in which software providing generic functionality can be selectively changed


> an abstraction

>>758052
#125 #758052
>>758042
Ёбаннный ты олень, тебе расшифровка абстракции дается.
#126 #758082
>>757996
Рискую увязнуть в них на всё лето.
Не могу себе позволить такую роскошь, просто не могу.
Я ведь обычно довожу до конца то, за что берусь.
Мне просто надо разобраться в фреймворке на уровне подключений, интеграции модулей и виджетов - и так далее.
>>758193
#127 #758193
>>758082
Эта задача маааксимум на неделю, бро.
Если уже хорошо разобрался в языке, справишься.
#128 #758194
Всем хорошего.

Я тут как то спрашивал о том, как идти на повышение зарплаты и как оценить свою стоимость.
Мне подкинули какую то книжку о том, как говорить о зарплате. Я всё проебал и не могу найти в архиваче, может кто вбросить еще раз?
#129 #758286
Старнно, что я не нашёл в этом треде упоминания о smarty.

Никто не юзает этот клёвый шаблонизатор?
#130 #758320
>>758286

как там, в 2000?
#131 #758321
>>758286
Шаблонизатор как шаблонизатор, откуда такой утиный восторг?
К тому же сильно устарел, хотя может в третьей версии подтянули, не знаю.
Пользуюсь твигом из-за множественного наследования, автоэскейпа и расширяемости (удобно добавлять свои фильтры и функции).
>>758395>>758574
#132 #758389
Привет, /зк/.

Я вот тут от нечего делать пишу древовидную структуру (в CMS встречается повсеместно - например категории и в них лежат товары).
Меня вот интересует, неужели оно везде сделано через такую же жопу?
[code]select group_concat(n.name order by n.id separator '/') as path from closure_table d left outer join closure_table a on (a.cid = d.cid) left outer join nodes n on (n.id = a.pid) where d.pid = 2 group by d.cid order by group_concat(lpad(n.id,11,'0') order by n.id separator ',');
+----------------------------+
| path |
+----------------------------+
| /var |
| /var/www |
| /var/run |
| /var/run/mysql |
| /var/run/mysql |
| /var/run/mysql/mysqld.sock |
| /var/run/mysql/mysqld.pid |
| /var/lib |
| /var/lib/mysql |
+----------------------------+
9 rows in set (0.00 sec)[/code]
>>758403
#133 #758395
>>758321
Когда-то писал свой первый и последний промышленный скрипт - использовал в качестве шаблонизатора XSLT. Конечно, он адово перегружен по сравнению с тем же твигом, но внезапно довольно удобен.
Правда сама разметка заметно сложнее - всякие там xsl-foreach и ебля с xpath.
>>758574
#134 #758403
>>758389

урок по теме https://github.com/codedokode/pasta/blob/master/db/trees.md

с closure_table по идее должен быть только один джойн
>>758409
#135 #758409
>>758403
Мне просто неохота туда пихать дополнительные поля.
Смысл в том, что без двух джойнов сортировка идёт чисто по ID, и если допустим /var/lib/mysql/mysqld.pid был добавлен сильно позже /var/lib/mysq/mysqld.sock, то он и в списке будет идти отдельно. А мне надо бы всё отсортировать к красивому виду.
#136 #758574
>>758286
>>758321
>>758395

Имхо, шаблонизаторы не нужны, пхп и есть шаблонизатор так то
>>758586
#137 #758586
>>758574
Смотря кому и в каких ситуациях.

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

{{ user.name }}
вместо
<?php echo $user->getName(); ?>

{{ var|e }} или даже {{ var }} (экранирование включено по умолчанию)
вместо
<?php echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8') ?>
которые будешь забывать в 20% случаев

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

Куча встроенных фильтров и функций тоже облегчает.
>>758743>>759122
#138 #758743
>>758586

> {{ user.name }}


аналогом будет <?= htmlspecialchars($user->name, ET_QUOTES) ?> скорее и это special chars довольно надоедает писать руками. Можно конечно сделать функцию вроде html () или h() но все равно не то.

Ты еще макросы не упомянул.
>>759122
#139 #758803
Второе задание а уже застрял, чувствую себя дауном, помогите! http://ideone.com/pNLFGc
>>758812
#140 #758812
>>758803
уже решил
#141 #758998
а я могу в методе класса А вызвать метод клсса Б?
>>759011>>759020
#142 #759011
>>758998
Только если ты наследуешь класс А от класса Б или имеешь зависимость класса А от класса Б. Ты узнаешь позже об этих вещах.
>>759335
#143 #759012
The PHP exe file you specified did not run correctly:
C:\PHP\php.exe

The php.ini used by your command-line PHP is: C:\PHP\php.ini

A setting in your php.ini could be causing the problem: Either the 'extension_dir' value is incorrect or the dll does not exist.

Program Output:
Warning: PHP Startup: Unable to load dynamic library 'C:\PHP\ext\php_interbase.dll' - %1 не является приложением Win32.
in Unknown on line 0

Что делать теперь?
>>759016>>759019
9 Кб, 646x223
#144 #759016
Друзья, что-то надо в php.ini включить теперь?
Обновил PHP7.0.5 до PHP7.0.7 - сразу вот это всё прошло - >>759012
Но там у меня куча всего была раскомментирована до этого, просто скопировать код из php.ini страшновато.
Подскажите, что там раскрыть надо, я немного еду.
Сейчас стал сидеть до 2-3 ночи, но днём сплю час после обеда - неплохо, базарю, только начинаю тупить под конец
>>759019
20 Кб, 657x392
#145 #759017
Вот ещё что.

>После установки Composer устанавливать Yii можно запустив следующую команду в папке доступной через веб:


>composer global require "fxp/composer-asset-plugin:~1.1.1"


>composer create-project --prefer-dist yiisoft/yii2-app-basic basic


>Первая команда устанавливает composer asset plugin, который позволяет управлять зависимостями пакетов bower и npm через Composer. Эту команду достаточно выполнить один раз. Вторая команда устанавливает Yii в директорию basic. Если хотите, можете выбрать другое имя директории.


А у меня пикрелейтед происходит...
Подскажите, пожалуйста, как всё установить.
>>759019
#146 #759019
>>759012

> Unable to load dynamic library


Это значит не хватает каких-то библиотек чтобы загрузить расширение. Ты можешь скачать программу dependency walker или аналогичную и увидеть какие dll нужны для php_interbase.dll (скорее всего что-то из комплекта interbase). Надо либо их установить либо отключить это расширение. Не надо было включать все подряд, сам виноват.

>>759016

Написано же: не хватает прав чтобы создать папку. Ты зачем в папке Windows пытаешься создать проект?

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

>>759017

У тебя git либо не установлен либо его нет в PATH. Прочитай гайд по командной строке. Также, если бы ты использовал инсталлятор композера, а не отдельный phar файл, то он бы установил тебе все, что нужно.
>>759124
#147 #759020
>>758998

Для этого тебе надо иметь объект класса Б (или наследоваться от него). Методы вызываются не сами по себе, а на каком-то объекте, если нет объекта - нельзя вызвать.
>>759040>>759335
#148 #759040
>>759020

>если нет объекта - нельзя вызвать


Статические методы есть.
#149 #759056
Господа, а как на водпрессе сделать клон хабра? Регистрируется фирма поликилинка, у каждой свой адрес, блог, отображается кол-во просмотров, комментов (через виджет вк), адрес, показывается адрес на гугл карте. Есть блоки самое читаемое, популярное, рекомендуемое. У каждой клиники не просто блог, а блок с подкаталогами и своя выдвигающаяся, как в водпрессе админка. Это же дохрена виджетов и плагинов подключать и разрабатывать, ведь так? И кучу таблиц в бд создавать? Каждая клиника может грузить видео, фото, в создании блогов есть возможность форматировать текст (как в жж). Там еще звезды, голосования, виджеты соцсетей.

В вордпрессе есть все это готовое?
>>759069
#150 #759069
>>759056

livestreet
#151 #759085
Каждый раз, запуская GitShell.exe нужно делать cd "путь проекта". Можно как-то сделать каталог по-умолчанию?
>>759093>>759576
7 Кб, 1366x65
31 Кб, 947x159
#152 #759091
И еще. При включенном set_exception_handler мне вместо нужных действий выводится ошибка на пике. Как я понял, проблема в том, что в ф-ии прописано принимать тип Exception, а у нас ошибка другого типа, и поэтому фатал ерор. Как это можно исправить? А то, чтобы посмотреть в чем ошибка мне приходится комментить эту ф-ию
>>759115
#153 #759093
>>759085
В свойствах ярлыка смени --open-shell на --open-shell=C:\path\to\folder

Где \path\to\folder очевидно папка которую ты хочешь сделать по умолчанию.
#154 #759115
>>759091

Исправить можно не укзаывая тип или указав интерфейс Throwable. Погугли.

И сразу скажу что ты очень невнимательно читал про исключения и видимо не изучал HTTP. Там написано что при ошибке принято отдавать код 5xx а ты отдаешь 3xx.
>>759576
#155 #759122
>>758743
>>758586

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

Но твиг красив, это да
#156 #759124
>>759019
Спасибо большое, попробую всё.
Прошу прощения, действительно забыл ознакомиться с мануалом о командной строке - у меня всё получилось с MySQL, я переключился на другое. Я помню, ты советовал его мне.
Буду разбираться теперь, спасибо, ОП!

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


Хм, я использовал вот отсюда именно инсталлятор: https://getcomposer.org/download/
Сначала проводник ругался, что нет FbClient.dll, я его вроде бы установил, обновил версию РНР - всё установилось. Ну а далее уже вот это всё пошло.
Буду разбираться.
#157 #759163
>>753595 (OP)
Может кто на примере объяснить как работать с singletone шаблоном?
>>759193
#158 #759193
>>759163

Перед изучением этого паттерна тебе стоит прочесть хотя бы этот урок (а возможно и что-то еще): https://github.com/codedokode/pasta/blob/master/arch/di.md
7 Кб, 768x38
#159 #759209
Ребят, что если csrt_token приходится escape'ить, то есть он генерируется вместе с символами ", ', <, >.
На выходе пик.
Сама случайная строка генерируется вот так:
for ($i = 0; $i < $randomStringLength; $i++) {
$randomString .= chr(mt_rand(33, 126));
}

Или стоит прописать набор символов, из которых генерировать случайную строку, исключив special chars?
>>759234
35 Кб, 938x212
#160 #759234
>>759209
Извините, оказывается у ОП-а в пасте всё есть. Вопрос закрыт.
#161 #759335
>>759011
>>759020
Условно говоря, что надо?

Есть некий товар с кучей параметров, храниться в БД.
И есть простыня процедур, для разных действие с этим товаром - КРУД, теги товара и бог знает что ещё.

Что я хочу? Переписать весь этот джехад в объектном стиле.
Допустим, я сделаю класс Product. В нём будут поля, соовтестующие полям товара в бд и методы, скажем, для их вывода и изменения. Но получается таким образом, что мне придётся в методах класса описывать функцию выборки из бд, к примеру. И что мы в этоге получим? Да ту же простыню, не?
Или, возможно, я не до конца понимаю суть ООП.
>>759339
#162 #759339
>>759335
Читал пасту ОПа по паттернам для работы с БД?
https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md

>возможно, я не до конца понимаю суть ООП.


Ты и с MVC, по-видимому, дела не имел.
#163 #759341
>>759339
Если я на MVC начну это переписывать, то я сейчас ёбнусь.
Так не так чтоб очень большой проект
#164 #759383
>>759339
Спасибо за наводку, полезная статья, втыкаю.
#165 #759386
>>759339
я ещё похоже и суть MVC не понимаю до конца.
В данном случае, применительно для, условно говоря, сайтов по продаже говна через интернет,
представление (view) - это шаблоны html на каком-то шаблонизаторе
модель (model) - это вся логика, например, связанная с БД,
а контроллер (controller) - это, видимо, "роутер" разбирающий запросы?
>>759411>>759582
#166 #759401
>>757628
Спасибо, поправил: https://github.com/fidnex/students/commit/f07543a8552746b94e13d2520dd7a32ba26170f0

>Непонятно зачем нужно обновлять токен.


Он не обновляет, а достает существующий из кук. Токен у меня роль айдишника в маппере выполняет.
>>759582
#167 #759411
>>759386

>а контроллер (controller) - это, видимо, "роутер" разбирающий запросы?


Обычно роутер разбирает запрос и вызывает нужный контроллер. Но вообще да, что-то такое.
47 Кб, 321x480
#168 #759489
Должен ли composer прописываться в PATH для нормальной работы?
>>759496>>759582
#169 #759496
>>759489
Прописывается исключительно для удобства, чтобы не печатать полный путь к исполняемому файлу. Если тебе не лень каждый раз вбивать полный путь к нему, то прописывать папку с ним в PATH незачем.
Если composer работает как-то неправильно (я не понял что ты подразумеваешь под "нормальной работой"), то добавление папки с ним в PATH ничего не изменит.
Зачем ты опять её запостил, у меня опять шишка дымиться начинает.
>>759507
#170 #759507
>>759496

>Если composer работает как-то неправильно (я не понял что ты подразумеваешь под "нормальной работой")


У меня вот такой путь в РАТН:

>C:\Users\User\AppData\Roaming\Composer\vendor\bin


Но в самой этой папке нет папки bin - ничего не работает.
Сейчас пробую установить Git - тоже нет его пока.
Я вообще в растерянности - ни черта ничего не работает, я думал, гораздо проще и лучше будет это всё. Я когда программирование учить начинааааал...
У меня всего 4-5 картинок, извини, не буду
>>759511>>759582
#171 #759508
Сделал тут сапера с использованием MVC из урока ОПа.

https://foobar1643.github.io/minesweeper/

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

https://foobar1643.github.io/minesweeper/multiple.html
#172 #759511
>>759507
А где у тебя исполняемый файл композера? Я не знаю, где в винде должен лежать композер, в линуксе бинарники, как правило, лежат в /usr/bin/
>>759519
10 Кб, 581x141
#173 #759519
>>759511
Вот нет его почему-то.
Только вот это
<-----
А в папке vendor есть две пустые папки - composer и fxp.

Я вообще пока бреду в темноте и раздвигаю руками какие-то неприятные заросли. Пока ничего не нараздвигал.
>>759538>>759561
9 Кб, 362x423
#174 #759520
>>759508
Когда остаётся последний квадрат - не получается поставить флажок - не реагирует на нажатие.
>>759524
10 Кб, 365x420
#175 #759521
>>759508
А дальше что-то непонятное.
Но я впервые играю, не понял, что тут такое вообще.

У меня вообще сегодня всё через задницу
>>759524
16 Кб, 874x417
#176 #759523
>>759508
Нет, это я и в простой игре туплю, простите.
#177 #759524
>>759520
Флажков на поле может быть не больше чем бомб, надо было мне где-нибудь счетчик сделать. Ты где-то лишний поставил.
>>759521
Знаком Х помечены места где флажки стояли неправильно. Сообщения о проигрыше не показало? Какой браузер?
>>759527>>759582
#178 #759527
>>759524
Нет, просто не мог поставить лишний флажок - не реагировало. А потом нажал и БАБАХНУЛ.
Firefox самый последний какой-то.
Хорошо было бы, если бы при закончившихся флажках появлялось предупреждение, что они закончились.
>>759535
#179 #759535
>>759527
Ок, сделаю, спасибо за фидбэк.
#180 #759538
>>759519
Вот сейчас установил Git и столкнулся с блокировкой запросов к API:

Created project in basic
Loading composer repositories with package information
Updating dependencies (including require-dev)
Reading bower.json of bower-asset/jquery.inputmask (3.1.55)
Could not fetch https://api.github.com/repos/RobinHerbots/jquery.inputmask/conte
nts/bower.json?ref, please create a Git
Hub OAuth token to go over the API rate limit
Head to https://github.com/settings/tokens/new?scopes=repo&description=Composer+
on+
+2016-06-01+1713
to retrieve a token. It will be stored in "C:/Users/User/AppData/Roaming/Compose
r/auth.json" for future use by Composer.
Token (hidden):

Как сделать этот токен?
>>759539
#181 #759539
>>759538
Ну вот тут можно сгенерировать токен: https://github.com/settings/tokens/new?scopes=repo&description=Composer
А что там должно быть, что нужно указать, какие чекбоксы проставить?
>>759582
18 Кб, 951x412
17 Кб, 841x354
#182 #759561
>>759508
У тебя можно с первого раза наткнуться на бомбу (пик). Одно из решений: поле должно заполняться бомбами только после того, как откроется первая клетка.

>>759519
Не знаю, братишка, я буквально через пару месяцев после того, как обзавёлся компом, пересел на линукс, чего и тебе советую. Там этот composer ставится и прописывается в PATH одной строчкой в консоли.
Как вариант попробуй зайти на официальный сайт composer'а, чтобы скачать оттуда архив с исполняемым файлом и уже им пробуй пользоваться. В винде есть опция вроде "открыть терминал в текущей директории"?
>>759580
#183 #759576
>>759085

Спасибо

>>759115

> при ошибке принято отдавать код 5xx


На скриншоте переадресация на 503

> а ты отдаешь 3xx


Где? Ты осмотрелся ведь?
>>759584
#184 #759577
Начал изучение погромирования на ПХП, решил кекнуть в тред свое "спасибо" за ваше графоманство.
#185 #759580
>>759561

>поле должно заполняться бомбами только после того, как откроется первая клетка.


Лучше делит бомбы если попал при первом нажатии.
>>759614
#186 #759582
>>759401

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

>>759386

роутер это роутер.

>>759489

Можно прописать, да, только не composer.phar (смысл?), а файл с названием composer, который обычно является скриптом, запускющим composer.phar

Обчно если ты ставишь его инсталлятором, он сам куда надо прописывается, если вручную то конечно нет. Я просто скачиваю его в любую папку и запускаю как php d:/tmp/cmposer.phar ....

>>759507

Чтобы команда composer работала, там должен быть файл composer.exe или composer.bat

>>759524

А это правило ты сам придумал или оно в других версиях сапера тоже есть? Первый раз слышу.

>>759539

Никакие права и доступы давать не надо, то есть галочки ставить не надо. Токен нужен тольо для обхода ограничения на частоту запросов с одного IP
>>759593>>759639
#187 #759584
>>759576

> На скриншоте переадресация на 503


Ну, а переадресация - какой это HTTP код?
>>759656
#188 #759593
>>759582

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


Действительно, да. Убрал.
#189 #759614
>>759580
Это костыль.
Во-первых, бомб становится меньше. Во-вторых, нужно уменьшать цифры вокруг удалённой бомбы на единицу. То есть, мы сначала расставили бомбы, посчитали их, расставили цифры вокруг. А после удаления бомбы, опять посчитали. А я предлагаю расставлять бомбы после первого хода и считать один раз.

Алсо, >>755604-это сообщение уже неактуально, допилил пагинацию и поиск жуткими костылями. Репозиторий переехал сюда: https://github.com/applejacky/students
Завтра добавлю дамп БД и инструкции по установке на локалхост.
Minesweeper MVC #190 #759622
>>759508

А интересно, по какой логике классы распределены по файлам? В одном файле один класс, в другом - несколько. И сами определения классов как-то перемешаны.

Далее: http://pastebin.ru/8hYTOhA9
#191 #759639
>>759582

>>роутер это роутер.


а что тогда такое контроллер?
>>759648
#192 #759648
>>759639
Чому не гуглишь? Контроллер, в общем и очень упрощенном случае, обращается к модели/мапперу, обрабатывает GET/POST параметры, обращается к валидатору, передаёт результат во вью.
>>759657
12 Кб, 765x159
#193 #759656
>>759584

Содержимое 503.php
>>759665
#194 #759657
>>759648

>>Контроллер, в общем и очень упрощенном случае, обращается к модели/мапперу, обрабатывает GET/POST параметры, обращается к валидатору


Нуууу я по роутером ЭТО тоже имел ввиду, просто несколько его расширил.
Понятно, снимаю вопрсо.
>>759665
Примеры готовых решений #195 #759665
Примеры решений задачи про список студентов:

- https://github.com/search?l=PHP&q=student+list&ref=searchresults&type=Repositories&utf8=✓
- https://github.com/search?l=PHP&p=1&q=student+&ref=searchresults&type=Repositories&utf8=✓

про файлообменник:

- https://github.com/search?l=PHP&q=file+sharing&ref=searchresults&type=Repositories&utf8=✓

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

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

>>759656

Ты представляешь, как делается редирект? Редирект это отдача в качестве ответа кода 3xx и заголовка Location. Редиректить при ошибке, как и при 404 или 403 - неправильно. Вдобавок, в адресной строке браузера теряется УРЛ и обновить страницу нельзя.

>>759657

Роутер делает только одну функциию: анализирует УРЛ и решает какой контроллер и какое действие надо вызвать.
Роутер и контроллер это очень разные вещи.

Также, есть паттерн Front Controller, когда все запросы поступают первоначально на основной контроллер, а он уже вызывает какой-то конкретный.
>>765725
#196 #759692
Примеры тестовых заданий с гитхаба: https://gist.github.com/search?utf8=✓&q=тестовое+задание&ref=searchresults

Особую сложность представляет тестовое задание для HR: https://gist.github.com/noff/8705086
>>759896
#197 #759694
оп, это ты?

Наведи на мысль, как правильно написать многоэтажную форму по созданию теста в testhub.
Потому что у меня пока получается лютый говнокод, стыдно даже коммитить, но как правильно сделать не представляю.

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

Я через пару часов запушу, но там по-любому нужно полностью переписывать.
>>759714>>759716
#198 #759714
>>759694

Форма в Симфони строится поверх какой-то модели. Модель может быть 2 видов:

- массив или вложенная структура из массивов (не одобряю для данного случая)
- сущность или дерево (вложенная структура) из сущностей

Если ты внимательно изучал формы симфони, то наверно знаешь что понятия "форма" и "элемент формы" там описываются одним классом (Form). Просто в первом случае он привязан к сущности, а во втором - к ее полю. Form могут произвольно вкладываться друг в друга, то есть мы можем сделать поле для:

- вложенной сущности (при связях многие-к-1 и 1-к-1)
- коллекции вложенных сущностей (CollectionType)

В твоем случае многоэтажная форма должна строиться поверх дерева объектов. Очевидно что корневой объект тут Тест, он содержит коллекцию Вопросов, они могут содержать Варианты Ответов.

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

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

Какие тут есть сложности? Ты их не сформулировал, придется формулировать мне:

- вопросы бывают разных типов (назовем это "полиморфность вопросов"). Форма на сервере должна корректно воссоздавать их при обработке данных и корректно выводить на странице. Очевидно, что это обозначает наследование в таблице и в зависимости от выбранного способа наследования (STI, ClTI, CoTI) будут разные реализации форм. Возможно что симфониевские формы из коробки не поддерживают некоторые варианты. Тогда тебе придется их расширить - например написав новый виджет формы "полиморфная коллекция", расширив существующий CollectionType или добавив "адаптер" между CollectionType и дочерними формами

Вот например я нагуглил такое:

https://gist.github.com/merk/3058342
https://github.com/infinite-networks/InfiniteFormBundle#polycollection

Там сделан кастомный виджет для коллекции из разнотипных сущностей. Но у меня есть и другая идея: может можно сделать "адаптер" который ставится между стандартным CollectionType и разнотипными вопросами. Может быть, это позволит избежать дублирования кода из collectionType, а также позволит использовать адаптер и для других случаев (полиморфная дочерняя сущность не в коллекции).

Я не советую спешить его копировать. Ты как минимум должен понимать каждую строчку в нем. Для этого, разумеется, потребуется понимание архитектуры symfony forms и без изучения исходников тут вряд ли получится обойтись.

- безопасное редактирование. Мы можем сделать так: удалять все вопросы, которые есть в базе, но которых нет в пришедших данных. А можем - удалять только те вопросы, для которых пришел флаг "delete". Очевидно второй подход чуть безопаснее и защищает от программистских ошибок. Также, если его реализовать в виде чекбокса (который можно стилизовать как кнопку например), как бонус, мы можем реализовать отмену удаления до отправки формы.

- еще проблема - как интегрировать яваскрипт-код добавления вопроса с кодом вывода форм симфони. Тут все относительно просто: во-первых, мы можем выводить форму вручную, по полям, во-вторых, мы можем сделать вопрос-пустышку и отрендерить форму с ним в JS-шаблон. И при добавлении нового вопроса брать шаблон и вставлять в код. Погугли symfony collection type dynamically add

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

Также, еще есть вариант отказаться от серверного рендеринга в пользу клиентского. Сервер дает только данные о форме, а сама форма создается и динамически модифицируется с помощью клиенткского фреймворка вроде angular, knockout или react. Но это получается очень сложно, ведь фактически ты должен написать клиентское приложение и поддерживать его параллельно с серверной частью. Лучше наверно обойтись тут простыми средствами.

- как что-то менять в рендеринге форм. Ну тут ответ стандартный - symfony form theming. Там можно переопределить любой из шаблонов.

В общем, хотелось бы услышать конкретные вопросы, что именно сложно, а то приходится угадывать и длинные телеги писать.
#198 #759714
>>759694

Форма в Симфони строится поверх какой-то модели. Модель может быть 2 видов:

- массив или вложенная структура из массивов (не одобряю для данного случая)
- сущность или дерево (вложенная структура) из сущностей

Если ты внимательно изучал формы симфони, то наверно знаешь что понятия "форма" и "элемент формы" там описываются одним классом (Form). Просто в первом случае он привязан к сущности, а во втором - к ее полю. Form могут произвольно вкладываться друг в друга, то есть мы можем сделать поле для:

- вложенной сущности (при связях многие-к-1 и 1-к-1)
- коллекции вложенных сущностей (CollectionType)

В твоем случае многоэтажная форма должна строиться поверх дерева объектов. Очевидно что корневой объект тут Тест, он содержит коллекцию Вопросов, они могут содержать Варианты Ответов.

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

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

Какие тут есть сложности? Ты их не сформулировал, придется формулировать мне:

- вопросы бывают разных типов (назовем это "полиморфность вопросов"). Форма на сервере должна корректно воссоздавать их при обработке данных и корректно выводить на странице. Очевидно, что это обозначает наследование в таблице и в зависимости от выбранного способа наследования (STI, ClTI, CoTI) будут разные реализации форм. Возможно что симфониевские формы из коробки не поддерживают некоторые варианты. Тогда тебе придется их расширить - например написав новый виджет формы "полиморфная коллекция", расширив существующий CollectionType или добавив "адаптер" между CollectionType и дочерними формами

Вот например я нагуглил такое:

https://gist.github.com/merk/3058342
https://github.com/infinite-networks/InfiniteFormBundle#polycollection

Там сделан кастомный виджет для коллекции из разнотипных сущностей. Но у меня есть и другая идея: может можно сделать "адаптер" который ставится между стандартным CollectionType и разнотипными вопросами. Может быть, это позволит избежать дублирования кода из collectionType, а также позволит использовать адаптер и для других случаев (полиморфная дочерняя сущность не в коллекции).

Я не советую спешить его копировать. Ты как минимум должен понимать каждую строчку в нем. Для этого, разумеется, потребуется понимание архитектуры symfony forms и без изучения исходников тут вряд ли получится обойтись.

- безопасное редактирование. Мы можем сделать так: удалять все вопросы, которые есть в базе, но которых нет в пришедших данных. А можем - удалять только те вопросы, для которых пришел флаг "delete". Очевидно второй подход чуть безопаснее и защищает от программистских ошибок. Также, если его реализовать в виде чекбокса (который можно стилизовать как кнопку например), как бонус, мы можем реализовать отмену удаления до отправки формы.

- еще проблема - как интегрировать яваскрипт-код добавления вопроса с кодом вывода форм симфони. Тут все относительно просто: во-первых, мы можем выводить форму вручную, по полям, во-вторых, мы можем сделать вопрос-пустышку и отрендерить форму с ним в JS-шаблон. И при добавлении нового вопроса брать шаблон и вставлять в код. Погугли symfony collection type dynamically add

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

Также, еще есть вариант отказаться от серверного рендеринга в пользу клиентского. Сервер дает только данные о форме, а сама форма создается и динамически модифицируется с помощью клиенткского фреймворка вроде angular, knockout или react. Но это получается очень сложно, ведь фактически ты должен написать клиентское приложение и поддерживать его параллельно с серверной частью. Лучше наверно обойтись тут простыми средствами.

- как что-то менять в рендеринге форм. Ну тут ответ стандартный - symfony form theming. Там можно переопределить любой из шаблонов.

В общем, хотелось бы услышать конкретные вопросы, что именно сложно, а то приходится угадывать и длинные телеги писать.
#199 #759716
>>759694

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


там же динамически добавляются только вопросы и варианты ответов. Нужны шаблоны только для них. Шаблон можно получить, сделав например модель-пустышку и отрендерив.
#200 #759720
Тестовое (JS) в Яндекс: https://gist.github.com/arikon/6200406f1fabd0046ea6
>>759722>>759725
#201 #759722
>>759720
Зачем ты это постишь? Издеваешься?
Тут никто не может продвинуться дальше задачи про блог студентов, а ты с собеседованиями от яндекса.
>>759724
#202 #759724
>>759722

Анон выше тестхаб пилит и в симфони ковыряется, другой анон, я помню, reactphp изучал. Все возможно, если приложить достаточно усилий.
#203 #759725
>>759720

>При выполнении задания покажите всё, на что вы способны, как разработчик. Мы будем оценивать все аспекты решения


>Мы будем использовать все аспекты решения

>>761956
100 Кб, 1280x719
35 Кб, 625x471
#204 #759740
Установил Yii2, смотрю слив курса по нему, там изначально разделение есть на папки backend, frontend, console (первый скрин).
Но у меня их нет!
Что я сделал не так?
У меня вот второй скрин.
>>759753
#205 #759753
>>759740
Откуда вы лезете? Зачем вам Yii, если не осиливаете прочитать первую страницу документации?
>>759760>>759762
32 Кб, 600x396
#206 #759760
>>759753
А де там на первой странице документации об этом?
>>759835
#207 #759762
>>759753
А что нам брать?
>>759835
92 Кб, 1232x468
61 Кб, 1111x662
80 Кб, 1020x623
#208 #759835
>>759760
Пикрил.

>>759762
Чистый PHP. И обзаводиться фундаментальными для программиста умениями: искать в документации и гугле, а не бежать отписываться в тред на каждый чих.
>>760095
#209 #759840
Есть такой дистрибутив линукса - Arch. Известен тем, что не имеет графического инсталлятора, устанавливать его нужно вручную, сидя в большой чёрной консоли, что очень многих отпугивает, хотя на деле всё оказывается просто и понятно после ознакомления с Arch Wiki. Так вот, есть предположение, что инсталлятор выпилили для сокращения количества глупых вопросов на форуме. Предоставив взамен обширную доходчивую документацию, которую люди используют, даже сидя на других дистрибутивах.

Из основных принципов Arch Way:

>"Read The Fucking (or Fine) Manual". This simple message is replied to a lot of new Linux/Arch users who ask about the functionality of a program when it is clearly defined in the program's manual.



>Whereas many GNU/Linux distributions attempt to be more user-friendly, Arch Linux has always been, and shall always remain user-centric. The distribution is intended to fill the needs of those contributing to it, rather than trying to appeal to as many users as possible. It is targeted at the proficient GNU/Linux user, or anyone with a do-it-yourself attitude who is willing to read the documentation, and solve their own problems.



Проблема в том, что легкая помощь становится своего рода наркотиком. Человек, получивший помощь, начинает полагать, что проще задать вопрос, чем поискать самому. И в случае возникновения проблемы в следующий раз, он опять обратиться за помощью, даже если ответ на его вопрос лежит на первых страницах гугла/документации. Только вот человек не задаётся вопросами "Почему они знают то, что знают? Тоже спрашивают кого-то на форумах и смотрят видеоуроки? Почему я этого не знаю и что стоит изменить в моём подходе получения знаний?".
>>759955>>760028
#210 #759878
аноны, работавшие с yii такой к вам вопрос: Можно ли как-то проверить url на то выбросит ли он ошибку или нет?
>>761956
#211 #759896
>>759692
https://gist.github.com/wannabearockstar/9bc790d3b5be4635b1c4
Вот это просто пушка, два дня делать такой круд с всякими дополнениями типа json-апи, только чтобы тебе на собеседовании сказали ВЫ НАМ НЕ ПОДХОДИТЕ. Причем задание это на уровне джуниора, просто какой-то странно большой объем работы для обычного тестового задания.
7 Кб, 267x181
#212 #759899
>>759896

>два дня делать такой круд с всякими дополнениями типа json-апи, только чтобы тебе на собеседовании сказали ВЫ НАМ НЕ ПОДХОДИТЕ.

14 Кб, 665x138
#213 #759908
>>759896
А с чего ты взял, что на джуниора? И не знаю, как на Symfony, но Laravel вполне реально подобный проект за пару дней сделать, даже зная только основы фреймворка.
#214 #759920
Анон, накидай вопросов, которые тебе задавали на собеседовании. Вот моиl:

1) Try/catch, как ловить, как написать свою ошибку, как идёт вверх по стеку, если не поймана в одном месте;
2) Приведение типов при сравнении, сложении, конкатенации, отличие ==/===;
3) Отличие or/and от || / $$ в таких местах: if(func1() or func2()) { ... }
4) Магические методы;
5) Традиционно много вопросов по БД и немного по паттернам.

Добавляйте.
114 Кб, 1280x716
#215 #759922
http://archive-ipq-co.narod.ru/l1/regexp.html
В уроке по регулярным выражениям есть задача «Grammar Nazi». Там есть пункт:

>В случае обнаружения ошибки скрипт должен писать сообщение об этом и выводить кусок текста с ошибкой (чтобы было понятно, что не так).


В каких границах выводить "кусок текста с ошибкой"?

https://ideone.com/KmCYnU
На данный момент я реализовал это выводом 10 символов, следующих за шаблоном.

Хочется сделать вывод не обрывая слова, несколько слов перед и после. Это сложно реализовать?
>>759926
#216 #759926
>>759922

>Хочется сделать вывод не обрывая слова, несколько слов перед и после. Это сложно реализовать?



Нет, погугли "word boundary regex".

>>759920
Блин, а на кого такие требования? Это совсем entry-level. Им, по-видимому, нужен человек для ковыряния CMS, потому что для тех, кто будет писать на фреймворках требования по знаниям в разы выше. Проходил через подобное, потом неделю разгребал джумлу и ушёл, не выдержав.
>>759935
#217 #759934
>>759920
Самое простое - просили перечислить все типы данных в PHP, рассказать про типизацию, и подобное.
Так же спрашивали в чем разница между $this и self, что такое конструктор и деструктор, иногда просили привести пример, преинкремент и постинкремент - в чем между ними разница, разница между двойными и одинарными кавычками, и еще много вопросов по основам, я уже не вспомню их все.
Так же давали немного коротких задачек, самая знаменитая и легкая - задача на переворот строки без использования функции strrev. Иногда задачу усложняли - просили перевернуть строку без создания новой строки. Еще один раз мне дали задачу на проверку номера телефона, она была похожа на ту, что в учебнике ОПа.
>>759936
#218 #759935
>>759926

> Им, по-видимому, нужен человек для ковыряния CMS


В итоге так и оказывалось. Внеси свои пять копеек, что будут спрашивать на мидла?
#219 #759936
>>759934

> Иногда задачу усложняли - просили перевернуть строку без создания новой строки.


Это же хардкор если массивы нельзя использовать. В utf-8 разные символы могут кодироваться разным числом байт.
>>759937>>759938
#220 #759937
>>759936
берешь последнюю букву и пишешь в начало
>>761956
#221 #759938
>>759936

>просили перевернуть строку без создания новой строки.


>массивы нельзя использовать.



Так не массивы а строку же. Решается так же, как и задача из учебника ОПа на палиндром.
41 Кб, 650x390
#222 #759940
>>759920
Спросили что такое mvc, какие sql команды я знаю и попросили написать на листочке цикл, который выводит числа делящиеся на 3 и 5. Потом допытывали что делает использованный мной оператор % и из какого он языка, лол.
Битрикс-макак
>>759944>>761956
#223 #759944
>>759940

>Битрикс-макак


Норм получаешь? У меня порой бывают мысли забить хуй на все новомодные фреймворки и вообще хабрамирок, устроится на битрикс и интегрировать его в рогах и копытах с 1с-складом.
>>760063
#224 #759955
>>759840
Социоблядям чисто эстетически приятнее спросить у живого человека, чем читать нудную херню на 1000 страниц, надрыстанную каким-то поехавшим задротом.

Ну и лень не нужно забывать: если мне нужно прописать одну строчечку, то я лучше спрошу на stackoverflow или еще где, чем буду перечитывать гигантский мануал.
>>759965>>761956
#225 #759965
>>759955
Ты утрируешь или я не понял шутки. Вопросы уровня "Чому composer не робит" свидетельствуют лишь о том, что человек слепо и без капли понимания копипастит команды или повторяет за тем, что пишут в видеоуроках, не утруждая себя пониманием того, как хотя бы примерно там всё работает. Нет элементарной базы вроде абсолютных/относительных путей в ФС и так далее. Или пишу на фреймворке, но не открывал ни единой страницы документации, это же вообще пушка.
>>760001
#226 #759975
>>759896
Это квест на мидла.
И совсем не обязательно делать его полностью, просто тебе предложат меньшую зарплату если что-то конкретное не получится.

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

>Для книги и жанра реализовать механизм ЧПУ - URL показа соответствующей сущности не должен содержать в себе числовой идентификатор сущности, вместо этого - уникальное транслитирированное имя


Это не знаю как сделать, но наверняка есть какой-нибудь бандл под эти цели.

В общем, вполне адекватное задание на миддла с з.п. около 70 тысяч. Если сделать не до конца, то скорее всего возьмут, но на джуна с 1,5-2 раза меньшей зарплатой, вот и все.
Хотя конечно если в вакансии написано "мы йоба-важная компания, даем вам, ничтожествам, поучаствовать в конкурсе, ответ получат только избранные после выполнения тестового", тогда лучше не тратить время.
>>761956
#227 #760001
>>759965
Такие на всю жизнь остаются джунами в дно-конторах, смысл о них говорить?

И ты слишком узко мыслишь, ситуации бывают разные.
Тот вопрос по установке yii, после которого ты завелся, задал вообще не программист.
Этот чувак как он о себе рассказывал работает сеошником и редактором в проекте книжного издательства.
Пытается во фреймворк и школьные задачи по php, чтобы не так часто наебывали фрилансеры, у которых иногда заказывает для себя.
И просто пообщаться с "братишками" в треде.

Еще английский и другие иностранные языки многим даются с трудом или вообще не даются.
Если говорить объективно, во всем виновата наша система образования.
На западе чуть ли не с детского сада детям помогают определиться с профессией, что им больше всего нравится, внушают важность учебы.
А что у нас? "Отмотай срок в вузике, тебе потом дадут диплом и сразу с ним работу и хорошую зарплату". А вот нихуя, сейчас ценятся только профессионалы
и преданные своему делу люди, по-крайней мере в айти. Это спрос.
Предложение: вованы, которые на бе услышали влажные мечты студентиков-первокурсников о космических зарплатах программистов, и решившие "вкатиться".

Думаю, стране нужна программа по айти образованию, например повысить еще плату за обучение (хотя она вроде и так не маленькая), и выделить 10% бюджетных мест для олимпиадников-гиков, повернутых на этом деле. Пусть богатые мажоры оплачивают себе корочку, которой потом подотрутся, а талантливые люди получат качественное образование.
Хотя встает вопрос, где брать хороших преподавателей?
>>760075
#228 #760028
>>759840

>Только вот человек не задаётся вопросами "Почему они знают то, что знают?


Потому что задроты без личной жизни.
Задам-ка я вопрос на форуме, и пойду играть дотку, завтра вернусь, проскроллю кукареканье о гугле и многотомных манах, и наверняка найду АДЕКВАТНЫЙ ответ на мой вопрос, выделю мышкой ответ, нажму контроле цэ, потом открою свой божественный нотепад плюс плюс, контрол вэ, и у меня все получиТЬСЯ)))) Посмеиваясь над лохами, годами пердолящими маны, получаю свои 30 тыщ, нихуя не делая.

Примерно так это работает.
>>760076
#229 #760063
>>759944
Взвоешь через два месяца.
#230 #760075
>>760001

>>Еще английский и другие иностранные языки многим даются с трудом


Если человеку даётся с трудом английский, то любой язык программирования ему не дастся вообще. Без английского в индустрии делать нечего, сейчас дела чуть лучше, чем было лет 5 назад, но тем не менее.
#231 #760076
>>760028

>>и пойду играть дотку


сказал не-задрот с личной жизнью.

Вы ударились в какую-то философию. Если у человака стоит задача "сделать вчера", у него в данный конкретный момент нет времени разрывать 1000 страничный мануал. Он спросит на стековерфлоу или в ирк канале, получит ответ (не всегда, но часто), и сделает работу.
>>760089
#232 #760079
>>759896

>только чтобы тебе на собеседовании сказали ВЫ НАМ НЕ ПОДХОДИТЕ


>НО НАМ ПОДХОДИТ ВАШЕ ВЫПОЛНЕННОЕ ЗАДАНИЕ

>>760089
#233 #760089
>>760076
Я приблизительно это и имел ввиду.
Тащемта дотка насколько я слышал очень социальна, все с микрофонами, можно знакомиться с телачками))

>>760079
Ты не можешь отличить рабочий проект от демонстрационного хелловорлда?
Хотя да, бывает и такое, что под видом тестового дно-конторы подсовывают свои текущие таски.
Но это же легко задетектить, хотя оказывается не для всех.
#234 #760095
>>759835
Спасибо!
Я так и подумал, что в этом разница в папках.

>не бежать отписываться в тред на каждый чих.


У нас же тут своя атмосфера, братишка, подобные вопросы я сам на будущее всегда читаю (хотя я всё полностью читаю в тредах, даже длинные посты ОПа, адресованные другим). Что-то лучше закрепляется в памяти.
Что-то, кстати, уже пару месяцев не было молодой крови - не появлялись кучи постов с просьбами подсказать решение задачи про Айфон и Айпад.
#235 #760200
ОПчик, что ты думаешь, по поводу абзаца "Обработка исключений"
http://phpfaq.ru/pdo
>>760205
#236 #760205
>>760200

по моему там написано то же самое что я всегда говорю. У меня есть урок по исключениям: https://github.com/codedokode/pasta/blob/master/php/exceptions.md

catch + die пиушт просто для примера чтобы показать что исключение можно поймать, а люди бездумно копируют этот код в реальные приложения.
#237 #760334
$rows = $this->db->prepare("SELECT * FROM `students` LIMIT :y OFFSET :x ORDER BY :sort :order");

Не работает, потому что вместо ORDER BY name DESC вставляет ORDER BY 'name' 'DESC'

Что делать? Может query builder использовать? И если да, то какой?
>>760341>>760416
#238 #760341
>>760334

>Что делать?



Использовать prepared statements только там, где нужно. Попробуй поменять ORDER BY :sort на ORDER BY {$sort}, и из параметров execute убери $sort.
#239 #760416
>>760334

С помощью плейсхолдеров можно подставлять только значения (числа и строки) но нельзя подставлять идентификаторы (названия) полей и таблиц. Названия полей придется вставлять напрямую в запрос, при этом проверяя их по белому списку разрешенных полей.
#241 #760531
>>759920

>1) Try/catch, как ловить, как написать свою ошибку, как идёт вверх по стеку, если не поймана в одном месте;


>2) Приведение типов при сравнении, сложении, конкатенации, отличие ==/===;


>3) Отличие or/and от || / $$ в таких местах: if(func1() or func2()) { ... }


>4) Магические методы;


Я читал про все это 2 раза, но все забыл. Когда использовал - смотрел в документацию. Это нормально? Сколько раз вы повторяете для запоминания? Сколько километров кода надо написать чтобы запомнить такие простые вещи?
>>760597>>760598
#242 #760597
>>760531
я глубоко убеждён, что надо не запоминать всё подряд, а запоминать где посмотреть всё, что нужно в данный момент.
Иначе можно просто поехать.
>>760598
#243 #760598
>>760531

>>760597
другое дело, что паста, которую ты отцитировал, должна быть у уме постольку, поскольку это как бе совсем алфавит практически.
>>760675
#244 #760675
>>760598
Ну я только только пытаюсь все осмыслить чтобы в терминах не путаться. Веб огромный. PHP тоже не маленький. Такое ощущение что я книгу в голове пишу. Я сейчас стал понимать авторов книг. У них столько знаний что они без запинаний могут главы книг писать. В каждом предложении по несколько посылов. Все посылы связаны между собой. Вот сижу сейчас читаю официальную документацию PHP. Там 26 разделов в справочнике функций, 19 разделов в справочнике языка. В каждом разделе по несколько подразделов. Никто мне не говорит что вот эта штука в 100 раз нужнее той штуки, приходится равномерно все читать. Причем задача горит, делать надо быстрее, нет времени вчитываться в слова и обдумывать их. А ведь если вчитаться в слова, то мы попадем в вики, математику, информатику, историю и т.д. И это только PHP, а ведь еще веб надо учить. Тысячи их.
#245 #760684
>>760675
И еще добавлю. Вот то что ты знал, анон, еще 5-10 лет назад, я только вчера прочитал например. А если мысль архиважная? Ты прожил 5 лет и у тебя знания поверх этой мысли накладывались как надо, а у меня бардак из мыслей только вчера начал утихать. Я от мыслей так устал, что отгоняю их, потому как считаю бесполезными. Все равно рассуждение стройное не получается построить хотя бы из нескольких связанных предложений. Куча обрывков, вспышки памяти, стресс и угнетение от мыслей что я неосилятор и быть мне хелловордщиком всю жизнь и не дойти до уровня макаки. А я ведь самоучка, учился урывками в свободное время между работой на стройке и получением вышки. Вот сейчас повезло, устроился сайты на цмсках клепать, время появилось свободное чтобы за пёкой сидеть. Жалею что раньше не мог набраться смелости, лет 5-6 упустил. Ребята молодые рядом сидят, разбираются больше чем я в некоторых вопросах, но профессию не уважают - злоба берет от них.
#246 #760688
>>760675

> Вот сижу сейчас читаю официальную документацию PHP. Там 26 разделов в справочнике функций, 19 разделов в справочнике языка. В каждом разделе по несколько подразделов. Никто мне не говорит что вот эта штука в 100 раз нужнее той штуки, приходится равномерно все читать.


Поздравляю, ты познал всю говенность библиотеки PHP.
>>760742
#247 #760703
Аноны, немного флейма, но надеюсь не погоните.
Уволился с работы прошлой, есть 1-2 месяца, чтоб выучить php, чтобы устроится на 35к в ДС.
Не буду спрашивать, реально ли это, т.к. надеюсь на лучшее. Так вот, к сути. Учил кто-либо из ва успешно по 8-12 часов в день? ПОнимаю ,что все субъективно, но просто интересно.
Есть еще всякие ноотропы, но планирую ограничиться 3-4 кружками кофе.
>>760729>>760748
80 Кб, 960x409
#248 #760729
>>760703

>есть 1-2 месяца, чтоб выучить php


Тут нужно особое десантное подразделение.
#249 #760742
>>760688
Я считаю что документация PHP очень понятна и может выступать как образец документации по ЯП. Говеность библиотеки? Почему?
>>761951>>761956
#250 #760748
>>760703

>успешно по 8-12 часов в день


Максимум 6, в идеале вообще 4. Остальное время подтягивай английский, листай документацию, курсы на ютубчике смотри и хорошо высыпайся. Вообще держи себя в тонусе. Не надо себя истязать, ты выгоришь через неделю и получится только хуже.
>>760751>>760758
#251 #760751
>>760748
А в какой срок можно, по-твоему уложиться, чтобы начать что-то зарабатывать? Немного платина, да.
>>760754>>760770
#252 #760754
>>760751
Зависит от того что уже знаешь, я бы смотрел на год - полтора.
мимо другой анон
>>760756
#253 #760756
>>760754
Блядство.

Спасибо.
#254 #760758
>>760748

>Максимум 6, в идеале вообще 4.


Лел, 99% вакансий пхп-макаки имеет график с 9 до 18, то есть 8 часов, учитывая обед.
>>760770
#255 #760770
>>760758
До обеда очень продуктивно работаю, потом в пол силы ковыряю, совсем сложное оставляя на завтра. Может я дефектный, хз.
>>760751
Я около месяца просиживал на learn.javascript.ru, дошел до прототипов и устроился стажером за бесплатно в вебстудию. Там в течении полугода вкачивался до среднестатистической макаки.
#256 #760796
>>760770
Хм, вот я надеялся на что-то такое: за месяц-два доучиться до уровня макаки ебаной.
>>760835
#257 #760835
>>760796
Ты зря так к макакам относишься, малыш. Макака - это вполне сносный программист, которого держать можно. Просто ему может не хватать опыта, базы и IQ.
Хелловордщик - это копипастер обычный.
За 1-2 месяца ты даже до азов хелловорда не дойдешь.
>>760770

>течении полугода вкачивался до среднестатистической макаки.


Очень сомневаюсь. До хелловордщиков вкачался наверное?
#258 #760836
>>760835

>За 1-2 месяца ты даже до азов хелловорда не дойдешь.


Да вы что блять стебетесь? На уровне жуниора сложности только с ООП у более-менее умного анона должны возникать. Вы таким образом хотите отпугнуть потенциальных конкурентов?
#259 #760840
>>760836
130IQ, учу пых 7 месяцев. Уровень начинающего хелловордщика. До ООП как до луны пешком. Задавай свои ответы.
>>760868>>761951
#260 #760852
>>760835

>>За 1-2 месяца ты даже до азов хелловорда не дойдешь.


я не оч понимаю, что ты вкладываешь в поянтие "азы хеллоуворлда".

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

А абстрактную задачу мало кто в состоянии себе приудмать сам. Поэому ОПу респект.
>>760855
#261 #760855
>>760852

>что ты вкладываешь в поянтие "азы хеллоуворлда"


Неуверенное владение синтаксисом, парадигмой, основными алгоритмами. Стадия изучения основ инструментария. До решения практических задач без дедлайнов знаний не хватает.

>заставляя нубюов решать задачи


Да тут не такие уж и нубы сидят так то. Я, например, привык к компилируемой статике. Для меня модель исполнения и динамика в новизну были. ООП не проходил по-человечески, хотя могу функциональное GUI приложение с ООП на С++ и Delphi написать. Ассемблер дрочил, алгоритмы, ОСы, сети, архитектуру, CS. Веб в новинку, в вебе все не так, в вебе все динамично, быстро, разбросанно.

>А абстрактную задачу мало кто в состоянии себе приудмать сам.


Да легко. По 10 штук за день. Только техзадание надо уметь писать и в разумное время укладывать как ОП. У ОПа опыт владения русским языком и стеком, ОП примерно знает что сколько времени займет.
>>760865>>761951
#262 #760864
ОПчик, поясни ты, ради Иисуса нашего Христа, вот паттерн
Table Gateway.

Пишем класс - соотв. таблице БД. Свойства - поля таблицы, методы - допустим, КРУД. Данные подаются через аргументы методов.

Чем это вот всё будет отличаться от подклбчаемого реквайром файла mytable.php со списком функций КРУДа? Без ООП?

Я, не подумай, не выступаю против ООП. Я просто хочу понять, ЧЕМ ооп лучше процедурного стиля.
#263 #760865
>>760855
чо ты гонишь, если ты на плюсах писал, ты ПХП не осилишь чтоль? Бро, ну ты ваще.
>>760867
#264 #760867
>>760865
Осиливаю со скрипом. Знаешь как блевать и дропнуть хочется? Питоню и скалаёбю для отдыха от пыха. Небо и земля.
>>760882
#265 #760868
>>760836
>>760840
Так ебать, за два месяца получится задрочить?
>>760875
105 Кб, 942x533
66 Кб, 649x487
91 Кб, 609x608
#266 #760870
>>760835

>Очень сомневаюсь. До хелловордщиков вкачался наверное?


Функциональное программирование, знание кмски и командная разработка в общем - миграции, контроль версий. Примерно тогда прошла паника при новых тикетах и мог браться за практически любую поступающую в отдел задачу. Для справки, на пике вакансии на ту самую среднестатистическую макаку, чтоб ты понимал о чем сейчас идет речь.
>>760873
#267 #760872
>>760864
Читабельнее.
>>760894
#268 #760873
>>760870

>знание кмски и командная разработка в общем - миграции, контроль версий.


Пффф

>Функциональное программирование


Колбеки - это малая часть функциональщины.

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


Для макаки список требований. Ты каким образом в эту сферу проник? Полгода на полный стек (да даже на 25% от JS)? Не верю.
40 Кб, 960x409
#269 #760875
>>760868
Тут нужно особое десантное подразделение.


https://www.livecoding.tv/livestreams/php/
Иди лучше кинца наверни, потом приходи.
#270 #760881
https://geekbrains.ru/courses/65
Наткнулся на этот курс. Что скажете о нем?
>>760885
#271 #760882
>>760867

>Питоню


Так на кой тебе РНР тогда?
>>760891
20 Кб, 400x362
#272 #760885
>>760881
Ни в коем случае!
Я там как Александров отписывался пару месяцев назад.
Сказать, что это плохо - ничего не сказать.
Это просто отвратительно.
Человек путает всё на свете, копипастит код, при этом путает сами файлы - был один код в этом файл - хоп, он вставляет другой.
Не наглядно, бестолково, не для новичков.
Выше есть слитый курс про Yii2 - он платный был. Такое же всё поверхностное, непонятное.
Капитальные стандарты преподавания не соблюдаются.
Не рекомендую Гикбрейнс вообще, короче.
>>760888
#273 #760888
>>760885
Ну я скептично отношусь к платному, но тут увидел, что беплатно и решил, что возможно годно.
Я понял тебя.
Буду читать шапку.
>>760895
#274 #760891
>>760882
1. ОП этого треда - хороший человек
2. Язык выбрал меня
>>760895>>760896
#275 #760894
>>760872
И всё? И ВСЁ?
>>760928
#276 #760895
>>760888
К сожалению, нет.
От себя рекомендую учебник ОПа и книгу Робина Никсона "Создаем динамические веб-сайты с помощью PHP, MySQL и JavaScript" (первая ссылка в Гугле на PDF в ВКонтакте).
Там самая выжимка, поэтому учебник ОПа должен быть к этому времени полностью проработан, все основные понятия должны быть уяснены.
В конце там проект без шаблона, но дающий базовые представления о всех основных технологиях веба. К тому времени ты и сам будешь понимать, что там может быть улучшено.

>>760891
Согласен с обоими пунктами.
>>760900
#277 #760896
>>760891
Хехе. Я тебя понимаю. Я вообще обожаю перл и невроятно клёвый фреймврк Mojolicious, а ПХП занимаюсь по работе главным образом, да и то, думаю, плюну и перепишу перле на Mojo.

Но в наше время ПХП надо знать. Просто хотя бы для того чтобы разбираться в чужом коде.
без питона-то, кстати, можно обойтись
>>760918
#278 #760900
>>760895
Как человек, который читал Никсона до того, как наткнулся на учебник ОПа - не рекомендую. По крайней мере не в том порядке, в котором ты советуешь. После учебника ОПа книжка никсона мало в чем может тебя просветить. Да, у ОПа нет ничего по основам БД или там по серверной части, вроде пост запросов и форм и тому подобного, но к моменту как ты его пройдешь, искать такие вещи проще в интернете, чем читать устаревшую книгу.
>>760903
#279 #760903
>>760900
Там для закрепления основных понятий - отлично.
Для перехода к базам данных, для создания динамики.
Я советую его только для закрепления того, что есть у ОПа.
#280 #760918
>>760896

>без питона-то, кстати, можно обойтись


Питон и Скала как разминка для глаз идет. Скала выносит мозг хорошо, питон и руби олицетворяют скрипты.
#281 #760926
https://www.livecoding.tv/cybarian/videos/REo1q-chat-system-pakistan-freelancers-2
Пакистанец стримит. Обкуренный походу, поет. Пьет воду так что кажется что это последняя вода в его жизни и он работает фрилансером только чтобы хотя бы заработать на эту воду.
#282 #760928
>>760894
Нет, не всё. На ООП можно применить множество решений, паттернов - процедурно уже никто не программирует. Поэтому я и привел первым аргументом именно читабельность, потому что понятный код, это наше альфа и омега.
>>760934
#283 #760934
>>760928
К тому же ООП лучше подходит в плане проектирования.
63 Кб, 799x507
#284 #760983
Почему такая непоследовательность?
MVC
Почему не MCV?
Ведь надо идти последовательно: модель -> контроллер -> вид.
>>760986
#285 #760986
>>760983
а еще правильнее CMCV
>>760991
32 Кб, 600x396
#286 #760991
>>760986
Вы хотите сказать, FCMCV?
51 Кб, 604x307
#287 #760999
Никогда не используйте NULL!
Иначе NULL использует вас!
http://ahrameev.ru/article/nikogda-ne-ispolzujjte-null.html
>>761165>>761944
#288 #761025
Собрался написать для друзяшек страничку, где будут располагаться различные таймеры каких-то событий ИРЛ. Видеть могут все, а редакторовать могут избранные. Помогите подобрать инструменты для этого, чтобы не с нуля все писать. Я так понимаю, что мне нужен бутстрап чтобы выглядело норм, jQuery чтобы реализовать таймеры и их формочки? И как правильно реализовать проверку ключа, который я раздам избранным? Как его хранить? Неужели заводить БД для этого, под один ключ?
>>773830
https://github.com/foobar1643/filehosting/ #289 #761042

>>747423


>>755118

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

В странице ошибки нет тега meta charset и вместо русских букв выводится абракадабра.

В sphinx.conf неправильно указаны пути к файлам с индексами - ну кто кладет индексы в /etc? Он для конфигов, а для таких вещей есть /var/lib/sphinx например. Но я бы тебе советовал сделать еще гибче и сделать, чтобы префикс для всех путей сфинкса задавался бы через переменную окружения, например SPHINX_ROOT. То есть мы задаем SPHINX_ROOT=/home/ivan/sphinx и все индексы, логи пиушутся туда.А если она не задана - то например в общесистемные папки. Это позволяет не использовать общесистемный сфинкс, а завести для проекта отдельный демон.

Чтобы это реалилизовать, тебе надо использовать фичу сфинкса которая позволяет делать конфиг на скриптовом языке, например php: http://sphinxsearch.com/blog/2013/11/05/sphinx-configuration-features-and-tricks/

Сам поиск у меня падает с сообщением 'exception 'ErrorException' with message 'PDO::__construct(): Server sent charset (0) unknown to the client. Please, report to the developers'

Для того, чтобы при большом числе файлов эффективно работал поиск последних/популярных, нужны индексы по соотв. колонкам. Нужны индексы для эффективной выборки комментариев. Прочитай для начала ознакомительный урок http://ruhighload.com/post/Работа+с+индексами+в+MySQL

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

В комментариях при отпраке аяксом содержится XSS. Попробуй добавить например комментарий Hello <s>world</div></div></div>

Переводы строк теряются в комментариях.

Формат дат в комментарии - американский и чуждый русскоязычному интерфейсу сайта.

"1 скачиваний" - что это за насмешка над правилами русского языка? Ты же делал задачу про числа прописью? Кроме варианта писать функцию склонения руками, есть еще вариант раскурить расширение Intl: http://php.net/manual/ru/book.intl.php

Оно скопировано с Явы и там есть функция, которая позволяет делать в строку подстановки с учетом правил языка. Например: http://php.net/manual/ru/messageformatter.formatmessage.php

> echo MessageFormatter::formatMessage("en_US", "{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree\n", array(4560, 123, 4560/123));


> $fmt = new MessageFormatter("en_US", "{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree");


> echo $fmt->format(array(4560, 123, 4560/123));



Предлагаю тебе раскурить документацию, если знаешь английский, и перевести все сообщения на использование этого замечательного объекта. Дополнительно, если есть желание и время, можешь сделать 2- (или более)-язычную версию сайта. Никаких велосипедов - использовать надо Intl и gettext. Для gettext есть готовые редакторы переводов, например, poedit. Уверен, знание основ локализации будет хорошо смотреться в твоем резюме. Страницы с разным языком должны отличаться в URL. Пользователь должен иметь возмодность переключить язык. Если пользователь зашел на сайт впервые, мы определяем его язык (по IP страны или заголовкам от браузера) и если он не совпадает с текущим, выводим вежливое скромное напоминание, что сайт доступен на родном языке. Если он игнорирует его, перестаем спамить на какое-то время.

> 'displayErrorDetails' => true,


Я думаю это можно брать из значения display_errors

> set_error_handler(function ($errno, $errstr, $errfile, $errline)


> {


> if (!(error_reporting() & $errno)) {


Разве Слим этого не делает?

Создание контейнера наверно тоже стоило вынести в app/init.php. Идея бутстрап файла в том, что мы подключаем один файл и получаем рабочее окружение.

CsrfGuard на мой взгляд мутный, хоть он и сделан по рекомендациям OWASP. Требует сессий. На каждый запрос генерирует токены, даже если они потом не используются.

Особо коварный момент: сессии умирают за 30 минут неиспользоания. Если пользователь откроет форму, оставит на 30 минут и попробует отправить, то получит страницу ошибки, и потеряет введенные данные.

Есть и плюсы: например благодаря одноразовым токенам не получится повторно отправить запрос с теми же данными. Хотя это может быть и недостатком: у пользователя плохая связь, не получил ответа на форму, отправил форму повторно и потерял данные.

Не хочешь сделать по мотивам этого более простой гвард на куках, с фичами:

- произвольный срок жизни куки

https://github.com/foobar1643/filehosting/blob/master/templates/file.twig#L22

> {% if file.getAuthToken == authToken %}


Вот тут ты в шаблон вынес логику проверки прав доступа. Должен быть где-то метод, вроде $someHelper->canManageFile($user, $file) или $someHelper->canManageFile($file).

https://github.com/foobar1643/filehosting/blob/master/app/Helper/IdHelper.php
Этот объект реализован неправильно на мой взгляд. Ты его сделал сервисом, то есть он существует в одном экземпляре. Но внутри он хранит информацию о каком-то конкретном файле. Это значит, что в некоторые моменты времени в нем нет этой информации и ни в какой момент времени в нем нелзя хранить информацию о нескольких файлах. То есть в одном месте кода мы засовываем туда файл, и в другом месте кода что-то ломается.

Это не может быть сервис. У сервиса не должно быть такого непредсказуемого состояния. Это должен быть класс-"сущность", который создается в нужном числе экземпляров, по одному на каждый файл.

Также, у этого класса есть недостаток. В промежуток между созданием и вызовом analyzeFile его состояние пусто. Из-за этого ты городишь везде нелепые isset. Лучше отказаться от пустого состояния и передавать файл в конструктор. Код упростится (если конечно у тебя нет цели поддерживать сценарий, когда файл отстутсвует).

https://github.com/foobar1643/filehosting/blob/master/app/Controller/FileController.php#L25

> if($file == false) {


> throw new \Slim\Exception\NotFoundException($request, $response);


> } else {


> много строк


> }


В такой ситуации блок else только ухудшает читаьельность кода лишним отступом, он не нужен. Везде где в if в итоге стоит выход из функции (return/die/throw) - else не нужен.

https://github.com/foobar1643/filehosting/blob/master/app/Controller/FileController.php#L39

> 'commentErrors' => isset($args['commentErrors']) ? $args['commentErrors'] : NULL



Вот тут немного мутный момент. Ты не рассмтривал вариант сделать обработку постинга комментария в том же контроллере что выводит страницу файла, по стандартному алгоритму обработки форм? При этом ты точно так же мог бы вынести код в CommentController (или просто в отдельный метод), только тут FileController будет вызывать CommentController, а не наоборот. не лучше ли такой вариант?
https://github.com/foobar1643/filehosting/ #289 #761042

>>747423


>>755118

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

В странице ошибки нет тега meta charset и вместо русских букв выводится абракадабра.

В sphinx.conf неправильно указаны пути к файлам с индексами - ну кто кладет индексы в /etc? Он для конфигов, а для таких вещей есть /var/lib/sphinx например. Но я бы тебе советовал сделать еще гибче и сделать, чтобы префикс для всех путей сфинкса задавался бы через переменную окружения, например SPHINX_ROOT. То есть мы задаем SPHINX_ROOT=/home/ivan/sphinx и все индексы, логи пиушутся туда.А если она не задана - то например в общесистемные папки. Это позволяет не использовать общесистемный сфинкс, а завести для проекта отдельный демон.

Чтобы это реалилизовать, тебе надо использовать фичу сфинкса которая позволяет делать конфиг на скриптовом языке, например php: http://sphinxsearch.com/blog/2013/11/05/sphinx-configuration-features-and-tricks/

Сам поиск у меня падает с сообщением 'exception 'ErrorException' with message 'PDO::__construct(): Server sent charset (0) unknown to the client. Please, report to the developers'

Для того, чтобы при большом числе файлов эффективно работал поиск последних/популярных, нужны индексы по соотв. колонкам. Нужны индексы для эффективной выборки комментариев. Прочитай для начала ознакомительный урок http://ruhighload.com/post/Работа+с+индексами+в+MySQL

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

В комментариях при отпраке аяксом содержится XSS. Попробуй добавить например комментарий Hello <s>world</div></div></div>

Переводы строк теряются в комментариях.

Формат дат в комментарии - американский и чуждый русскоязычному интерфейсу сайта.

"1 скачиваний" - что это за насмешка над правилами русского языка? Ты же делал задачу про числа прописью? Кроме варианта писать функцию склонения руками, есть еще вариант раскурить расширение Intl: http://php.net/manual/ru/book.intl.php

Оно скопировано с Явы и там есть функция, которая позволяет делать в строку подстановки с учетом правил языка. Например: http://php.net/manual/ru/messageformatter.formatmessage.php

> echo MessageFormatter::formatMessage("en_US", "{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree\n", array(4560, 123, 4560/123));


> $fmt = new MessageFormatter("en_US", "{0,number,integer} monkeys on {1,number,integer} trees make {2,number} monkeys per tree");


> echo $fmt->format(array(4560, 123, 4560/123));



Предлагаю тебе раскурить документацию, если знаешь английский, и перевести все сообщения на использование этого замечательного объекта. Дополнительно, если есть желание и время, можешь сделать 2- (или более)-язычную версию сайта. Никаких велосипедов - использовать надо Intl и gettext. Для gettext есть готовые редакторы переводов, например, poedit. Уверен, знание основ локализации будет хорошо смотреться в твоем резюме. Страницы с разным языком должны отличаться в URL. Пользователь должен иметь возмодность переключить язык. Если пользователь зашел на сайт впервые, мы определяем его язык (по IP страны или заголовкам от браузера) и если он не совпадает с текущим, выводим вежливое скромное напоминание, что сайт доступен на родном языке. Если он игнорирует его, перестаем спамить на какое-то время.

> 'displayErrorDetails' => true,


Я думаю это можно брать из значения display_errors

> set_error_handler(function ($errno, $errstr, $errfile, $errline)


> {


> if (!(error_reporting() & $errno)) {


Разве Слим этого не делает?

Создание контейнера наверно тоже стоило вынести в app/init.php. Идея бутстрап файла в том, что мы подключаем один файл и получаем рабочее окружение.

CsrfGuard на мой взгляд мутный, хоть он и сделан по рекомендациям OWASP. Требует сессий. На каждый запрос генерирует токены, даже если они потом не используются.

Особо коварный момент: сессии умирают за 30 минут неиспользоания. Если пользователь откроет форму, оставит на 30 минут и попробует отправить, то получит страницу ошибки, и потеряет введенные данные.

Есть и плюсы: например благодаря одноразовым токенам не получится повторно отправить запрос с теми же данными. Хотя это может быть и недостатком: у пользователя плохая связь, не получил ответа на форму, отправил форму повторно и потерял данные.

Не хочешь сделать по мотивам этого более простой гвард на куках, с фичами:

- произвольный срок жизни куки

https://github.com/foobar1643/filehosting/blob/master/templates/file.twig#L22

> {% if file.getAuthToken == authToken %}


Вот тут ты в шаблон вынес логику проверки прав доступа. Должен быть где-то метод, вроде $someHelper->canManageFile($user, $file) или $someHelper->canManageFile($file).

https://github.com/foobar1643/filehosting/blob/master/app/Helper/IdHelper.php
Этот объект реализован неправильно на мой взгляд. Ты его сделал сервисом, то есть он существует в одном экземпляре. Но внутри он хранит информацию о каком-то конкретном файле. Это значит, что в некоторые моменты времени в нем нет этой информации и ни в какой момент времени в нем нелзя хранить информацию о нескольких файлах. То есть в одном месте кода мы засовываем туда файл, и в другом месте кода что-то ломается.

Это не может быть сервис. У сервиса не должно быть такого непредсказуемого состояния. Это должен быть класс-"сущность", который создается в нужном числе экземпляров, по одному на каждый файл.

Также, у этого класса есть недостаток. В промежуток между созданием и вызовом analyzeFile его состояние пусто. Из-за этого ты городишь везде нелепые isset. Лучше отказаться от пустого состояния и передавать файл в конструктор. Код упростится (если конечно у тебя нет цели поддерживать сценарий, когда файл отстутсвует).

https://github.com/foobar1643/filehosting/blob/master/app/Controller/FileController.php#L25

> if($file == false) {


> throw new \Slim\Exception\NotFoundException($request, $response);


> } else {


> много строк


> }


В такой ситуации блок else только ухудшает читаьельность кода лишним отступом, он не нужен. Везде где в if в итоге стоит выход из функции (return/die/throw) - else не нужен.

https://github.com/foobar1643/filehosting/blob/master/app/Controller/FileController.php#L39

> 'commentErrors' => isset($args['commentErrors']) ? $args['commentErrors'] : NULL



Вот тут немного мутный момент. Ты не рассмтривал вариант сделать обработку постинга комментария в том же контроллере что выводит страницу файла, по стандартному алгоритму обработки форм? При этом ты точно так же мог бы вынести код в CommentController (или просто в отдельный метод), только тут FileController будет вызывать CommentController, а не наоборот. не лучше ли такой вариант?
>>768780
https://github.com/foobar1643/filehosting/ #290 #761043

>>747423


>>755118

В валидаторе ты валидируешь массив: https://github.com/foobar1643/filehosting/blob/master/app/Validation/Validation.php#L34 А ведь можно валидировать модель комментария.

Это имеет такие преимущества:

- валидируем объект с полями и методами вместо бесформенного нетbпизированного массива. Не надо ставить кучу isset.
- мы можем провалидировать любой объект комменатрия, не обязательно пришедший из формы. код более универсальный и менее спутанный

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

А как ты считаешь, что лучше?

https://github.com/foobar1643/filehosting/blob/master/app/Controller/CommentController.php#L35

> if(isset($getVars['ajax']) && $getVars['ajax'] == "true") {


Опять массиво-ориентированное программирование. Там у request есть что-то вроде $r->getQuery()->get('ajax');

> print(json_encode($jsonResponse));


по моему это неправильно. Ты должен вписать это в тело ответа, а не выводить. То есть $response->withBody или как-то так.

Также, там по моему есть класс JsonResponse (или нет, только в сифмони?) ну или ты можешь сделать метод $this->sendJson чтобы не копипастить код.

> return $response->withHeader('Location', "/file/" . $args['id']);


тут еще можно прибавлять якорь с id комментария и с помощью CSS анимации и :target подсветить новый комментарий.

Далее, тут https://github.com/foobar1643/filehosting/blob/master/app/Controller/CommentController.php#L19 одна функция и в ней стена текста, плохо читаемая. Надо разбивать на части, например:

- функция отдачи json
- функция воссоздающая модель из POST данных
- функция, вызывающая вывод страницы файла

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

- взять стакан муки
- добавить в него 2 яйца

ты пишешь:

- подойти к шкафу
- открыть дверцу
- осмотреть верхнюю полку в поисках цилиндрического предмета с открытым верхом определенных габаритов
- переместить ладонь к предмету
....

Пройдись сам по другим контроллерами и посмотри, не надо ли разбить код там.

Вот как еще один пример тут:

https://github.com/foobar1643/filehosting/blob/master/app/Controller/DownloadController.php#L39

> if($config->getValue('app', 'enableXsendfile') == 1) {


Вместо низкоровневого кода должен быть вызов if (canUseSendfile()), более того, сам код отдачи файла стоит вынести в хелпер так как он может быть повторно использован где-то еще, и вообще выглядит как отдельная от данного контроллера вещь, а каждый класс, как мы помним, должен заниматься своим делом.

> readfile($filePath);


Там я думаю, есть метод стриминга ответа из файла - изучи-ка PSR, как можно задавать тело HTTP-ответа из файла.

То, что ты принтишь данные вместо того чтобы вставить их в ответ, это не очень соответствует идее фреймворка (что контроллер должен заполнить response), да и тестирование усложнит.

> $fileMapper = $this->container->get('FileMapper');


> $pathingHelper = $this->container->get('PathingHelper');


> $config = $this->container->get('config');


Можно чуть облагородить код если эту ерунду перенести в конструктор контроллера и сохранить сервисы в приватных полях. Хотя, код станет чуть длинее.

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

Вот в SearchController я вижу не очень хороший момент:

https://github.com/foobar1643/filehosting/blob/master/app/Controller/SearchController.php#L40

> $searchIds = $searchGateway->search($searchHelper->escapeString($query), self::RESULTS_PER_PAGE, $offset);


> $searchMeta = $searchGateway->showMeta(); // results count


Во-первых, тут в контроллер из поискового сервиса вытекает знание о формате ответа сфинкса (что он возвращает id и метаданные). Во-вторых, код поиска нельзя использовать повторно где-то еще.

Я думаю, нам нужен примерно такой метод:

search(query, offset, limit) -> ([File], totalCount)

То есть нам нужны сущности, а не их id, и число, а не какие-то метаданные.

https://github.com/foobar1643/filehosting/blob/master/templates/file.twig#L70

> <div class="media" id="comment-dummy" style="display: none;">


для шаблонов есть более интересные решения:

- https://learn.javascript.ru/templates
- https://learn.javascript.ru/template-tag

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

> replyForm.children(".form-group").removeClass("has-error");


> replyForm.children(".form-group").children(".real-label").remove();


> replyForm.children(".form-group").attr('id', "reply-form-group")



(хуже того, тут еще и копипаста выражения replyForm.children(".form-group"))

Лучше сделать например так:

<div class="comment-author">%author%</div>

Ты можешь сделать свою велосипедную систему или поискать готовый шаблонизатор тут: https://garann.github.io/template-chooser/

https://github.com/foobar1643/filehosting/blob/master/app/Database/CommentMapper.php#L21

> :file_id_bind",


Я думаю что можно было просто писать :file_id, bind добавлять не надо было. Ну добавил, ладно, пусть будет.

https://github.com/foobar1643/filehosting/blob/master/app/Helper/CommentHelper.php#L16

> public function addComment(Comment $comment)


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

Насчет выборк комментов - ты строишь дерево. А не проще ли делать плоскую структуру? Просто выбирать комменты ORDER BY path?

> $this->normalizePath("{$parentComment->getParentPath()}.{$comment->getId()}"))


Вот это лучше было бы вынести в метод appendToPath(oldPath, newId)

https://github.com/foobar1643/filehosting/blob/master/app/Helper/FileHelper.php#L20

> public function createFile(File $file, $adminFlag)


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

> $searchGateway->insertRtValue($file->getId(), $file->getName());


тут лучше высокоуровневый метод

indexNewFile($file)
https://github.com/foobar1643/filehosting/ #290 #761043

>>747423


>>755118

В валидаторе ты валидируешь массив: https://github.com/foobar1643/filehosting/blob/master/app/Validation/Validation.php#L34 А ведь можно валидировать модель комментария.

Это имеет такие преимущества:

- валидируем объект с полями и методами вместо бесформенного нетbпизированного массива. Не надо ставить кучу isset.
- мы можем провалидировать любой объект комменатрия, не обязательно пришедший из формы. код более универсальный и менее спутанный

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

А как ты считаешь, что лучше?

https://github.com/foobar1643/filehosting/blob/master/app/Controller/CommentController.php#L35

> if(isset($getVars['ajax']) && $getVars['ajax'] == "true") {


Опять массиво-ориентированное программирование. Там у request есть что-то вроде $r->getQuery()->get('ajax');

> print(json_encode($jsonResponse));


по моему это неправильно. Ты должен вписать это в тело ответа, а не выводить. То есть $response->withBody или как-то так.

Также, там по моему есть класс JsonResponse (или нет, только в сифмони?) ну или ты можешь сделать метод $this->sendJson чтобы не копипастить код.

> return $response->withHeader('Location', "/file/" . $args['id']);


тут еще можно прибавлять якорь с id комментария и с помощью CSS анимации и :target подсветить новый комментарий.

Далее, тут https://github.com/foobar1643/filehosting/blob/master/app/Controller/CommentController.php#L19 одна функция и в ней стена текста, плохо читаемая. Надо разбивать на части, например:

- функция отдачи json
- функция воссоздающая модель из POST данных
- функция, вызывающая вывод страницы файла

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

- взять стакан муки
- добавить в него 2 яйца

ты пишешь:

- подойти к шкафу
- открыть дверцу
- осмотреть верхнюю полку в поисках цилиндрического предмета с открытым верхом определенных габаритов
- переместить ладонь к предмету
....

Пройдись сам по другим контроллерами и посмотри, не надо ли разбить код там.

Вот как еще один пример тут:

https://github.com/foobar1643/filehosting/blob/master/app/Controller/DownloadController.php#L39

> if($config->getValue('app', 'enableXsendfile') == 1) {


Вместо низкоровневого кода должен быть вызов if (canUseSendfile()), более того, сам код отдачи файла стоит вынести в хелпер так как он может быть повторно использован где-то еще, и вообще выглядит как отдельная от данного контроллера вещь, а каждый класс, как мы помним, должен заниматься своим делом.

> readfile($filePath);


Там я думаю, есть метод стриминга ответа из файла - изучи-ка PSR, как можно задавать тело HTTP-ответа из файла.

То, что ты принтишь данные вместо того чтобы вставить их в ответ, это не очень соответствует идее фреймворка (что контроллер должен заполнить response), да и тестирование усложнит.

> $fileMapper = $this->container->get('FileMapper');


> $pathingHelper = $this->container->get('PathingHelper');


> $config = $this->container->get('config');


Можно чуть облагородить код если эту ерунду перенести в конструктор контроллера и сохранить сервисы в приватных полях. Хотя, код станет чуть длинее.

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

Вот в SearchController я вижу не очень хороший момент:

https://github.com/foobar1643/filehosting/blob/master/app/Controller/SearchController.php#L40

> $searchIds = $searchGateway->search($searchHelper->escapeString($query), self::RESULTS_PER_PAGE, $offset);


> $searchMeta = $searchGateway->showMeta(); // results count


Во-первых, тут в контроллер из поискового сервиса вытекает знание о формате ответа сфинкса (что он возвращает id и метаданные). Во-вторых, код поиска нельзя использовать повторно где-то еще.

Я думаю, нам нужен примерно такой метод:

search(query, offset, limit) -> ([File], totalCount)

То есть нам нужны сущности, а не их id, и число, а не какие-то метаданные.

https://github.com/foobar1643/filehosting/blob/master/templates/file.twig#L70

> <div class="media" id="comment-dummy" style="display: none;">


для шаблонов есть более интересные решения:

- https://learn.javascript.ru/templates
- https://learn.javascript.ru/template-tag

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

> replyForm.children(".form-group").removeClass("has-error");


> replyForm.children(".form-group").children(".real-label").remove();


> replyForm.children(".form-group").attr('id', "reply-form-group")



(хуже того, тут еще и копипаста выражения replyForm.children(".form-group"))

Лучше сделать например так:

<div class="comment-author">%author%</div>

Ты можешь сделать свою велосипедную систему или поискать готовый шаблонизатор тут: https://garann.github.io/template-chooser/

https://github.com/foobar1643/filehosting/blob/master/app/Database/CommentMapper.php#L21

> :file_id_bind",


Я думаю что можно было просто писать :file_id, bind добавлять не надо было. Ну добавил, ладно, пусть будет.

https://github.com/foobar1643/filehosting/blob/master/app/Helper/CommentHelper.php#L16

> public function addComment(Comment $comment)


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

Насчет выборк комментов - ты строишь дерево. А не проще ли делать плоскую структуру? Просто выбирать комменты ORDER BY path?

> $this->normalizePath("{$parentComment->getParentPath()}.{$comment->getId()}"))


Вот это лучше было бы вынести в метод appendToPath(oldPath, newId)

https://github.com/foobar1643/filehosting/blob/master/app/Helper/FileHelper.php#L20

> public function createFile(File $file, $adminFlag)


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

> $searchGateway->insertRtValue($file->getId(), $file->getName());


тут лучше высокоуровневый метод

indexNewFile($file)
https://github.com/foobar1643/filehosting/ #291 #761044

>>747423


>>755118

> if(!mkdir("{$pathingHelper->getPathToStorage()}/{$file->getFolder()}")) {


> $fileMapper->rollBack();


> throw new FileUploadException(UPLOAD_ERR_CANT_WRITE);


> }


Чтобы не писать кучу роллбеков руками, есть более простой способ:

beginTransaction()
try {
executeSteps()
} catch () {
rollback()
throw
}

commit()

Более того, уже есть готовые функции для этого: http://doctrine-orm.readthedocs.io/projects/doctrine-dbal/en/latest/reference/transactions.html - можно сделать аналогичную.

https://github.com/foobar1643/filehosting/blob/master/app/Helper/FileHelper.php#L56

> public function deleteFile(File $file)


> $commentMapper->deleteComments($file->getId());


> $fileMapper->deleteFile($file);


> $searchGateway->deleteRtValue($file->getId());


Мне кажется там в сервисе должен быть высокоуровневый метод "удалить файл со всем что есть в рамках транзакции". А не в контроллере.

Более того, кли версия - не удаляет комментарии: https://github.com/foobar1643/filehosting/blob/master/cli-tools/admin-tools.php#L66

> class PathingHelper


Ты не пробовал поискать готовые решения? Чем-то не подошли? например

- https://github.com/eloquent/pathogen
- https://packagist.org/search/?search_query[query]=path
- http://phptrends.com/dig_in/path (поиск что-то тормозит)

https://github.com/foobar1643/filehosting/blob/master/public/media/js/comments.js#L19
Плоховато сделана работа с аяксом, почитай мой урок: https://github.com/codedokode/pasta/blob/master/js/ajax.md

-------

В общем, я все пока проверить не успел, увы, времени и так много ушло. Разберись пока с этим. Если есть какие-то вопросы - задавай, я постараюсь не тянуть время и сразу ответить. Напомню еще раз:

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

В общем, неплохая работа, но наверно стоит еще доработать.

И стандартный вопрос: автоматизированные тесты сделать не хочешь?
https://github.com/foobar1643/filehosting/ #291 #761044

>>747423


>>755118

> if(!mkdir("{$pathingHelper->getPathToStorage()}/{$file->getFolder()}")) {


> $fileMapper->rollBack();


> throw new FileUploadException(UPLOAD_ERR_CANT_WRITE);


> }


Чтобы не писать кучу роллбеков руками, есть более простой способ:

beginTransaction()
try {
executeSteps()
} catch () {
rollback()
throw
}

commit()

Более того, уже есть готовые функции для этого: http://doctrine-orm.readthedocs.io/projects/doctrine-dbal/en/latest/reference/transactions.html - можно сделать аналогичную.

https://github.com/foobar1643/filehosting/blob/master/app/Helper/FileHelper.php#L56

> public function deleteFile(File $file)


> $commentMapper->deleteComments($file->getId());


> $fileMapper->deleteFile($file);


> $searchGateway->deleteRtValue($file->getId());


Мне кажется там в сервисе должен быть высокоуровневый метод "удалить файл со всем что есть в рамках транзакции". А не в контроллере.

Более того, кли версия - не удаляет комментарии: https://github.com/foobar1643/filehosting/blob/master/cli-tools/admin-tools.php#L66

> class PathingHelper


Ты не пробовал поискать готовые решения? Чем-то не подошли? например

- https://github.com/eloquent/pathogen
- https://packagist.org/search/?search_query[query]=path
- http://phptrends.com/dig_in/path (поиск что-то тормозит)

https://github.com/foobar1643/filehosting/blob/master/public/media/js/comments.js#L19
Плоховато сделана работа с аяксом, почитай мой урок: https://github.com/codedokode/pasta/blob/master/js/ajax.md

-------

В общем, я все пока проверить не успел, увы, времени и так много ушло. Разберись пока с этим. Если есть какие-то вопросы - задавай, я постараюсь не тянуть время и сразу ответить. Напомню еще раз:

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

В общем, неплохая работа, но наверно стоит еще доработать.

И стандартный вопрос: автоматизированные тесты сделать не хочешь?
>>763268
6 Кб, 423x196
4 Кб, 1027x127
#292 #761112
Что-то я в растерянности. массив=массив =>ошибка
>>761148
#293 #761148
>>761112
У тебя ошибка в том что ты в 16 строке обращаешься не к свойству а к $this->array(...), проще говоря ты поставил переменную $get в место свойства
>>761150
#294 #761150
>>761148

>$this->array(...)


Даже не к самому аррею, а к его содержимому преобразованному строку.
>>761221
#295 #761165
>>760999

>$logger ?: new Logger\NullLogger();


Чем ?: отличается от ?? ?
>>761169>>761944
#296 #761169
>>761165
?: - проверяет на true
?? - проверяет на null
#297 #761170
господа есть ли пример разработки приложение как в задании про студентов или что то подобное?
>>761280>>761938
#298 #761221
>>761150
Опять этот чертов доллар! Спасибо, в упор не видел
#299 #761222
Погроммисты, какой скрипт нужен для перехода из программы по внешней ссылке в инет?
>>761283>>761938
#300 #761280
>>761170
Чем тебе студентов не хватает?
>>761308
48 Кб, 1104x562
#301 #761283
>>761222
Чего блять?
fopen("Youdick.com");
#302 #761308
>>761280
Ему нужно по готовому примеру студентов сделать. Видимо, очередной YouTube'овский саморазвиванец прикатился. Не удобно, когда не ведут за ручку.
>>762943
#303 #761317
Господа, а вы довольны своей зп? не думали перекатываться во что-то другое?
#304 #761319
>>761317
Квалифицированному специалисту везде будут платить хорошо, не?
>>761320
#305 #761320
>>761319
Да, но в разных сферах зп разные.
>>761660
#306 #761327
Начал юзать IDE, но пока не вижу особых преимуществ перед текстовыми редакторами. Да, есть подсказки с переменными и классами по всему проекту, но я ими все равно не пользуюсь. Дебаггер? Не знаю как в пхпшторме, но я прочитал небольшой фак по нему в нетбинсе и там только показывают пример небольшого скрипта с парой функций, а что если я захочу дебажить отдельный файл, который подключается через контроллер, причем с разными аргументами?
>>761938
3 Кб, 413x108
#307 #761336
>>753595 (OP)

>


Уже 2 часа с этим кодом мучаюсь. Это задание про тупого шкАльника из книжки, который покупает себе новый айпад. Я уже понял, что ошибка у меня в цикле, но какая? Подскажите, люди добрые
http://ideone.com/Gt7wk2
>>761340>>761389
#308 #761340
>>761336
Ты два часа не можешь понять, что твой цикл не делает ни одной итерации, так как изначально не проходит условие?
>>761345
#309 #761345
>>761340
Ох, спасибо. Понял. Похоже, задача про меня
#310 #761387
>>761317
В плане иное? Вообще "уйти из авиации" в смысле из айти? Не, не реально мне. Вспоминаю как в особенностях охоты чувак говорил менту, потерявшему пистолет: "Работать пойдешь... делать-то умеешь что-нибудь?" на что мент грустно мотал головой, вот тут как-то так же.

Да и не охота, от офисов и менеджеров по говноебанию тянет блевать.
>>761400
360 Кб, 1920x1080
#311 #761389
>>761336

>http://ideone.com/Gt7wk2


У тебя считает неверно.
1. Процент надо высчитывать каждый раз от оставшейся суммы задолженности.
2. У тебя сумма ежемесячного платежа прибавляется в последней итерации цикла, так как стоит в шапке цикла.
>>761634
#312 #761400
>>761387
Я имею ввиду в js, java и прочее.
#313 #761634
>>761389
И еще в последнем месяце проценты и оплата ведение счета не будут начисляться. Это не правильно.
#314 #761660
>>761320
Для пыхи есть 2 сферы.
Энтерпрайз (обычно внутренний продукт), и Уэб - сайтики/стартапы
И зп зависит по большей мере от уровня спеца
#315 #761665
>>753595 (OP)
У тебя есть задачка про кошек и мышей.
В ней рекомендуется хранить животных в ОДНОМЕРНОМ массиве.
А что там конкретно хранить? объекты Animal?
Делать специальный метод для отрисовки животных на 2d поле?
А как представить себе перемещение по этому полю? вычитать/прибавлять к значению координаты . Ты говорил что так проще будет.
>>761938
249 Кб, 1700x1100
#316 #761673
>>753595 (OP)
PHP-гуру, подскажите поожалуйста как оформить такой код:

Внести данные в таблицу TEST где id = 1;
Если ( такой запрос к базе был сделан в теченнии последних 15 секунд ) {
Не делать запрос
} else if ( запрос не был сделан в течении последних 15 секунд ) {
Обновить старый запрос - новым.
}
>>761677>>761762
#317 #761677
>>761673
такой запрос к базе был сделан в теченнии последних 15 секунд
Многопоточность, таймер с который через 15 сек обратно ставит переменную в false
по другому никак
>>761678>>761695
#318 #761678
>>761677
блять, разметку проебал
#319 #761695
>>761677
Ну типу дело в том, что предумсмотрена отправка запроса из разных компьютеров.
Как дслеать вот такой код правильно
(SELECT * FROM test_table WHERE id=1);
if ( test_table['time'] > "сейчас минус 15 секунд" ) {
Не делать ничего.
} else if ( test_table['time'] < "сейчас минус 15 секунд" ) {
UPDATE test_table SET test_row = test_text WHERE id=1;
Что нужно вставить в "сейчас минус 15 секунд", чтобы оно меня поняло ?
}
>>761697
#320 #761697
>>761695
А кто тебе 'тикать' эту запись будет?
>>761706
#321 #761706
>>761697
А она аяксом тикается раз в 15 секунд.
>>761714
#322 #761714
>>761706
С головой всё в порядке? А если у меня пека зависнет, и не тикнет. Фиг ты че обновишь на другой пеке
>>761723
#323 #761723
>>761714
Так оно аяксом тикается вне зависимости от твоего компьютера. Сервер вызывает скрипт раз в 15 секунд.
>>761724
181 Кб, 960x1280
#324 #761724
>>761723
Тогда это крон, а не аякс
Ты зелёный что-ли?
#325 #761762
>>761673

>Внести данные в таблицу TEST где id = 1


Если под "внести данные" подразумевается insert или update (вставка или обновление записи), то наверное в таблице и хранить время последней модификации, затем сравнивать его с текущим.

Напиши лучше в какой ситуации это понадобилось, возможно есть более рациональное решение.
>>761780
164 Кб, 900x1265
#326 #761780
>>761762
Генерируется вопрос, заносится в таблицу. 15 секунд этот вопрос отображается у всех пользователей. Если обновить страницу, то этот вопрос всё ещё останется. Через 15 секунд, вопрос поменяется. И так каждые 15 секунд собстна.
>>761806>>761827
#327 #761806
>>761780
Я бы на вебсокетах сделал, аякс для такого реалтайма неудачное решение. На PHP есть библиотека Rachet для этого.
>>761843
#328 #761827
>>761780
Так в чем сложность?
В таблице добавить поле с временной меткой, когда был создан "вопрос" (что еще за "вопрос"?).

Сверхсложный алгоритм:
Выбрать из бд последний (по дате создания) "вопрос".
Если (дата создания вопроса + 15 секунд < текущего времени) { сгенерировать новый вопрос и сохранить в базу, отдать клиенту новый вопрос }
иначе { отдать последний найденный вопрос }

Если подробно опишешь проблему, получишь соответствующий ответ.
Пока непонятно, что у тебя за "вопросы", какой смысл их "генерировать" каждые 15 секунд, вместо того чтобы заранее занести в базу определенное количество и отдавать рандомный.
>>761840
#329 #761830
Как пользоваться ActiveRecord?
Есть ли какой-нибудь мануал, типа Thinking with ActiveRecord, или Core principles of ActiveRecord?
В вузе учили SQL, а что такое ActiveRecord и зачем он нужен - не понятно.

В yii2 есть отличные средства для отправки sql-запросов, пилил бы как в вузе учили. Но сейчас говорят, что нельзя использовать чистый sql.
А как по мне, то он лучший.
>>761938
#330 #761840
>>761827
Ну так если просто отдавать рандомный, то у каждого пользователя будет отдельный рандом, а соответственно разные вопросы. А мне вопрос нужен одинаковый на всех страницах чтобы выводился.
>>761938
#331 #761843
>>761806
Опиши. Почему неудачное ? Есть отдельный файлик с запросом и выводом. Я его просто Аяксом обновляю каждые 15 секунд и всё. Зачем вебсокет целый тащить для этого ?
#332 #761932
Что такое обтекание в html?
>>761938
#333 #761938
>>761932

float?

>>761840

Можно отдать список с запланированным временем показа.

>>761830

Есть такое https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md

> Но сейчас говорят, что нельзя использовать чистый sql.


> А как по мне, то он лучший.


Придется писать много рутинного однотипного кода.

>>761665

> объекты Animal?


да

> как представить себе перемещение по этому полю?


Изменение координаты животного, которая хранится в самом животном. А представь, если у тебя двухмерный массив, как ты гарантируешь что он всегда будет содержать актуальные данные и соответствовать координатам животных? Тут тогда надо будет координаты выносить из объекта Animal в карту, так как иначе гарантии дать трудно.

А какие у тебя есть идеи?

>>761327

Если ты пишешь задачки на 100 строк то разницы особой нет. Разница есть при работе с проектами, где много файлов. Ну и плюс тебе надо изучить разные горячие клавиши облегчающие работу с ИДЕ - например, переход к функции по имени и тд.

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


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

>>761317

А где платят больше, просто интересно? В магазине? В макдональдсе? В ЖКХ? На госпредприятии? Сейчас кризис на дворе вообще-то и на рынке труда не лучшая ситуация.

>>761170

Готового примера нет, но в задаче на студентво есть много комментариев. Также, ты можешь задавать конкретные вопросы вроде "как делается X" и тебе либо подскажут либо отправят в гугл.

>>761222

Не понял, в чем вопрос.
#333 #761938
>>761932

float?

>>761840

Можно отдать список с запланированным временем показа.

>>761830

Есть такое https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md

> Но сейчас говорят, что нельзя использовать чистый sql.


> А как по мне, то он лучший.


Придется писать много рутинного однотипного кода.

>>761665

> объекты Animal?


да

> как представить себе перемещение по этому полю?


Изменение координаты животного, которая хранится в самом животном. А представь, если у тебя двухмерный массив, как ты гарантируешь что он всегда будет содержать актуальные данные и соответствовать координатам животных? Тут тогда надо будет координаты выносить из объекта Animal в карту, так как иначе гарантии дать трудно.

А какие у тебя есть идеи?

>>761327

Если ты пишешь задачки на 100 строк то разницы особой нет. Разница есть при работе с проектами, где много файлов. Ну и плюс тебе надо изучить разные горячие клавиши облегчающие работу с ИДЕ - например, переход к функции по имени и тд.

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


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

>>761317

А где платят больше, просто интересно? В магазине? В макдональдсе? В ЖКХ? На госпредприятии? Сейчас кризис на дворе вообще-то и на рынке труда не лучшая ситуация.

>>761170

Готового примера нет, но в задаче на студентво есть много комментариев. Также, ты можешь задавать конкретные вопросы вроде "как делается X" и тебе либо подскажут либо отправят в гугл.

>>761222

Не понял, в чем вопрос.
#334 #761944
>>761165

По моему тем что ?? проверяет на !empty и не дает ошибки если переменная слева отстутствует

>>760999

Да, ну, отдает фанатизмом (в плане того что везде надо делать NullObject). В случае с логгером можно всего сделать метод log() который будет проверять наличие логгера. В других случаях - учитывать возможность наличия NULL.

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


ну так не надо использовать null вместо исключения

>>760864

Ты правильно делаешь, что задаешь вопросы. Инженер принимает решения не потому что "уважаемый человек так сказал" или "я прочел в твиттере что на этой неделе яваскриптщики пишут на этом фреймворке" или "фейсбук это использует". Нет, он сравнивает преимущества и недостатки разных подходов и выбирает оптимальный для решения задачи.

> Пишем класс - соотв. таблице БД. Свойства - поля таблицы, методы - допустим, КРУД.


> Данные подаются через аргументы методов.


Это ближе к ActiveRecord и точно не TDG. невнимательно читал ты мой урок.

> Я просто хочу понять, ЧЕМ ооп лучше процедурного стиля.


Тем, что на процедурном стиле хорошо пишутся только маленькие программы из 10 функций. Как только программа становится сложнее, код становится запутанным и не читаемым и нам нужен другой подход к организации кода - например, ООП.

Ну вот у тебя задача: ты пишешь соцсеть и надо сделать форму регистрации. Надо написать функцию, проверяющую правильно ли заполнена форма (указаны ли все нужные поля, правильный ли возраст и тд). Что ты подаешь на вход функции? Что на выход? Затем, появляются доработки. Надо также уметь проверять не только данные в форме, но и в базе данных. Чтобы проверить, соответствуют ли старые пользователи нашим новым правилам. Далее, мы вводим многоязычность и надо возвращать описания ошибок на нужном языке. После этого, разработчики просят добавить отключаемый логгер, чтобы у себя в тестовой версии сайта они могли включить запись информации в логи. И в конце, надо написать автоматические тесты, тестирующие твою функцию (например проверяющие что если мы не заполнили в форме имя, то выводится ошибка что имя не заполнено). Как ты это все реализуешь без ООП?

Или другой пример: у тебя есть файл A, работающий с базой данных. Надо логгировать все запросы, которые делает этот файл. Код файла менять нельзя, так как это сторонняя библиотека.

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

Или четвертый пример: ты делаешь приложение TestHub для создания и прохождения тестов и проверки знаний ученика. Тест состоит из нескольких вопросов, вопросы бывают разных типов (с вводом слова, числа в пределах погрешности, выбором готового варианта). Тест может быть помечен тегами (полное описание задачи: https://gist.github.com/codedokode/8733007 ). как в своей программе ты представишь сущность "тест"? Ну то есть тест с описанием, со всеми вопросами, тегами итд. Вот тебе надо его передать например в функцию, которая считает максимально возможное число баллов за него. Или которая проверяет правильно ли введены ответы.

Или пятый пример. Допустим, ты пишешь соцсеть и хранишь информацию о постах в массиве. Тебя просят под постом выводить кроме имени автора, еще и его рейтинг. Ты смотришь в шаблон поста и видишь там:

<div><?= html($post['text']) ?></div>
<div>Автор: <?= html($post['author_name']) ?></div>

Как понять, есть ли в массиве рейтинг пользователя? В каком поле он хранится? Откуда берется массив $post, понять трудно так как этот шаблон подключается из другого шаблона, а тот вызвается из нескольких разных мест кода.
#334 #761944
>>761165

По моему тем что ?? проверяет на !empty и не дает ошибки если переменная слева отстутствует

>>760999

Да, ну, отдает фанатизмом (в плане того что везде надо делать NullObject). В случае с логгером можно всего сделать метод log() который будет проверять наличие логгера. В других случаях - учитывать возможность наличия NULL.

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


ну так не надо использовать null вместо исключения

>>760864

Ты правильно делаешь, что задаешь вопросы. Инженер принимает решения не потому что "уважаемый человек так сказал" или "я прочел в твиттере что на этой неделе яваскриптщики пишут на этом фреймворке" или "фейсбук это использует". Нет, он сравнивает преимущества и недостатки разных подходов и выбирает оптимальный для решения задачи.

> Пишем класс - соотв. таблице БД. Свойства - поля таблицы, методы - допустим, КРУД.


> Данные подаются через аргументы методов.


Это ближе к ActiveRecord и точно не TDG. невнимательно читал ты мой урок.

> Я просто хочу понять, ЧЕМ ооп лучше процедурного стиля.


Тем, что на процедурном стиле хорошо пишутся только маленькие программы из 10 функций. Как только программа становится сложнее, код становится запутанным и не читаемым и нам нужен другой подход к организации кода - например, ООП.

Ну вот у тебя задача: ты пишешь соцсеть и надо сделать форму регистрации. Надо написать функцию, проверяющую правильно ли заполнена форма (указаны ли все нужные поля, правильный ли возраст и тд). Что ты подаешь на вход функции? Что на выход? Затем, появляются доработки. Надо также уметь проверять не только данные в форме, но и в базе данных. Чтобы проверить, соответствуют ли старые пользователи нашим новым правилам. Далее, мы вводим многоязычность и надо возвращать описания ошибок на нужном языке. После этого, разработчики просят добавить отключаемый логгер, чтобы у себя в тестовой версии сайта они могли включить запись информации в логи. И в конце, надо написать автоматические тесты, тестирующие твою функцию (например проверяющие что если мы не заполнили в форме имя, то выводится ошибка что имя не заполнено). Как ты это все реализуешь без ООП?

Или другой пример: у тебя есть файл A, работающий с базой данных. Надо логгировать все запросы, которые делает этот файл. Код файла менять нельзя, так как это сторонняя библиотека.

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

Или четвертый пример: ты делаешь приложение TestHub для создания и прохождения тестов и проверки знаний ученика. Тест состоит из нескольких вопросов, вопросы бывают разных типов (с вводом слова, числа в пределах погрешности, выбором готового варианта). Тест может быть помечен тегами (полное описание задачи: https://gist.github.com/codedokode/8733007 ). как в своей программе ты представишь сущность "тест"? Ну то есть тест с описанием, со всеми вопросами, тегами итд. Вот тебе надо его передать например в функцию, которая считает максимально возможное число баллов за него. Или которая проверяет правильно ли введены ответы.

Или пятый пример. Допустим, ты пишешь соцсеть и хранишь информацию о постах в массиве. Тебя просят под постом выводить кроме имени автора, еще и его рейтинг. Ты смотришь в шаблон поста и видишь там:

<div><?= html($post['text']) ?></div>
<div>Автор: <?= html($post['author_name']) ?></div>

Как понять, есть ли в массиве рейтинг пользователя? В каком поле он хранится? Откуда берется массив $post, понять трудно так как этот шаблон подключается из другого шаблона, а тот вызвается из нескольких разных мест кода.
#335 #761949
>>760864

И еще кое-что. Вот у меня есть задача про ООО Вектор и Кошки-мышки в моем учебнике: http://archive-ipq-co.narod.ru/l1/pasta.html

Попробуй решить любую из них без ООП.

ООП позволяет нам вместо неразборчивой кучи функций и массивов разбить код на отдельные слабосвязанные модули-классы, каждый из которых отвечает за свою часть задачи и может использоваться независимо. Модули можно конфигурировать и связывать друг с другом произвольно. Да и просто хранить информацию о чем-то удобнее в объектах. В отличие от массивов, у них есть жестко определенный список полей, методы, опции видимости (private/public). Как ты все это без ООП реализуешь?

ООП позволяет ставить ограничения, например: это поле может менять только этот класс, в эту функцию можно передать только объект такого-то класса. Это защищает от ошибок. Как ты это сделаешь без ООП?

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

Можно строить сложные структуры из объектов. Например, пост, в него включить комментарии, в комментарии их авторов, в авторов - список их друзей, список лайков. Потом одной строчкой сконвертировать всю эту структуру в JSON, причем часть полей не будет туда экспортирована.

Как ты это сделаешь без ООП? На массивах? Ты запутаешься в этой куче данных.
#336 #761951
>>760855

> ООП не проходил по-человечески, хотя могу функциональное GUI приложение с ООП на С++ и Delphi написать.


ООП это важно. Я не представляю как писать поддерживаемый, аккуратный и тестируемый код без ООП будь то PHP, JS или C++.

> Я, например, привык к компилируемой статике. Для меня модель исполнения и динамика в новизну были.


В фреймворках как раз к типизации стремятся, все в объектах, у функций прописаны тайп-хинты.

>>760840

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

>>760836

Не должно быть у джуниора непонимания ООП. Как он код писать собрался? Если это конечно не джумла или вордпресс.

>>760770

Ой, какие низкие требования у вашей студии.

>>760742

Насчет библиотеки - претензии отчасти справедливы. Смотри, что плохо:

- все сделано в виде функций, никак не разбитых на модули. То есть есть 1000 глобальных функций и все. А лучше бы было так:

string.find(...) вместо strpos
regexp.match вместо preg_match

- нет единого принципа именования. например strpos без подчеркивания, а str_replace - с ним.
- нет единого порядка аргументов. Одна функция принимает аргументы в одном порядке, другая -в другом. Запомнить тяжело, приходится смотреть в справочник
- строковые функции безнадежно плохи и не работают - например substr не умеет вырезать подстроку в utf-8 так как она рассчитана на однобайтные кодировки, а в utf-8 буква может кодироваться несколькими байтами
- нет никакой логики в обработке ошибок. Одна функция при ошибке вернет false, другая выведет Warning и вернет false, PDO может либо вернуть false либо выбрасывать исключение в зависимости от режима работы. Вообще, обработка ошибок в PHP сделана неправильно на 100%, куда не глянь. Нужно было с самого начала: 1) использовать исключения 2) останавливаться при ошибке а не продолжать 3) при фатальной ошибке не выводить белую страницу, а страницу ошибки 4) не делать опций в php.ini для игнорирования ошибок
#336 #761951
>>760855

> ООП не проходил по-человечески, хотя могу функциональное GUI приложение с ООП на С++ и Delphi написать.


ООП это важно. Я не представляю как писать поддерживаемый, аккуратный и тестируемый код без ООП будь то PHP, JS или C++.

> Я, например, привык к компилируемой статике. Для меня модель исполнения и динамика в новизну были.


В фреймворках как раз к типизации стремятся, все в объектах, у функций прописаны тайп-хинты.

>>760840

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

>>760836

Не должно быть у джуниора непонимания ООП. Как он код писать собрался? Если это конечно не джумла или вордпресс.

>>760770

Ой, какие низкие требования у вашей студии.

>>760742

Насчет библиотеки - претензии отчасти справедливы. Смотри, что плохо:

- все сделано в виде функций, никак не разбитых на модули. То есть есть 1000 глобальных функций и все. А лучше бы было так:

string.find(...) вместо strpos
regexp.match вместо preg_match

- нет единого принципа именования. например strpos без подчеркивания, а str_replace - с ним.
- нет единого порядка аргументов. Одна функция принимает аргументы в одном порядке, другая -в другом. Запомнить тяжело, приходится смотреть в справочник
- строковые функции безнадежно плохи и не работают - например substr не умеет вырезать подстроку в utf-8 так как она рассчитана на однобайтные кодировки, а в utf-8 буква может кодироваться несколькими байтами
- нет никакой логики в обработке ошибок. Одна функция при ошибке вернет false, другая выведет Warning и вернет false, PDO может либо вернуть false либо выбрасывать исключение в зависимости от режима работы. Вообще, обработка ошибок в PHP сделана неправильно на 100%, куда не глянь. Нужно было с самого начала: 1) использовать исключения 2) останавливаться при ошибке а не продолжать 3) при фатальной ошибке не выводить белую страницу, а страницу ошибки 4) не делать опций в php.ini для игнорирования ошибок
>>762051
#337 #761956
>>760742

А, еще пример идиотизма: PDO умеет создавать объекты и заполнять данными из базы но он сначала создает объект, затем проставляет значения полей и только потом вызывает конструктор. Кто мог до такого додуматься? только человек, не понимающий ООП в принципе.

Еще проблема: отстутствие объектов запроса/ответа. Вот у тебя есть код делающий setcookie() и попробуй-ка перехвати этот вызов. И сверхглобальные переменные GET/POST, доступные везде, хотя мы бы хотели чтобы к ним имел доступ например только контроллер. И опять же, мы не можем их подменить. Попробуй представить что мы хотим параллельно обрабатывать несколько запросов, переключаясь между обработчиками. Мы же замучаемся перезаписывать GET/POST так как в каждом запросе свой набор параметров.А был бы у нас объект запроса -мы бы просто создали несколько объектов и каждому обработчику дали бы свой.

>>760675

Учить все разделы функций не надо. Читать надо справочник языка + поплярные функции работы со строками, массивами, датами, базой данных.

>>759975

У меня есть подозрение что авторизация в Симфони может быть переусложнена Разберись сам в этом вопросе, если переусложнена - делай что-то свое.

ЧПУ делается элеметарно, просто делаешь в тблице поле slug и прописываешь его при создании сущности, а потом по нему ищешь. Можешь в тестхабе для тестов сделать слуги например, хотя тут вопрос, не получатся ли УРЛ слишком большие?

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

>>759955

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

>>759940

> и из какого он языка, лол.


Из пхп? Из Си? Странный вопрос.

>>759937

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

>>759920

> Отличие or/and от || / $$ в таких местах: if(func1() or func2()) { ... }


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

> Приведение типов при сравнении, сложении,


Тоже есть сложности. Кстати, ты знаешь что с PHP7.1 попытка сложить строки не хранящие число ("3 cakes" + 3 или "hello" + "world") будет приводить к ошибке? Столько лет этого ждал.

>>759878

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

>>759725

Бывают и платные тестовые задания. Где я работал, там новому разработчику давали реальную оплачиваемую задачу и смотрели как справится. Но это не везде работает:

- разработчик должен успеть настроить и разобраться в проекте. Если проект сложный, это займет много времени
- надо давать разработчику доступ к коду
- нужна специальная версия базы
#337 #761956
>>760742

А, еще пример идиотизма: PDO умеет создавать объекты и заполнять данными из базы но он сначала создает объект, затем проставляет значения полей и только потом вызывает конструктор. Кто мог до такого додуматься? только человек, не понимающий ООП в принципе.

Еще проблема: отстутствие объектов запроса/ответа. Вот у тебя есть код делающий setcookie() и попробуй-ка перехвати этот вызов. И сверхглобальные переменные GET/POST, доступные везде, хотя мы бы хотели чтобы к ним имел доступ например только контроллер. И опять же, мы не можем их подменить. Попробуй представить что мы хотим параллельно обрабатывать несколько запросов, переключаясь между обработчиками. Мы же замучаемся перезаписывать GET/POST так как в каждом запросе свой набор параметров.А был бы у нас объект запроса -мы бы просто создали несколько объектов и каждому обработчику дали бы свой.

>>760675

Учить все разделы функций не надо. Читать надо справочник языка + поплярные функции работы со строками, массивами, датами, базой данных.

>>759975

У меня есть подозрение что авторизация в Симфони может быть переусложнена Разберись сам в этом вопросе, если переусложнена - делай что-то свое.

ЧПУ делается элеметарно, просто делаешь в тблице поле slug и прописываешь его при создании сущности, а потом по нему ищешь. Можешь в тестхабе для тестов сделать слуги например, хотя тут вопрос, не получатся ли УРЛ слишком большие?

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

>>759955

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

>>759940

> и из какого он языка, лол.


Из пхп? Из Си? Странный вопрос.

>>759937

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

>>759920

> Отличие or/and от || / $$ в таких местах: if(func1() or func2()) { ... }


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

> Приведение типов при сравнении, сложении,


Тоже есть сложности. Кстати, ты знаешь что с PHP7.1 попытка сложить строки не хранящие число ("3 cakes" + 3 или "hello" + "world") будет приводить к ошибке? Столько лет этого ждал.

>>759878

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

>>759725

Бывают и платные тестовые задания. Где я работал, там новому разработчику давали реальную оплачиваемую задачу и смотрели как справится. Но это не везде работает:

- разработчик должен успеть настроить и разобраться в проекте. Если проект сложный, это займет много времени
- надо давать разработчику доступ к коду
- нужна специальная версия базы
607 Кб, 1324x1101
301 Кб, 1920x1080
107 Кб, 1024x685
269 Кб, 1280x960
#338 #761958
Доброе утро анончики, вкатываюсь в тред после годичного отсутствия тут. Прошлой весной еще сидел с вами и выполнял упражнения. Потом нашел работку в небольшой студии веб-макакичем, где писал на php + codeigniter, оп еще говорил мне, что кодигнайтер - плохо и всё такое, но мне было норм, работать было интересно и постоянно обучался новому. Потом в этой же студии php закончилось, и меня пересадили на вордпрессы и прочую поддержку, а потом я вообще баннеры менял, после чего и съебал оттуда по осени. Думал что пару недель освежу знания и снова в бой, в место получше, где я буду ебашить пусть и джуном, но полноценный и качественный бэк-энд с ооп и на современных фреймворках. Но чет я стал пинать хуи, и вот это пинание хуев уже длится 8 месяцев, если не соврать бы.

Неделю назад заполнил первую анкетку, и вот прислали приглашение пройти у них тест. В котором вроде как будет матан, алгоритмы и ооп. Очень сильно боюсь обосраться. Как бы мне сейчас освежить хотя бы основы в ооп и прочих современных штуках по нашей теме? В веб-студии я не уверен что освоил хорошее ооп, просто MVC, в котором модели и контроллеры описаны как классы, ну и которые наследуются от игнайтеровских моделей и контроллеров. Ну и конструкторы использовались там, ничего более.

Ща думаю вернуться к продвинутым задачам от ОПа, с ооп, рекурсией и прочими анонимными функциями, в которых я в своё время хуево разобрался, а так же хотелось бы параллельно книжку почитать годную. Что есть для среднего джунивора, который уже видел в глаза как написана приложуха на mvc и работал пол года с несложными задачами?

Что скажите про вот эту статью?
https://habrahabr.ru/post/260201/

В общем надеюсь на вас, анчоусы. Если что, с радостью отвечу на вопросы стремящихся, которые еще только хотят устроиться на свою первую работку, но неуверенны в себе.

яркие рандомные картинки, для привлечения внимания, как вашего, так и моего в дальнейшем
>>761969>>762982
#339 #761969
>>761958

По ООП - я переделал урок про ООП в учебнике и немного его дополнил. Также, отдельные уроки:

- https://github.com/codedokode/pasta/blob/master/arch/di.md
- https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
- https://github.com/codedokode/pasta/blob/master/php/autoload.md
- https://github.com/codedokode/pasta/blob/master/php/exceptions.md

Также, советую погуглить и почитать про SOLID, DRY, YAGNI. Почитать статью на хабре "как 2 пекаря хлею пекли". Про паттерны - сайт http://designpatternsphp.readthedocs.io/ru/latest/README.html (примеры правда там довольно дурацкие и бессмысленные и не объясняют зачем нужен паттерн)

> Прочитать книжки (по неделе на книжку, читая вечерами и на выходных):


> Совершенный код


Эта неплохая, хотя не про PHP

> Symfony 2


Полезно почитать

> PHPUnit — основы, перевод 8 глав документации


перед этим читай мой урок про автоматизированное тестирование

> Vagrant — документация, в PhpStorm


Сомневаюсь что нужен. Докер вроде сейчас чаще используют, да и на него не стоит тратить время, это скорее задача администратора.

> Идеи проектов:


> блог


> интернет-магазин


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

> Научиться набирать вслепую


> Выучить на память TOP100-300 ф


не трать время

> Изучить еще один язык программирования на уровне написания простеньких приложений. Желательно совсем другой парадигмы:


Я рекомендую тогда книгу по SICP (например http://newstar.rinet.ru/~goga/sicp/sicp.pdf ) - там изучается язык scheme.

Боюсь только у тебя на все это времени не хватит.
#339 #761969
>>761958

По ООП - я переделал урок про ООП в учебнике и немного его дополнил. Также, отдельные уроки:

- https://github.com/codedokode/pasta/blob/master/arch/di.md
- https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
- https://github.com/codedokode/pasta/blob/master/php/autoload.md
- https://github.com/codedokode/pasta/blob/master/php/exceptions.md

Также, советую погуглить и почитать про SOLID, DRY, YAGNI. Почитать статью на хабре "как 2 пекаря хлею пекли". Про паттерны - сайт http://designpatternsphp.readthedocs.io/ru/latest/README.html (примеры правда там довольно дурацкие и бессмысленные и не объясняют зачем нужен паттерн)

> Прочитать книжки (по неделе на книжку, читая вечерами и на выходных):


> Совершенный код


Эта неплохая, хотя не про PHP

> Symfony 2


Полезно почитать

> PHPUnit — основы, перевод 8 глав документации


перед этим читай мой урок про автоматизированное тестирование

> Vagrant — документация, в PhpStorm


Сомневаюсь что нужен. Докер вроде сейчас чаще используют, да и на него не стоит тратить время, это скорее задача администратора.

> Идеи проектов:


> блог


> интернет-магазин


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

> Научиться набирать вслепую


> Выучить на память TOP100-300 ф


не трать время

> Изучить еще один язык программирования на уровне написания простеньких приложений. Желательно совсем другой парадигмы:


Я рекомендую тогда книгу по SICP (например http://newstar.rinet.ru/~goga/sicp/sicp.pdf ) - там изучается язык scheme.

Боюсь только у тебя на все это времени не хватит.
>>761985
488 Кб, 701x1024
#340 #761985
>>761969
О, привет опчик. Подкинь мне сразу еще задач на рекурсию и анонимные функции и коллбеки, я помню они есть у тебя. Я тогда как раз на всем этом сидел + кофе считал и антикризисные меры, ага. Ща продолжу с перечитыванием мануалов.
абесните #341 #762026
ЗДаров ОП и гуру JS. Вот задумал реализовать такую же штуку
http://alvarotrigo.com/fullPage/ то есть легонько проворачиваешь скролл а у тебя листаются блоки размером 100% на 100%. Шняга для промо-сайтов короче.
Ну и чтоб чуть отличалось сделал чтоб текущий слайд не уезжал, а на месте оставался.
http://codepen.io/anon/pen/RRPyGL
У меня вопрос. Почему у этого чела подобный функционал занимает 3к строк на гитхабе? И почему я в нем нихрена не могу понять он для меня выглядит как китайские иероглифы. Мой код похож на говно, но он занимает 30 строк ну и просто работает (в последнем хроме, хехе). Да, понятно, что нужны фолбеки для определения события для разных браузеров, поддержка скролла с клавы и на мобилах, заворачивание в плагин и т. д. но все равно я не пойму как писать такой профессионально выглядящий нихера непонятный код вместо
боди.онскролл = {
страница[текущая].крутаниВверх()
}
#342 #762043
>>762026

>я не пойму как писать такой профессионально выглядящий нихера непонятный код


Зачем?
>>762060
#343 #762051
>>761951

>Не спеша как-то ты учишь. В нашем учебнике до ООП можно за 7 месяцев дойти, хоть он и в последней главе.


Дизайн, верстка, ЦМСки, инструментарий мелкий (тысячи их), фреймворки, JS, CEO, алгоритмы. В оставшееся время PHP.
>>762058
#344 #762058
>>762051

>Дизайн


Покажи работу. Могли бы упарывать вместе.
>>762071
#345 #762060
>>762043
Ну зачем-то же люди с 4к форков пишут такую дичь. Значит так надо.
>>762070
#346 #762070
>>762060
Когда дорастешь до этих людей, тогда сам будешь знать, как и зачем.
#347 #762071
>>762058
Мне нечего пока показать. Весь мой дизайн пока сводится к тому что я пытаюсь отрисовать в фотошопе по памяти отдельные функциональные блоки, которые вышли у авторов очень удачно, дрочу на идеальный пэддинг, оптимальную высоту шрифта, ширину колонок текста. Микровопросы пока идут в общем.
>>762087
#348 #762087
>>762071

Попробуй еще векторные редакторы (inkscape например) - многие вещи там удобнее делать чем в ФШ.
>>762102
#349 #762102
>>762087
Illustrator использую.
#350 #762131
Господа, как средствами пхп войти в аккаунт инстаграмма посредством http запроса? там же куки сессии. знаю, что надо curl юзать, но есть конкретный скрипт, который входит (и выходит)?
Желательно еще чтобы он умел проверять, если ли запрос на подтверждение телефона.
>>773830
#351 #762134
5 лет не могу найти работу, высказываюсь цепочкой мелких постов, понял мразь
>>762233
#352 #762213
Уже используют php7?
Именно на работе кто-то перекатился и зачинает новые проекты на нем?
#353 #762233
>>762134
Как так? Работы дохуя.
>>762255
#354 #762255
>>762233
не в моей локации наверное.
#355 #762502
Спасибо, ОП. Исправил все кроме склонений слов, локализации и CSRF, это позже доделаю.
https://github.com/foobar1643/filehosting

>ты используешь константу-массив, которая пока доступна только в новом php. Пришлось исправлять, чтобы запустить.


5.6 же последняя пятая, да и вышла она уже давно. Я вообще думал к следующей задаче (тестхаб) делать перекат на седьмую версию, вроде бы Yii 2 с ней нормально работает. То что в ридми указано 5.5 это потом исправлю, когда буду его на английский переводить.

>Чтобы это реалилизовать, тебе надо использовать фичу сфинкса которая позволяет делать конфиг на скриптовом языке


Я сделал, но я не очень понимаю откуда брать эту переменную окружения. Точнее, каким образом администратор узнает что её можно задавать. Можно написать в ридми что есть возможность задать переменную окружения SPHINX_ROOT, для хранения индексов в другой директории. Этого хватит?

>Сам поиск у меня падает с сообщением 'exception 'ErrorException' with message 'PDO::__construct(): Server sent charset (0) unknown to the client. Please, report to the developers'


Я погуглил, пишут что это пофиксили в новых версиях (правда запись в багтрекере еще за 2012 год).
http://sphinxsearch.com/bugs/view.php?id=1249

>В комментариях при отпраке аяксом содержится XSS.


Тут я не совсем понял как бороться с XSS с помощью JS. Насколько я знаю там нет функции которая по функционалу была бы как htmlspecialchars, единственное что я смог придумать это encodeURIComponent(comment.text), это работает, но совсем не так как нужно, и вообще назначение у функции другое. Я еще думал регулярками убирать теги, но этот вариант мне не очень нравится, и насколько я помню там нужна хорошая регулярка, потому что существует много способов её обойти.

>CsrfGuard на мой взгляд мутный, хоть он и сделан по рекомендациям OWASP. Требует сессий. На каждый запрос генерирует токены, даже если они потом не используются.


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

>В валидаторе ты валидируешь массив А ведь можно валидировать модель комментария.


>А как ты считаешь, что лучше?


Когда я делал тот валидатор, вроде бы логика была в том, чтобы отправить туда данные из формы, и если они неправильные то не заполнять модель зря, а показать пользователю ошибку. Я не подумал о том что мне так же нужно будет проверять комментарий который был получен другим способом (CLI скриптом например, я там сделал добавление комментариев). В таком случае, конечно лучше всегда проверять модель.
У меня еще вопрос был по поводу валидации. Это нормально что я совместил валидацию формы загрузки файла и комментариев в одном классе? Я сначала думал делать по классу-валидатору на сущность, но потом понял что тут у меня всего две сущности и легче будет сделать класс в котором два метода. А если сущностей в приложении 5 и более, тут будет разумным делать по классу-валидатору на каждую (при условии что их вообще нужно проверять, конечно)?

>> public function addComment(Comment $comment)


>Тут алгоритм какой-то мутный. Нельзя минимизировать число обращений к БД?


Если не добавлять id комментария в его mpath, тогда сломается сортировка при выборке из БД. Хотя мне должно быть все равно, я же дерево строю. Я пока оставил, потом потестирую и уберу, если получится.

>Насчет выборк комментов - ты строишь дерево. А не проще ли делать плоскую структуру? Просто выбирать комменты ORDER BY path?


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

> https://github.com/foobar1643/filehosting/blob/master/app/Helper/FileHelper.php#L56


>Мне кажется там в сервисе должен быть высокоуровневый метод "удалить файл со всем что есть в рамках транзакции". А не в контроллере.


Так это и есть сервис, в контроллере такой метод как раз и используется.

>> class PathingHelper


>Ты не пробовал поискать готовые решения? Чем-то не подошли?


Я смотрел готовые решения, но они мне показались слишком перегруженными, и больше половины функций оттуда я бы в этой работе все равно не использовал бы. А PathingHelper это простой класс, который строит пути из корня, который ему передали. Он выполняет свою функцию и я не вижу смысла его менять.

>Плоховато сделана работа с аяксом, почитай мой урок


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

>И стандартный вопрос: автоматизированные тесты сделать не хочешь?


Хочу, только я слабо понимаю как они работают. Я читал урок, понимаю зачем они нужны, но раньше никогда тестов не писал и не очень понимаю что именно нужно будет тестировать в этой задаче. Операции с файлами и комментариями (добавление, удаление)? Хотя сам PHPUnit я толком и не изучал, почитаю как доделаю локализацию и csrf.
#355 #762502
Спасибо, ОП. Исправил все кроме склонений слов, локализации и CSRF, это позже доделаю.
https://github.com/foobar1643/filehosting

>ты используешь константу-массив, которая пока доступна только в новом php. Пришлось исправлять, чтобы запустить.


5.6 же последняя пятая, да и вышла она уже давно. Я вообще думал к следующей задаче (тестхаб) делать перекат на седьмую версию, вроде бы Yii 2 с ней нормально работает. То что в ридми указано 5.5 это потом исправлю, когда буду его на английский переводить.

>Чтобы это реалилизовать, тебе надо использовать фичу сфинкса которая позволяет делать конфиг на скриптовом языке


Я сделал, но я не очень понимаю откуда брать эту переменную окружения. Точнее, каким образом администратор узнает что её можно задавать. Можно написать в ридми что есть возможность задать переменную окружения SPHINX_ROOT, для хранения индексов в другой директории. Этого хватит?

>Сам поиск у меня падает с сообщением 'exception 'ErrorException' with message 'PDO::__construct(): Server sent charset (0) unknown to the client. Please, report to the developers'


Я погуглил, пишут что это пофиксили в новых версиях (правда запись в багтрекере еще за 2012 год).
http://sphinxsearch.com/bugs/view.php?id=1249

>В комментариях при отпраке аяксом содержится XSS.


Тут я не совсем понял как бороться с XSS с помощью JS. Насколько я знаю там нет функции которая по функционалу была бы как htmlspecialchars, единственное что я смог придумать это encodeURIComponent(comment.text), это работает, но совсем не так как нужно, и вообще назначение у функции другое. Я еще думал регулярками убирать теги, но этот вариант мне не очень нравится, и насколько я помню там нужна хорошая регулярка, потому что существует много способов её обойти.

>CsrfGuard на мой взгляд мутный, хоть он и сделан по рекомендациям OWASP. Требует сессий. На каждый запрос генерирует токены, даже если они потом не используются.


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

>В валидаторе ты валидируешь массив А ведь можно валидировать модель комментария.


>А как ты считаешь, что лучше?


Когда я делал тот валидатор, вроде бы логика была в том, чтобы отправить туда данные из формы, и если они неправильные то не заполнять модель зря, а показать пользователю ошибку. Я не подумал о том что мне так же нужно будет проверять комментарий который был получен другим способом (CLI скриптом например, я там сделал добавление комментариев). В таком случае, конечно лучше всегда проверять модель.
У меня еще вопрос был по поводу валидации. Это нормально что я совместил валидацию формы загрузки файла и комментариев в одном классе? Я сначала думал делать по классу-валидатору на сущность, но потом понял что тут у меня всего две сущности и легче будет сделать класс в котором два метода. А если сущностей в приложении 5 и более, тут будет разумным делать по классу-валидатору на каждую (при условии что их вообще нужно проверять, конечно)?

>> public function addComment(Comment $comment)


>Тут алгоритм какой-то мутный. Нельзя минимизировать число обращений к БД?


Если не добавлять id комментария в его mpath, тогда сломается сортировка при выборке из БД. Хотя мне должно быть все равно, я же дерево строю. Я пока оставил, потом потестирую и уберу, если получится.

>Насчет выборк комментов - ты строишь дерево. А не проще ли делать плоскую структуру? Просто выбирать комменты ORDER BY path?


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

> https://github.com/foobar1643/filehosting/blob/master/app/Helper/FileHelper.php#L56


>Мне кажется там в сервисе должен быть высокоуровневый метод "удалить файл со всем что есть в рамках транзакции". А не в контроллере.


Так это и есть сервис, в контроллере такой метод как раз и используется.

>> class PathingHelper


>Ты не пробовал поискать готовые решения? Чем-то не подошли?


Я смотрел готовые решения, но они мне показались слишком перегруженными, и больше половины функций оттуда я бы в этой работе все равно не использовал бы. А PathingHelper это простой класс, который строит пути из корня, который ему передали. Он выполняет свою функцию и я не вижу смысла его менять.

>Плоховато сделана работа с аяксом, почитай мой урок


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

>И стандартный вопрос: автоматизированные тесты сделать не хочешь?


Хочу, только я слабо понимаю как они работают. Я читал урок, понимаю зачем они нужны, но раньше никогда тестов не писал и не очень понимаю что именно нужно будет тестировать в этой задаче. Операции с файлами и комментариями (добавление, удаление)? Хотя сам PHPUnit я толком и не изучал, почитаю как доделаю локализацию и csrf.
#356 #762607
Анон, помоги, либо ideone тупит, либо я не понимаю, как остаток считается. С некоторыми числами выходит следующее:

32564376345%1000 = -23
23542423432%1000 = 952

Должно же быть 345 и 432?
>>779251
35 Кб, 1017x314
19 Кб, 1334x194
#357 #762662
Хм, непонятно, чем он негодует. hash в базе - Обычная строка
>>762695
#358 #762695
>>762662
Запятая перед where
>>762770
Анон #359 #762732
http://ideone.com/OfNX5i
анончики, я ещё совсем ньюфаг, дрочу preg_split, разбиение текста на предложения. Внезапно вылетает bool(false), читал в мануале, они мне что то втирают про не соответсвие regexp со строкой, но в моем коде, вроде все соответствует
>>762735
#360 #762735
>>762732
Надо экранировать некоторые символы, если именно они тебе нужны.
Посмотри у ОПа, какие.
Ещё надо читать оповещения: PHP Warning: preg_split(): Compilation failed: missing terminating ] for character class at offset 4 in /home/Bo1kal/prog.php on line 4
Понятно, что ты хотел в квадратных скобках перечислить знаки конца предложения, но всё же.
>>762742
#361 #762742
>>762735
бля, я косоглазый. Спасибо, анончик.
Иногда замечаю, что когда не можешь найти ошибку, надо развеяться на некоторое время и вернуться к коду, и сразу внезапно видешь совершенно глупую ошибку.
#362 #762752
Пацаны, а ОП уже взял кого-нибудь из треда на работу?
>>762774
#363 #762770
>>762695
Спасибо!
#364 #762774
>>762752
Меня взял. Пилим сейчас стартап в Аргентине еще с двумя анонами. Ищем 4-го. Оставляйте свои резюме в треде.
>>762787
#365 #762787
>>762774
Выслал тебе в личку, ответь в течении дня подалуйста, а то меня в яндекс зовут, но я дропну их, если с вами срастется.
>>762856
#366 #762856
>>762787
Какой у тебя уровень юмора, TARS?
#367 #762943
>>761308
>>761308
ты не прав очередной студент хуепинальщик заехал к вам в гости
#368 #762982
>>761958
А почему codeigniter плохо, расскажите пожалуйста ?
>>763330
#369 #762995
Только что первый раз в жизни словил ERR_EMPTY_RESPONSE.
Оказалось, что слово Parent нельзя использовать в качестве имени класса, так как зарезервировано. Хотя не вижу его в списке
http://php.net/manual/ru/reserved.keywords.php

Просто странно, почему не обычная 500 ошибка?
>>763019
#370 #763019
>>762995

EMPTY_RESPONSE скорее всего значит что процесс Апача с PHP внутри упал. В логе будет запись вроде child terminated unexpectedly. Это баг который ты мог бы зарепортить, если можешь собрать все подробности и минималистичный пример кода для повторения.

> почему не обычная 500 ошибка?


php не отадет код 5xx, при фатальной ошибке он отдает белую страницу с кодом 200.
#371 #763076
Пацаны, а поясните как реализовывается, допустим, добавление контента на страницу?

Ну классика, делаешь сайт, тебе надо туда какое-то подобие цмс прикрутить, то есть условно кнопка "добавить статью", это текстовое поле и кнопка "добавить". Допустим нахрен весь джаваскрипт, по первой кнопке проваливаемся на новую пхп-страничку добавления статьи, которая с полем и кнопкой. Заполняем поле, жмакаем, это я так понимаю пост-запрос, возвращается изначальная страница, но уже с условно добавленным дивом.

Как это дело сохранять? Только базы данных?

Да и вообще, логику я правильно описал или как оно?
>>763080>>763082
#372 #763080
>>763076

>Как это дело сохранять? Только базы данных?


Конечно бд, как же еще? В текстовый файлик сохранять? Все верно ты описал.
#373 #763082
>>763076

>Заполняем поле, жмакаем, это я так понимаю пост-запрос, возвращается изначальная страница, но уже с условно добавленным дивоманицы то джаваскрипт.


Когда жмагаем на кнопку добавить то твоя статья попадает в базу, никаких дивов никуда не добавляется. После чего редирект на изначальную страницу которой пофиг что ты куда добавлял, она достает из базы последние статьи или их превью и показывает как обычно. Если нужно без обновления страницы тогда только аякс
#374 #763150
Привет, анон. Поясни, пожалуйста, за SQL-инъекции. Какой самый простой и эффективный способ защиты от них?

Не откажусь от ссылочки на какую-нибудь годную библиотеку на пдо/mysqli, где это уже предусмотрено.
>>763183
#375 #763183
>>763150

>Какой самый простой и эффективный способ защиты от них?


Использовать только PDO и его Prepared statements.
http://php.net/manual/ru/pdo.prepared-statements.php
И еще не подставлять данные в SQL запросы из переменных вообще никогда.
>>763189
#376 #763189
>>763183
Хм, то есть, если я, например, сюда:
$stmt = $dbh->prepare ("INSERT INTO user (firstname, surname) VALUES (:fname, :sname)");
$stmt -> bindParam(':fname', $_GET['fname']);
$stmt -> bindParam(':sname', $_GET['sname']);
$stmt -> execute();

Передам какой-нибудь ') DROP TABLE users, это не сработает?
В чем магия-то?
>>763192>>763238
sage #377 #763192
>>763189
Ответ на 13 строке мана, который тебе скинули выше.
>>763198
#378 #763198
>>763192
А, прошу прощения, пропустил этот пункт. Спасибо.
#379 #763238
>>763189

Не сработает. Просто в таблицу будет вставлено переданное значение, оно не будет воспринято как команда.
#380 #763263
объясните нубу,что такое zend?symfony и др простым языком?
>>763290>>763298
#381 #763268
>>761044
Возникла проблема с реализацией многоязычного варианта. Весь функционал перевода я сделал, кроме одной строки

>"1 скачиваний" - что это за насмешка над правилами русского языка?


Как реализовать перевод этой строки на несколько языков и при этом не сломать множественное число?
Обычные склонения в русском языке у меня получилось сделать через MessageFormatter вот так

> new MessageFormatter("ru_RU", "У файла {n, plural, =0{нет загрузок} =1{1 загрузка} one{# загрузка} few{# загрузки} many{# загрузок} other{# загрузок}}");


Но проблема в том что в шаблонах Twig это можно реализовать только следующим способом (тег {% plural %})
http://twig.sensiolabs.org/doc/extensions/i18n.html#complex-translations-within-an-expression-or-tag
Там нет такого функционала как у MessageFormatter, максимум что можно сделать это склонения в английском языке вроде 1 download > 2 downloads.
Единственный вариант который приходит на ум - передавать в шаблон уже отформатированную MessageFormatter строку, а в MessageFormatter локаль получать через Locale::getDefault(), текст получать через gettext. Это уже велосипедом каким-то выглядит, передавать одну строку в шаблон.
>>763278
#382 #763278
>>763268

> Но проблема в том что в шаблонах Twig это можно реализовать только следующим способом (тег {% plural %})


Это плохой и неудачно реализованный тег. Например он не позволит склонять несколько слов независимо в одном предложении.

> передавать в шаблон уже отформатированную MessageFormatter строку,


А нельзя передавать объект MesageFromatter с уже настроенной локалью? Если нет то ты можешь просто запилить свою функцию для вызова MessageFormatter в твиг.

Также, ты можешь сделать свой класс для переводов. И передавать его объект в твиг.

> а в MessageFormatter локаль получать через Locale::getDefault(),


Глобальная переменная, какой кошмар
>>763302
#383 #763290
>>763263
Среда для работы скриптов на сервере. Костяк веб-сайта. Взаимосвязанные кирпичики, из которых можно собрать что угодно.
#384 #763298
>>763263

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

Фреймворк это примерно то же самое, только намного универсальнее. То есть в нем не заложен модуль новостей или обратной связи, а только основа, на которой можно сделать любой нужный модуль. Что-то общее, что пригодится на любом сайте. Например, функции для работы с базой данных, функции для создания и вывода форм, и тд.
#385 #763302
>>763278

>А нельзя передавать объект MesageFromatter с уже настроенной локалью


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

>Также, ты можешь сделать свой класс для переводов. И передавать его объект в твиг.


В этом не очень много смысла, потому что дополнение http://twig.sensiolabs.org/doc/extensions/i18n.html предоставляет тег {% trans %} для переводов в шаблонах.

>Глобальная переменная, какой кошмар


Это класс из Locale из Intl http://php.net/manual/en/class.locale.php , я его использовал чтобы получать локаль для gettext из заголовка HTTP_ACCEPT_LANGUAGE.
>>763513
30 Кб, 450x450
#386 #763330
>>762982
Не знаю, мне было норм. Я очень легко в него вкатился и на его основе вроде как даже понял немного ооп и MVC. Тогда я просто тоже писал в тредике, спрашивал советов и всё такое, а мне ОП говорил что фреймворк старый, сыпет ошибками и прочее. Но я наверное в силу того, что писал на нем относительно простую логику ничего такого не замечал. Видимо всё познается в сравнении с другими фремворками и то, как пишут на них. Хотя опять же именно год назад выкатили его обновление до 3.0, и я первым делом собственно на него перекатил проект, который мне дали. То есть с 2.х версиями я вообще не работал.
#387 #763366
Вопрос по регуляркам, задача про телефонные номера. ( http://archive-ipq-co.narod.ru/l1/regexp.html )

Как можно описать в regex игнорирование символов " -()", чтобы была возможность указать кол-во цифр в телефоне равное 10?
#388 #763471
>>763366
Используй квадратные скобки, Люк!
#389 #763513
>>763366

Просто напиши 10 раз подряд идет одна цифра, за ней любое чсло скобок, пробелов, минусов.

>>763302

> Это класс из Locale из Intl http://php.net/manual/en/class.locale.php , я его использовал чтобы получать локаль для gettext из заголовка HTTP_ACCEPT_LANGUAGE.


Очевидно дефолтный намертво прописанный алгоритм определения языка не подходит. У нас будет отдельный код для его определения и отдельная переменная для него.
>>763532
#390 #763528
>>763366
\d{1,10} или типа того
>>763530
#391 #763530
>>763528
>>763366
или надо ровно 10
#392 #763532
>>763513

>Очевидно дефолтный намертво прописанный алгоритм определения языка не подходит. У нас будет отдельный код для его определения и отдельная переменная для него.


Я для разных языков сделал разные ссылки. И из заголовка я получаю родной язык пользователя, и если приложение доступно на родном языке - показываю уведомление. Так же сделаю возможность сменить язык в любой момент через настройки.
Опять вопрос возник - как получать список доступных языков в приложении? Вот есть папка locales где есть папки вида ru_RU, en_US - можно получать список папок через scandir и пропускать результаты через регулярку, чтобы ничего лишнего туда не попало. Или можно сделать таблицу languages в базе данных, но как туда добавлять новые языки? Тут я придумал только два варианта - добавлять языки в дамп, таким образом при установке приложение сразу будет иметь список доступных в нем языков, или сделать панель для администратора с возможностью добавления языка. Админ панель только ради этого не очень хочется делать, но с другой стороны, в случае с дампом, каждый раз открывать консоль и подключатся к базе чтобы добавить новый язык - это не очень удобно.
>>764116
173 Кб, 720x1018
#393 #763547
Всем привет.
Решаю задачу "Опечаточники" из раздела "Регулярные выражения" учебника ОПа.
http://ideone.com/jicK9b
Не получается реализовать вывод слова с несколькими ошибками в нем. Проблема в том что внутри группы подгруппы выделяются только один раз, в параметре $replacement функции preg_replace() нельзя вывести несколько подгрупп с одинаковыми номерами и совпавшими с разными участками текста.
#394 #763562
>>763547
Можно попробовать разложить $match на составляющие с помощью цикла for, посчитав перед этим количество элементов в нём.
for ($i = 0; $i < count($match) - 1; $i++) {
$wrongText = $match[$i];
}
Извини за столь прозрачную подсказку, но тут не всё так однозначно - сам поймёшь, когда попробуешь.
>>763594
#395 #763594
>>763562
Зачем ты высчитываешь count($match) каждую итерацию?
>>763637>>764116
#396 #763622
Отправляю огромный многомерный массив (1500 переменных) POST-запрос, на обрабатывающем сервере ограничение стоит на объем, и соответственно обрезает 500 последних переменных как выйти из ситуации без настройки сервера? Может ajax'ом отправлять несколько мелких подзапросов?
>>764116
#397 #763637
>>763594
Админы хайлоад-проектов в треде, я спокоен.
#398 #763796
>>753595 (OP)
Госпади, за что мне такое наказание.
Читаю, я значит, умные книжки. Делаю задачки, все оки идет.
Время своего творчества, пора накатывать сервак, все дела.
Запускаю тест, как в инструкции, через командную строку-ошибка.
Пошел скачивать редистирбутивы с от мелкомягких. Процесс установки...другая ошибка. Переустановите, обновите систему. Сделал. Снова ошибка. 1 из многих раз, вроде бы, ошибки не было. Но пыха все равно не запускается, не хватает библиотечного файла, который ставится после обновления дистрибутивов. Как же я заебался, чес слово. Хоть по клаве головой катайся, ну что за херня. Ошибка на ошибке, шиндоус, что ты делаешь.
Ну нахуй это говно.
>>763806
#399 #763806
>>763796
Попробуй xampp. Я им пользуюсь только потому что когда то давно установщик denwer какую-то ошибку показал и обламал меня
вспомнил свой бугурт когда лет 7 назад php не поставился на macbook, а там не было никаких альтернатив в виде денверов и пр. Приходилось кодить в стол
>>763808>>764116
#400 #763808
>>763806

>xampp


Но ведь это просто и удобно, поставил и все.
А в гайдах написано, что я должен вручную все ставить, чтобы разбираться.
Как это вообще, влияет на работу, на фриланс? Или не сильно?
Ясен пень, если дело пойдет, то в будущем себе накатаю по нескольку систем, чтобы мозги не парить.
>>763810>>764116
#401 #763810
>>763808

>Как это вообще, влияет на работу


Устроился вот ты в офис, приходишь в первый день, тебе дают компьютер на котором стоит чистый линукс без интерфейса, и говорят чтобы через час ты уже код писал. Как ты думаешь, это сильно будет влиять на работу?
#402 #763811
>>763810
Я скажу что я спермовор и не собираюсь отказываться от своего рациона.

Я не думал пока о работе в офисе.
Плюс я и с линуксом не знаком, но знаю, что там тот еще мозготрах. Но с другой стороны, так и в чем-то проще. Короче, это отдельная тема. Пока у меня шиндоус и никакого продвижения в работе.
Позже отпишусь, пока что спасибо за наводку.
>>763822
483 Кб, 1810x1216
#403 #763822
>>763811
Ставь отдельно Апач, Мускул, РНР.
Не гневи ОПа (не меня), там дела на 15 минут.
Я всё сказал.
>>763827
#404 #763827
>>763822
Я же говорю-ошибки у меня.
https://www.smartftp.com/support/kb/the-program-cant-start-because-api-ms-win-crt-runtime-l1-1-0dll-is-missing-f2702.html
http://superuser.com/questions/979546/vc-redist-x86-exe-setup-failed-0x80240017-unspecified-error
Вот это вот. Ничего не помогает. Еще и ошибки с дисками. Я бы переустановил винду, накатил бы линукс-но мой комп так по-божески засран неотсортированной инфой, поэтому я ничего радикального делать не хочу.
>>764116>>779251
#405 #763842
>>763810

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


Это правда? Дайте линк на клуб изучающих гей-проституцию пока не поздно.
>>764671
#406 #763858
Ну зашибись, какм-то макаром у меня уже установлен Mysql и поэтому ксамп сам не может включить, пока занят порт.
Как отключить порт? Я пытался удалить все масклы в программах, но эта штука все равно работает.
Пробовал писать все команды из гугла-да нихера не работает, одни линуксовые инструментарии.
Поменял в ини дефолтный порт-не переключает.
Аггрх, как же меня всегда вставляли проблемы с софтом. Щелки не нюхал, а уже поебался, называется.
>>764116
#407 #763861
Анон, как работает wp_upload_bits?

А точнее, я знаю как он работает и что он создает на серваке файл и копирует в него контент, вопрос в том чому не работает как должен

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

$_FILES имеет следующий вид

`Array`
`(`
`[file1] => Array`
`(`
`[name] => MyFile.txt`
`[type] => text/plain`
`[tmp_name] => /tmp/php/php1h4j1o`
`[error] => UPLOAD_ERR_OK (= 0)`
`[size] => 123 (the size in bytes)`
`)`

`[file2] => Array`
`(`
`[name] => MyFile.jpg`
`[type] => image/jpeg`
`[tmp_name] => /tmp/php/php6hst32`
`[error] => UPLOAD_ERR_OK`
`[size] => 98174`
`)`
`)`

но `wp_upload_bits($_FILES['files']['name'], null, file_get_contents($_FILES['files']['tmp_name']));` не хочет делать то что мне надо.

Я бы уже сделал аякс калбэком или на чистом пхп вручную, но мучает вопрос именно по этой функции.

Может, дело в хтмл5 в метабоксе?

`<input type="file" id="files" name="files" size="25" multiple="multiple"/>`

Раньше делал вебкитом чтоб папки загружать, но так вообще не пахало, таким же способом удалось создать нужные файлы на сервере (но содержимое туда так и не скопировалось)
#407 #763861
Анон, как работает wp_upload_bits?

А точнее, я знаю как он работает и что он создает на серваке файл и копирует в него контент, вопрос в том чому не работает как должен

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

$_FILES имеет следующий вид

`Array`
`(`
`[file1] => Array`
`(`
`[name] => MyFile.txt`
`[type] => text/plain`
`[tmp_name] => /tmp/php/php1h4j1o`
`[error] => UPLOAD_ERR_OK (= 0)`
`[size] => 123 (the size in bytes)`
`)`

`[file2] => Array`
`(`
`[name] => MyFile.jpg`
`[type] => image/jpeg`
`[tmp_name] => /tmp/php/php6hst32`
`[error] => UPLOAD_ERR_OK`
`[size] => 98174`
`)`
`)`

но `wp_upload_bits($_FILES['files']['name'], null, file_get_contents($_FILES['files']['tmp_name']));` не хочет делать то что мне надо.

Я бы уже сделал аякс калбэком или на чистом пхп вручную, но мучает вопрос именно по этой функции.

Может, дело в хтмл5 в метабоксе?

`<input type="file" id="files" name="files" size="25" multiple="multiple"/>`

Раньше делал вебкитом чтоб папки загружать, но так вообще не пахало, таким же способом удалось создать нужные файлы на сервере (но содержимое туда так и не скопировалось)
>>763862>>764116
#408 #763862
>>763861

Похерил разметку. Бля, как в макабе код оформлять? Раньше же так было вроде.
#409 #763883
Где брать макеты готовых сайтов визиток ?
>>763909
#410 #763909
>>763883
Я двачевал этот вопрос задолго до того как он стал мейнстримом. Годных бесплатных макетов не существует. Можно своровать виндовс, фотошоп, игру престолов, 3 ведьмака - все что угодно, кроме путевых макетов. Максимум что ты найдешь - однотипное вырвиглазное дерьмище из 2007-го года. Даже не трать время.
>>763923
#411 #763923
>>763909
Окей, тогда с чего вообще начать ? самому рисовать в фотошопе потом делать верстку, хотелось бы как то упростить этот вопрос, учитывая бюджет проекта в 5 тыр.
>>763929>>764116
#412 #763929
>>763923
Бери первую попавшуюся парашу и верстай. На досуге дрочи скилл передирания дизайна с джипегов. Шрифты можно вырезать и распознавать, цвета пикать, картинки искать через гугол, пропорции считать на калькуляторе. Может у тебя дар проснется и ты без этой ебатни сможешь рисовать красоту. Годные джипеги проектов ищи на дрибле и бехансе правда тем дебильный поиск. Также можно спамить личку авторам с просьбой поделиться макетом если он не коммерческий. Лучше прикидываясь телкой.
>>763970
#413 #763970
>>763929

Зачем это надо если есть бутстрапы и цмски?
>>763979
#414 #763979
>>763970
Покажи мне куда тыкнуть в бутстрапе чтоб получить ну что-нибудь уровня этого https://www.behance.net/gallery/37276397/FC-Barcelona
>>764033>>764037
29 Кб, 756x363
#415 #764033
>>763979

Да я хуй знает, поищи темку какую-нибудь, авось чего похожего подыщешь.

Не найдется среди бутстраповских поищи в вордпрессовских, там их заебись много и годные очень хорошо настраиваются. Навешай плагинов разных по вкусу и вуаля - твори что хочешь. Добавишь еще каких-нибудь модных ui js фреймворков и пиздец.

Я просто предпологаю что ты врядли на серьёзных типов работаешь, которые понимают как и что за сколько делается, им может и красивой чуть кастомизированной тут и там темки хватить.
>>764062
#416 #764037
>>763979

Но то что ты кинул это как-то слишком.

Тебе типа такого сделать сказали? Если да, то ты наверное очень состоятельный паря.
>>764062
#417 #764062
>>764033
>>764037
Я не тот чел которому что-то заказали. Он спросил совет, где взять макет визитки. Я ему ответил что годный и бесплатный нигде, так как сам закумарился их искать. А тысячи однотипного индусского шлака для вп - где угодно по первой ссылке free template.
>>764116
#418 #764116
>>763532

Список можно захардкодить в конфиге или коде определения языка.

>>763594

Это O(1)

>>763622

никак. Либо не передавать столько либо поменять настрйоки.

>>763806

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

>>763808

там разве пхп не устаревший стоит?

>>763827

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

>>763858

остановить сервис (службу) либо поменять номер порта в конфиге

>>763861

читал доки и код?

>>763923

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

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

Картинки кстати с гугла тоже брать нельзя если они не под свободной лицензией.

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

>>764062

Хороший дизайн может нарисовать только дизайнер. Когда я еще делал сайты, у нас часто были свои макеты от дизайнера, и кстати, довольно хорошие.

Но конечно в 5 тр это никак не уложится.
#418 #764116
>>763532

Список можно захардкодить в конфиге или коде определения языка.

>>763594

Это O(1)

>>763622

никак. Либо не передавать столько либо поменять настрйоки.

>>763806

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

>>763808

там разве пхп не устаревший стоит?

>>763827

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

>>763858

остановить сервис (службу) либо поменять номер порта в конфиге

>>763861

читал доки и код?

>>763923

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

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

Картинки кстати с гугла тоже брать нельзя если они не под свободной лицензией.

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

>>764062

Хороший дизайн может нарисовать только дизайнер. Когда я еще делал сайты, у нас часто были свои макеты от дизайнера, и кстати, довольно хорошие.

Но конечно в 5 тр это никак не уложится.
>>764269
#419 #764269
>>764116

Читал. Судя по всему передают туда $_FILES['file_field']['name'] что есть тоже массив имен прикрепленных файлов. Если просто использовать вкупе с html5 input = file multiple на сервере оказывается только последний файл, а не оба.

НО

Может быть я тупой и в функции привязанной к хуку save_post надо сделать как-то в цикле вызов другой функции в зависимости от колличества прикрепленных файлов, ибо я сохраняю мету в бд вордпресса и что-то мне подсказывает, что там должна быть мета одного файла и $id одного только post.

Сейчас там одна функция и один $id я как-то надеялся что все что прикреплено по умолчанию сразу грузится и записывается в мету, но нет.
>>779251
#420 #764420
>>763810

>чистый линукс без интерфейса


Такое реально бывает? Ладно у нас ОП адепт философии "ИНТЕРФЕЙС НИНУЖОН", но я не думал что такое извращение может встретиться в конторах.
>>764444>>764671
#421 #764444
>>764420

> но я не думал что такое извращение может встретиться в конторах


Какое извращение? Это твое рабочее место, ты можешь настроить как тебе удобно. Из командной строки легко ставится x11, туда накатывается гном или кде, остальные пакеты по желанию. Потом для тестирования устанавливаешь апач и последнюю версию пхп с базой. Всё это можно сделать и настроить за минут 30 - 40 при быстром интернете.
#422 #764477
Хелп, только вникаю в консоль, так как я шиндовс блядь. Есть ssh, PuTTY - пытаюсь залить архив на сервер пишу что-то
"scp Local_File username@host:/директория" Проблема в локал файле. Как блядь его правильно указать, D:\papka\test.txt не работает. !Could not resolve hostname D: Name or service not known lost connection! Окей, пишу без D, пишет, что не может найти файл. Как блядь правильно указать путь? Что считается корнем? Папка где PuTTy или Аллах. Файл который нужно залить: D:\programms\test.txt
#423 #764490
>>764477
scp не нужен. Используй Filezilla для этого, у него есть sftp (over ssh) соединение. Только через него всё скачиваю/закачиваю на удалённые сервера
>>764495
#424 #764491
Есть группа сайтов, в общей сумме на ней, допустим, миллиард страниц. Контент страниц лежит в БД (в разных базах одного инстанса MySQL), причем пост отдельно, каменты отдельно. Пока всё это пыхтит и отдаётся за 1-2 секунды. Но если народу станет больше, то конец. На сервере 64 ГБ ОЗУ + 32 SWAP'а. Из них 37.7 ГБ съедает mysql и временные файлы в /dev/shm (kind of key value storage с синхронизацией через rsync на жесткий диск каждые 30 минут). PHP до седьмой версии обновил, стало гораздо быстрее работать (раза в 2-3 по ощущениям).
Страницу полностью я хранить не могу, потому что в зависимости от пользователя там разный интерфейс (хотя это можно обойти, отдавая stub, который через JS на client side'е сам поправит все формы и меню).

Теперь вопрос: как ускорять? Я не могу миллиард страниц хранить в ОЗУ. Завозить нормальный key-value с вытеснением?
>>764593
#425 #764495
>>764490
Знаю, но хотелось бы научиться работать с консолью, я не думаю, что и через консоль сложно залить, значить бы что указать
#426 #764591
>>764477

Тут https://the.earth.li/~sgtatham/putty/0.60/htmldoc/Chapter5.html написано что команда в составе putty назвается pscp, а не scp (scp это та что в линуксе). И написано что надо писать pscp d:\file ...

Но если у тебя работает scp то это наверно команда не из состава путти, а из чего-то другого. Попробуй d:/files или /d/files или просто перейти в папку с файлом и писать не полный путь к нему, а только имя: scp file.txt
#427 #764593
>>764477

> Что считается корнем? Папка где PuTTy или Аллах.


Э? Не понял. Ты наверно спрашивал про то, что считается текущей папкой? В винде она написана в командной строке в подсказке и меняется командой chdir /d d:\files

>>764491

> Я не могу миллиард страниц хранить в ОЗУ


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

Вообще, в твоем случае я думаю надо оптимизировать запросы, ставить индексы. Если это все правильно сделано и все равно скорости не хватает, значит надо либо больше памяти либо больше серверов. либо SSD диски если вдруг ты их не используешь.

Вот ты написал "все пыхтит" но я не вижу даже предварительно анализа. Что тормозит? база медленно отдает ответы? или на строне пхп что-то? Что загружено. а что нет? На сколько процентов загружены ядра, сколько памяти занято, сколько свопа (должно быть немного), какой дисковый трафик?
>>764641>>764851
187 Кб, 707x1000
#428 #764599
Ребята, я вот тут http://ideone.com/jbJBwe переписал задачу >>763547.

Посмотрите пожалуйста. Выводит верно, но можно ли обойтись без вторых регулярок?
>>764645>>764654
#429 #764606
Дорогие аноны, пожалуйста, посоветуйте материалы по прикладному использованию php, ибо синтаксис, основы ООП и т.д. это все просто. Интересует сразу работа с формами (вот например, "как вернуть ответ сервера на ту же страницу, с которой был сделан запрос?"); работа с базами данных; архитектура серверных приложений (как принято связывать все между собой чтобы сделать хоть простенькую систему управления контентом или там магазинчик элементарный).
С хтмл, цсс, джаваскриптом проблем нет. Спс.
>>764617
#430 #764617
>>764606
Задача про студентов из ОП-поста.
#431 #764630
>>764477
cd d:\programms
scp test.txt user@чототаму:/тебя
>>764639
#432 #764639
>>764630
SSH я нахожусь на хосте. Cd у меня будет по хосту, то бишь cd domen.com/www/. А вот путь на локалке я так и не нашел :)
>>764651
#433 #764641
>>764593

> Что считается корнем? Папка где PuTTy или Аллах.


>Э? Не понял. Ты наверно спрашивал про то, что считается текущей папкой? В винде она написана в командной строке в подсказке и меняется командой chdir /d d:\files.


Если я через terminal(ssh) нахожусь уже на сервере(ввел юзернейм, пасс), то там я понимаю где "корень". А вот как с Локальной машины(на моем компе), взять файл и залить туда. Я не знаю как найти эту картинку у себя на пк(путь правильный прописать)
>>764653>>764705
#434 #764645
>>764599
Выводит не верно: http://ideone.com/dZ4uP1
>>764669
#435 #764651
>>764639
Ты с сервера файл с винды хочешь скопирвать, чтоль? Чувак, так не получится.
#436 #764653
>>764641
Ты понимаешь, что на венде не запущен ssh сервер? Его там попросту нет и неизвестно, когда сделают (пилят реализацию). Я уж не говорю о том, что на машине с виндой должен быть либо белы айпи, либо как-то проброшен порт.
Поставь на винду git-sch или как он там называется, в него входит mingw и тогда сможешь делать scp на удалённый сервак
>>764760
879 Кб, 2560x1920
#437 #764654
>>764599
И да: фу таким быть, как ты.
Для кого прежде были советы?
Непонятно.
>>764669
#438 #764655
>>764477

Юзай путти только для комманд на сервере, для файлов юзай файлзилу или любой другой фтп. Не еби себе мозги
>>764760
#439 #764658
У меня вопрос, в профессиональных командах разработки уже не кодят в среде windows ?
>>764660>>764662
#440 #764660
>>764658
Какая разница в какой среде кодить, если код в результате один и тот же?
#441 #764662
>>764658
Где тебе удобно, там и кодь.
Я лично ненавижу линукс на десктопе, например.
Поэтому пишу код под виндой.
С другой стороны, веб-кодеру до лампочки среда, пхп интерпретиеруемый язык и исполняется все равно на сервере.
>>764665>>764666
#442 #764664
Где глянуть примеры правильного использования форм + БД?
>>779251
358 Кб, 406x587
#443 #764665
>>764662
Столкнулся тут с тем, что часто годные мануалы-руководства рассчитаны на Linux.
Вот взять это руководство, например:
<-----
В итоге буду ставить Linux на виртуальном диске.
А ещё буду и nginx изучать - всё равно свой реальный проект на нём буду поднимать, а не на Apache.
#444 #764666
>>764662
Мне просто блевать хочется с windows 10 и его тормозами, хотя у меня не самый слабый ноутбук. Но на мак пока денег нет.
#445 #764667
>>764665
Кстати скоро выходит видеокурс от webformyself по этой теме.
>>764670
#446 #764668
>>764665
Держи нас в курсе.
>>764670
#447 #764669
>>764654
О каких советах идет речь? Перебор for'ом когда есть key в foreach? Как видишь http://ideone.com/mHSVPc тут брать из массива нечего.

>>764645
Верно выводит. Символы, которые может различить человек, не берутся во внимание.
>>764672>>764674
71 Кб, 600x720
#448 #764670
>>764667
Видеокурсов по этой теме, как грязи, а про webformyself впервые слышу.

>>764668
Разумеется!
>>764737
#449 #764671
>>764420
>>763842

Вы утрируете сложность освоения линукса.
Всё, что вам понадобится по работе, изучается за пару дней. Если хотите по-настоящему хорошо разобраться, то в виртуалке пробуете ставить Arch/Gentoo (без шуток). У первого дистрибутива шикарнейшая вики, у второго есть handbook, там тоже всё с азов. Уйдёт максимум пару недель.

Мимо-с-арча
#450 #764672
>>764669

>Символы, которые может различить человек, не берутся во внимание.


Там в "Удмуртской" латиница в каждом похожем символе, не только в заглавной Y.
>>764673
#451 #764673
>>764672
Но не работает именно из-за заглавной Y. Верно все. Таких франкенштейнов никто не будет писать.
>>764679
#452 #764674
>>764669
http://ideone.com/dZ4uP1 - посмотрел ещё раз, там точно "c" стоит, проверяй.
#453 #764678
>>764665
Я не понимаю твоей проблемы. При чем тут руководства? У тебя твои php скрипты должны лежать на сервере под управлением какого-нибудь апача, какая разница, в чем ты набирать код будешь?
Поставь вон virtual box
>>764686
#454 #764679
>>764673
Проверяй-проверяй.
Не работает и с "У" в начале слова.
>>764688
#455 #764680
>>764665
А проявить ТВОРЧЕСКИЙ ПОДХОД?
Ну вот что там например такого Linux-специфического, чего нету вообще под Windows?
>>764686
#456 #764681
>>763810
А про два стула не спрашивают? Что за идиотия.
76 Кб, 700x500
#457 #764686
>>764678
Там всё через консоль Linuxовскую, все команды.
Это просто как пример.

>>764680
Да ничего там специфического. У меня был ноутбук на Убунту - я плевал практически от всего, что там было.
Просто часто красноглазики пишут хорошие книги.
Так-то думаю просто аналогичные команды подыскивать, пока не дошёл ещё до этого руководства, читаю основное руководство по Yii2 на Гитхабе.
>>764689>>764690
#458 #764688
>>764679
Исправил. http://ideone.com/ZulaSV
Добавил "y" маленькое.
>>764700>>764705
#459 #764689
>>764686

>>Там всё через консоль Linuxовскую, все команды.


Это просто как пример.

Да ты траллируешь чтоль? Зашёл по ssh на сервак и вбивай команды, етить колотить.
>>764695
#460 #764690
>>764686
Дефолтная убунта - не линукс, а раздутая донельзя свинья с неудобным окружением рабочего стола. Соберите debian netinstall c легковесным DE/WM, а потом уже делайте выводы.
>>764695
#461 #764695
>>764689
На сервак к себе в локалхост Apache24, азаза?

>>764690
Как раз буду ставить Дебиан - тоже был опыт её использования, был всем доволен.
Выводы я сделал только такие:
1. Замороченные программисты пишут хорошие книги с использованием консоли Linux.
2. Параллельно с cmd.exe надо и консоль Linux изучать.
>>764712
#462 #764700
>>764688
Почему теперь латинскую "O" в "Области" не видит?
Она же есть в регулярке?
http://ideone.com/8LpdaC
>>764725
#463 #764705
>>764641

Та папка, в которой ты оказываешься после логина - это не корень, а просто текущий каталог. Путь к нему можно получить через pwd и потом этот путь вписать в команду scp на винде.

> Я не знаю как найти эту картинку у себя на пк(путь правильный прописать)


А откуда у тебя взялась команда scp на винде? Из какого она пакета программ? В любом случае, я написал, перейди в папку с файлом и тогда тебе не надо указывать полный путь к нему, а достаточно указать только имя файла.

Если что мануал по командной строке есть в ОП посте, стоит почитать.

>>764688

Тут главное понимать что нам достаточно просто искать слова, содержащие буквы разных алфавитов, сами буквы перечислять не обязательно.

> \b(([А-ЯЁа-яё]+)([AaBCcEeHKMOoPpTy]+))+([А-ЯЁа-яё]*


Правило слишком сложное. Можно же написать так:

- начало слова, русские буквы, за ними латинская, за ними любые буквы

Для подсветки букв ты по моему сделал какие-то переусложненные выражения. Можно же проще: если у нас русское слово, заменяем в нем любую латинскую букву на такую же в скобках.

Для замены стоит использоваь preg_replace а не preg_match_all, она для поиска.

В общем, попробуй упростить код - там явно есть куда двигаться.
>>764725
#464 #764712
>>764695

>>На сервак к себе в локалхост Apache24, азаза?


Вот же ты долбоеб-то, а
Тебе сказали - поставь виртуальную машину, на неё накати любую ос какая тебе нравится, а на ней запускай апач. Да, азазаза, на локалхосте.
>>764715
#465 #764715
>>764712
У тебя не получится меня затраллить, лалка.
Ведь именно это я и собираюсь сделать - написал именно об этом в самом первом сообщении.
#466 #764716
Как в пхп проверить тип переменной?
>>764751
106 Кб, 692x692
#467 #764725
>>764705

>Для подсветки букв ты по моему сделал какие-то переусложненные выражения. Можно же проще: если у нас русское слово, заменяем в нем любую латинскую букву на такую же в скобках.


Не работает если несколь

>Для замены стоит использоваь preg_replace а не preg_match_all, она для поиска.


Там не замена, а сборка идет.

>В общем, попробуй упростить код - там явно есть куда двигаться.


Ну ОП. Ну некуда же упрощать.
>>764700
Это баг был. Исправил. http://ideone.com/BPGuYs
>>764726>>764760
#468 #764726
>>764725

>Не работает если несколь


Не работает если несколько ошибок в слове.
#469 #764737
>>764670
Согласен, но у них более менее нормальные курсы, лучше чем у "гуру" PHP типа Михаила Русакова, Попова, Geekbrains
#470 #764751
>>764716
Ну же! Бамп
#472 #764754
>>764751
Анус себе бампни, пёс ленивый.
>>764757
#473 #764755
>>764751
Не проще ли посмотреть в мануале чем ждать ответа с сосача ?
http://php.net/manual/ru/function.gettype.php
>>764757
#474 #764757
>>764753
>>764754
Ну и зачем мне что-то делать, если за меня мои ручные песики сделают? >>764755
#475 #764760
>>764725

> Не работает если несколь


Должно работать, посмотри выражение внимательно - оно не запрещает слова с несколькими замененными буквами.

>>Для замены стоит использоваь preg_replace а не preg_match_all, она для поиска.


> Там не замена, а сборка идет.


Там цикл который заменяется одной строчкой с preg_replace

>>764751

gettype, is_integer, is_string, тайп хинты

>>764655

Разобраться полезно. Тем более что в командной строке и скрипты можно писать.

>>764653

По моему ты не понял в чем вопрос. Он на винде запускает клиент scp, а не сервер. Единственное что он не признается откуда он его взял. Ну и не хочет следовать моему совету и перейти в папку с нужным файлом.
#475 #764760
>>764725

> Не работает если несколь


Должно работать, посмотри выражение внимательно - оно не запрещает слова с несколькими замененными буквами.

>>Для замены стоит использоваь preg_replace а не preg_match_all, она для поиска.


> Там не замена, а сборка идет.


Там цикл который заменяется одной строчкой с preg_replace

>>764751

gettype, is_integer, is_string, тайп хинты

>>764655

Разобраться полезно. Тем более что в командной строке и скрипты можно писать.

>>764653

По моему ты не понял в чем вопрос. Он на винде запускает клиент scp, а не сервер. Единственное что он не признается откуда он его взял. Ну и не хочет следовать моему совету и перейти в папку с нужным файлом.
>>764768
#476 #764761
А можно выложить на проверку страничку с одним полем ввода? Суть в том, чтобы внести данные в бд, но у меня не выходит, получаю ошибку:

>Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '0' for key 'PRIMARY'' in C:\OpenServer\domains\test.local\conf\Mapper.php:19 Stack trace: #0 C:\OpenServer\domains\test.local\conf\Mapper.php(19): PDOStatement->execute() #1 C:\OpenServer\domains\test.local\index.php(15): Mapper->addName(Object(Name)) #2 {main} thrown in C:\OpenServer\domains\test.local\conf\Mapper.php on line 19

>>764767
#477 #764767
>>764761
Хм, смотрю на свою же ошибку и думаю может сделать столбец таблицы автоинкрементным?
>>764772
3770 Кб, Webm
65 Кб, 1280x720
#478 #764768
>>764760

>Должно работать


Но не работает. Пройдено. http://ideone.com/jicK9b

>Там цикл который заменяется одной строчкой с preg_replace


Но не работает. Пройдено. http://ideone.com/jicK9b
>>764858
#479 #764772
>>764767
Да, очистил табличку, сделал столбец id автоинкрементным и все заработало. Правильно сделал или это костыль?
>>764859
99 Кб, 1261x876
30 Кб, 585x828
#480 #764851
>>764593

> Не очень понимаю, зачем ты там сделал самодельный кеш на shm когда есть редис умеющий сохранять данные (правда он и память ест)


Понимаешь, редиску надо было учить. А самодельный key value storage через file_get_contents / file_put_contents и файловые мьютексы через flock было написать достаточно быстро. Вот когда я вдруг задумался о написании своего kv, который будет висеть в памяти, я понял, что какой-то ад творю и реально надо лучше редиску покурить.

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


Оптимизировано

> либо SSD диски если вдруг ты их не используешь


Нет, не использую. Был выбор между не помню чем и SSD. Выбрал не помню что

> база медленно отдает ответы?


Медленно их обрабатывает (потому что их много параллельных), но всё в индексах, проверял через explain. Точнее, так было раньше, потом я переехал на 5.7, и сейчас в процессах пусто (кроме реплики-слейва).

> или на строне пхп что-то?


Пых мне говорит (через профайлинг), что обработка (вплоть до единственного реального echo) идёт 280-500 мс. Хром уверяет, что прошло ~900 мс. Я знаю, что часть latency уходит на прокси (запрос идёт к одному серверу (с кучей IP), а он через proxy_pass на реальный сервер) и с этим ничего не сделаешь.

> На сколько процентов загружены ядра


> сколько памяти занято


прикрепил

> сколько свопа (должно быть немного)


все 4 гб это как раз kv в /dev/shm

> какой дисковый трафик?


Прикрепил iostat 5 вторым файлом

пасибки, что ответил
>>764858
https://github.com/applejacky/tmp #481 #764853
>>755118

>>747986



> Попытался сделать DI-контейнер похожим на Pimple, до сих пор не знаю, хорошая ли это идея;


Гм, а почему бы тогда сразу pimple и не взять?

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


Вообще мне не очень нравятся сессии. например, они общие для нескольких вкладок браузера. В твоем случае "одноразовые сообщения" могут сгенерироваться в одной влкадке и отобразиться в другой при неудачном стечении обстоятельств, а также потеряться при перезагрузке станицы. На мой взгляд, удобнее их делать через GET-параметр в URL, хотя можно наверно и сессии оставить.

> Как обойтись без isset в шаблонах - не знаю


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

> В валидаторе студента 2 метода: validate и checkEmailUnique. Их пришлось разделить так как в случае с обновлением данных проверять email на уникальность не нужно.


Вообще-то при обновлении тоже надо проверять. Иначе человек заменит email на уже существующий у другого студента.

> В модели студента есть поля password и passwordHash. В БД есть только второе, первое добавлено в модель, чтобы удобнее было валидировать всего студента, а не передавать переменную password отдельно.


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

Также, ты можешь сделать объект "форма редактирования" и в него положить студента + дополнительные поля. Или просто передавать их отдельно.

https://github.com/applejacky/students/blob/master/dump.sql#L8

> `group_name` text NOT NULL,


> `salt` text NOT NULL,


Почему TEXT? Имя группы может содержать до 65535 символов? Зато email ограничен 40 символами.

https://github.com/applejacky/students/blob/master/app/Lib/ExceptionHandler.php#L13

> public function handleError ($errno, $errstr) {


> echo "<b>Error:</b> [$errno] $errstr<br>"


Ты делаешь странные вещи. Во-первых, php из коробки умеет выводить тексты ошибок. Зачем повторять этот функционал, только теряя при этом название файла и номер строки? Более того, php по умолчанию логгирует ошибки в лог - твой код нет, php позволяет управлять выводом ошибок на экран через параметр в php.ini - твой код нет. И вдобавок выводишь пользователю непонятную надпись на английском языке.

Если ты хочешь писать обработчик ошибок, ты должен сначала разобраться в том как эта система сделана в php.

Но даже если взять тот обработчик ошибок, что встроен в php, он абсолютно неправильный. Кто в здравом уме будет при ошибке продолжать выполнение программы? Ошибка это ошибка, ее надо исправлять, а не притворяться что все нормально. Разработчики php (как и bash который поступает так же) которые когда-то эту систему сделали, сами толком не понимали как обрабатвать ошибки.

Единственный правльный вариант обработки ошибок - это выбрасывать исключение. Так сделано в Яве, Питоне и других языках. Это соответствует принципу fail fast.

Обработчик исключений тоже реализован некорреткно. Они не пишутся в лог и в итоге ты о них не узнаешь.

> <?php namespace App\Lib;


namespace надо писать на новой строке

https://github.com/applejacky/students/blob/master/public/index.php#L3

> ini_set('display_errors', 1);


Это надо писать в php.ini и разумеется отключать на боевом сервере

> require_once dirname(__DIR__) . '/vendor/autoload.php';


> use App\Lib\Request;


use должны идти раньше чем любой код кроме namespace

Тут https://github.com/applejacky/students/blob/master/public/index.php#L52 и тут https://github.com/applejacky/students/blob/master/util/StudentTableSeeder.php#L16 у тебя повторяется код создания объекта PDO. Нехорошо. У тебя должен быть бустрап-файл и его идея в том, что ты можешь подключить его и получить полностью настроенное окружение, со всеми нужными сервисами, а не копипастить код инициализации по нескольким файлам.

https://github.com/applejacky/students/blob/master/app/Lib/Request.php#L15

> switch ($method)


> case 'GET':


> $queryArray = $_GET;


> case 'POST':


Существуют другие методы например HEAD. Массивы $_POST и $_GET существуют независимо и могут быть заполнены оба в некоторых случаях.

https://github.com/applejacky/students/blob/master/app/Routing/Route.php#L39

> $placeholderInArray = key($placeholderRegexArray); // Получить первый ключ массива


> $regexRuleInArray = reset($placeholderRegexArray); // Получить первое значение массива


Как-то странно что передается массив и исопльзуется только первый элемент.

https://github.com/applejacky/students/blob/master/app/Routing/RouteRequestMatcher.php#L19

> $placeholder = key($route->placeholderRegex); // Первый ключ массива


> $ruleRegex = reset($route->placeholderRegex); // Первое значение массива


Опять же, вот это странно как-то выглядит, если ты используешь 1 элемент массива, почему не сделать 2 отдельных поля вместо массива?

И кстати, почему ты не сделал просто метод match(Request) в классе Route?

Насчет классов Request, Route - они подозрительно напоминают классы из компонентов Симфони. Может лучше было оттуда их и взять?

https://github.com/applejacky/students/blob/master/app/Routing/RouteRequestMatcher.php#L13

> if () {


> много кода


> }


Не стоит делать такие гигантские ифы. Лучше перевернуть условие и сделать

> if () {


> continue;


>}


>много кода



https://github.com/applejacky/students/blob/master/app/Routing/RouteRequestMatcher.php
Этот класс вообще странно спроектирвоан. Почему match не возвращает результат роутинга сразу, а возвращает просто true/false? Также, класс сработает некорректно если match вызвать несколько раз подряд:

$matcher->match('/');
$matcher->match('/sdadasdadad');
$matcher->getMatchedRoute() -> вернет результат для /, а не для последнего вызова

Роутер почему-то не позволяет использовать больше 1 параметра в URL. Ну может в этой задаче это и не требуется, конечно.
https://github.com/applejacky/tmp #481 #764853
>>755118

>>747986



> Попытался сделать DI-контейнер похожим на Pimple, до сих пор не знаю, хорошая ли это идея;


Гм, а почему бы тогда сразу pimple и не взять?

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


Вообще мне не очень нравятся сессии. например, они общие для нескольких вкладок браузера. В твоем случае "одноразовые сообщения" могут сгенерироваться в одной влкадке и отобразиться в другой при неудачном стечении обстоятельств, а также потеряться при перезагрузке станицы. На мой взгляд, удобнее их делать через GET-параметр в URL, хотя можно наверно и сессии оставить.

> Как обойтись без isset в шаблонах - не знаю


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

> В валидаторе студента 2 метода: validate и checkEmailUnique. Их пришлось разделить так как в случае с обновлением данных проверять email на уникальность не нужно.


Вообще-то при обновлении тоже надо проверять. Иначе человек заменит email на уже существующий у другого студента.

> В модели студента есть поля password и passwordHash. В БД есть только второе, первое добавлено в модель, чтобы удобнее было валидировать всего студента, а не передавать переменную password отдельно.


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

Также, ты можешь сделать объект "форма редактирования" и в него положить студента + дополнительные поля. Или просто передавать их отдельно.

https://github.com/applejacky/students/blob/master/dump.sql#L8

> `group_name` text NOT NULL,


> `salt` text NOT NULL,


Почему TEXT? Имя группы может содержать до 65535 символов? Зато email ограничен 40 символами.

https://github.com/applejacky/students/blob/master/app/Lib/ExceptionHandler.php#L13

> public function handleError ($errno, $errstr) {


> echo "<b>Error:</b> [$errno] $errstr<br>"


Ты делаешь странные вещи. Во-первых, php из коробки умеет выводить тексты ошибок. Зачем повторять этот функционал, только теряя при этом название файла и номер строки? Более того, php по умолчанию логгирует ошибки в лог - твой код нет, php позволяет управлять выводом ошибок на экран через параметр в php.ini - твой код нет. И вдобавок выводишь пользователю непонятную надпись на английском языке.

Если ты хочешь писать обработчик ошибок, ты должен сначала разобраться в том как эта система сделана в php.

Но даже если взять тот обработчик ошибок, что встроен в php, он абсолютно неправильный. Кто в здравом уме будет при ошибке продолжать выполнение программы? Ошибка это ошибка, ее надо исправлять, а не притворяться что все нормально. Разработчики php (как и bash который поступает так же) которые когда-то эту систему сделали, сами толком не понимали как обрабатвать ошибки.

Единственный правльный вариант обработки ошибок - это выбрасывать исключение. Так сделано в Яве, Питоне и других языках. Это соответствует принципу fail fast.

Обработчик исключений тоже реализован некорреткно. Они не пишутся в лог и в итоге ты о них не узнаешь.

> <?php namespace App\Lib;


namespace надо писать на новой строке

https://github.com/applejacky/students/blob/master/public/index.php#L3

> ini_set('display_errors', 1);


Это надо писать в php.ini и разумеется отключать на боевом сервере

> require_once dirname(__DIR__) . '/vendor/autoload.php';


> use App\Lib\Request;


use должны идти раньше чем любой код кроме namespace

Тут https://github.com/applejacky/students/blob/master/public/index.php#L52 и тут https://github.com/applejacky/students/blob/master/util/StudentTableSeeder.php#L16 у тебя повторяется код создания объекта PDO. Нехорошо. У тебя должен быть бустрап-файл и его идея в том, что ты можешь подключить его и получить полностью настроенное окружение, со всеми нужными сервисами, а не копипастить код инициализации по нескольким файлам.

https://github.com/applejacky/students/blob/master/app/Lib/Request.php#L15

> switch ($method)


> case 'GET':


> $queryArray = $_GET;


> case 'POST':


Существуют другие методы например HEAD. Массивы $_POST и $_GET существуют независимо и могут быть заполнены оба в некоторых случаях.

https://github.com/applejacky/students/blob/master/app/Routing/Route.php#L39

> $placeholderInArray = key($placeholderRegexArray); // Получить первый ключ массива


> $regexRuleInArray = reset($placeholderRegexArray); // Получить первое значение массива


Как-то странно что передается массив и исопльзуется только первый элемент.

https://github.com/applejacky/students/blob/master/app/Routing/RouteRequestMatcher.php#L19

> $placeholder = key($route->placeholderRegex); // Первый ключ массива


> $ruleRegex = reset($route->placeholderRegex); // Первое значение массива


Опять же, вот это странно как-то выглядит, если ты используешь 1 элемент массива, почему не сделать 2 отдельных поля вместо массива?

И кстати, почему ты не сделал просто метод match(Request) в классе Route?

Насчет классов Request, Route - они подозрительно напоминают классы из компонентов Симфони. Может лучше было оттуда их и взять?

https://github.com/applejacky/students/blob/master/app/Routing/RouteRequestMatcher.php#L13

> if () {


> много кода


> }


Не стоит делать такие гигантские ифы. Лучше перевернуть условие и сделать

> if () {


> continue;


>}


>много кода



https://github.com/applejacky/students/blob/master/app/Routing/RouteRequestMatcher.php
Этот класс вообще странно спроектирвоан. Почему match не возвращает результат роутинга сразу, а возвращает просто true/false? Также, класс сработает некорректно если match вызвать несколько раз подряд:

$matcher->match('/');
$matcher->match('/sdadasdadad');
$matcher->getMatchedRoute() -> вернет результат для /, а не для последнего вызова

Роутер почему-то не позволяет использовать больше 1 параметра в URL. Ну может в этой задаче это и не требуется, конечно.
>>767005
https://github.com/applejacky/tmp #482 #764855
>>755118

>>747986



> BadMethodCallException(sprintf('В классе "%s" не существует действия "%s".


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

https://github.com/applejacky/students/blob/master/app/Lib/DiContainer.php#L7

> public function offsetExists($offset)


Для контейнеров есть PSR с описанием интерфейса и там описан метод get(), а тебя его нет.

Контейнер реализован неправильно. При повторном обращении надо возвращать ранее созданный экземпляр сервиса, а не создавать новый.

https://github.com/applejacky/students/blob/master/app/Lib/DiContainer.php#L23

> if (is_callable($value)) {


Тут надо использовать тайп хинт callable

https://github.com/applejacky/students/blob/master/app/Lib/Response.php#L69

> public function sendHeaders()


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

https://github.com/applejacky/students/blob/master/app/Controller/Controller.php#L19

> require_once dirname(__DIR__) . '/functions.php';


У нас же ООП, используй класс со статическими методами

https://github.com/applejacky/students/blob/master/app/Controller/Controller.php#L23
тут не сделана обработка исключений в процессе вывода шаблона. У тебя все, что успело вывестись, вывалится на экран.

https://github.com/applejacky/students/blob/master/app/Controller/StudentController.php#L19

> if ($recordsPerPage > $recordsCount) {


> $recordsPerPage = 5;


> }


Логика немного непонятна. тут нет ошибки?

> $students = $this->studentMapper->findAllWith($search, $sortBy, $order, $page, $recordsPerPage);


Универсальнее передавать offset, а не номер страницы. А так ты возлагаешь функцию пагинации на маппер.

https://github.com/applejacky/students/blob/master/app/Controller/StudentController.php#L38

> if (is_null($this->studentMapper->findById($id))) {


> return $response->withRedirect('/', "Студент с id {$id} не найден");


> };


для случаев когда страница не найдена есть специальный HTTP код 404. Редирект обычно исплоьзуется когда страница переехала по другому адресу или после ПОСТ запроса. Не стоит его ставить всегда.

https://github.com/applejacky/students/blob/master/app/Controller/FormController.php
лучше сделать как описано в моему алгоритме работы с формами. Вместо 4 однотипных методов, для форм регистрации и редактирования достаточно одного общего метода.

> if (is_null($student)) {


> return $response->withRedirect('/');


> }


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

https://github.com/applejacky/students/blob/master/app/Controller/FormController.php#L119

> $errors = $this->studentValidator


> ->validate($student)


> ->getAllErrors();


тут лучше вернуть ошибки сразу. Почему у тебя одна функция для проверки, а другая для возврата результата? Это вообще не очень удачная идея, так как надо знать в каком порядке вызвать функции, если его перепутать, можно получить не те данные.

https://github.com/applejacky/students/blob/master/app/Database/AbstractMapper.php#L69

> return static::mapObject($result);


mapObject - не статическая функция, а ты ее вызываешь как статическую.

https://github.com/applejacky/students/blob/master/app/Database/AbstractMapper.php#L97

> public function __destruct()


> {


> $this->pdo = null;


Этот метод не требуется.

$table лучше сделать не статическим полем, а абстрактным методом.

https://github.com/applejacky/students/blob/master/app/Database/StudentMapper.php#L72

> LIMIT {$start}, {$recordsPerPage}


Тут SQL инъекция по моему

https://github.com/applejacky/students/blob/master/app/Exception/ClassNotFoundException.php#L7
Непонятно что тут делает ucfirst

https://github.com/applejacky/students/blob/master/app/Helper/Auth.php#L72
Непонятно почему при разлогинивании стирается CSRF токен и почему с ним работает класс авторизации, а не класс отвечающий за CSRF. Явно нарушение инкапсуляции.

https://github.com/applejacky/students/blob/master/app/Helper/Csrf.php#L21
Тут токену не продлевается время жизни если он уже есть

https://github.com/applejacky/students/blob/master/app/Helper/StringGenerator.php#L18
Не очень понятно почему этот метод тут, а не в классе авторизации.

https://github.com/applejacky/students/blob/master/app/Helper/Auth.php#L39
Метод регистрации на мой взгляд сделан не универсально. Что если мы хотим зарегистрировать студента не ставя кук или из консоли?

Тут https://github.com/applejacky/students/blob/master/app/View/form/index.phtml надо добавить HTML5 валидацию. Объект Student удобнее передавать всегда, а не делать кучу isset.

https://github.com/applejacky/students/blob/master/app/View/student/index.phtml#L6

> ", удовлетворяющие запросу {$search}, "


Тут xss по моему
https://github.com/applejacky/tmp #482 #764855
>>755118

>>747986



> BadMethodCallException(sprintf('В классе "%s" не существует действия "%s".


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

https://github.com/applejacky/students/blob/master/app/Lib/DiContainer.php#L7

> public function offsetExists($offset)


Для контейнеров есть PSR с описанием интерфейса и там описан метод get(), а тебя его нет.

Контейнер реализован неправильно. При повторном обращении надо возвращать ранее созданный экземпляр сервиса, а не создавать новый.

https://github.com/applejacky/students/blob/master/app/Lib/DiContainer.php#L23

> if (is_callable($value)) {


Тут надо использовать тайп хинт callable

https://github.com/applejacky/students/blob/master/app/Lib/Response.php#L69

> public function sendHeaders()


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

https://github.com/applejacky/students/blob/master/app/Controller/Controller.php#L19

> require_once dirname(__DIR__) . '/functions.php';


У нас же ООП, используй класс со статическими методами

https://github.com/applejacky/students/blob/master/app/Controller/Controller.php#L23
тут не сделана обработка исключений в процессе вывода шаблона. У тебя все, что успело вывестись, вывалится на экран.

https://github.com/applejacky/students/blob/master/app/Controller/StudentController.php#L19

> if ($recordsPerPage > $recordsCount) {


> $recordsPerPage = 5;


> }


Логика немного непонятна. тут нет ошибки?

> $students = $this->studentMapper->findAllWith($search, $sortBy, $order, $page, $recordsPerPage);


Универсальнее передавать offset, а не номер страницы. А так ты возлагаешь функцию пагинации на маппер.

https://github.com/applejacky/students/blob/master/app/Controller/StudentController.php#L38

> if (is_null($this->studentMapper->findById($id))) {


> return $response->withRedirect('/', "Студент с id {$id} не найден");


> };


для случаев когда страница не найдена есть специальный HTTP код 404. Редирект обычно исплоьзуется когда страница переехала по другому адресу или после ПОСТ запроса. Не стоит его ставить всегда.

https://github.com/applejacky/students/blob/master/app/Controller/FormController.php
лучше сделать как описано в моему алгоритме работы с формами. Вместо 4 однотипных методов, для форм регистрации и редактирования достаточно одного общего метода.

> if (is_null($student)) {


> return $response->withRedirect('/');


> }


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

https://github.com/applejacky/students/blob/master/app/Controller/FormController.php#L119

> $errors = $this->studentValidator


> ->validate($student)


> ->getAllErrors();


тут лучше вернуть ошибки сразу. Почему у тебя одна функция для проверки, а другая для возврата результата? Это вообще не очень удачная идея, так как надо знать в каком порядке вызвать функции, если его перепутать, можно получить не те данные.

https://github.com/applejacky/students/blob/master/app/Database/AbstractMapper.php#L69

> return static::mapObject($result);


mapObject - не статическая функция, а ты ее вызываешь как статическую.

https://github.com/applejacky/students/blob/master/app/Database/AbstractMapper.php#L97

> public function __destruct()


> {


> $this->pdo = null;


Этот метод не требуется.

$table лучше сделать не статическим полем, а абстрактным методом.

https://github.com/applejacky/students/blob/master/app/Database/StudentMapper.php#L72

> LIMIT {$start}, {$recordsPerPage}


Тут SQL инъекция по моему

https://github.com/applejacky/students/blob/master/app/Exception/ClassNotFoundException.php#L7
Непонятно что тут делает ucfirst

https://github.com/applejacky/students/blob/master/app/Helper/Auth.php#L72
Непонятно почему при разлогинивании стирается CSRF токен и почему с ним работает класс авторизации, а не класс отвечающий за CSRF. Явно нарушение инкапсуляции.

https://github.com/applejacky/students/blob/master/app/Helper/Csrf.php#L21
Тут токену не продлевается время жизни если он уже есть

https://github.com/applejacky/students/blob/master/app/Helper/StringGenerator.php#L18
Не очень понятно почему этот метод тут, а не в классе авторизации.

https://github.com/applejacky/students/blob/master/app/Helper/Auth.php#L39
Метод регистрации на мой взгляд сделан не универсально. Что если мы хотим зарегистрировать студента не ставя кук или из консоли?

Тут https://github.com/applejacky/students/blob/master/app/View/form/index.phtml надо добавить HTML5 валидацию. Объект Student удобнее передавать всегда, а не делать кучу isset.

https://github.com/applejacky/students/blob/master/app/View/student/index.phtml#L6

> ", удовлетворяющие запросу {$search}, "


Тут xss по моему
>>767005
#483 #764858
>>764768

> Но не работает. Пройдено.


Ты ведь сделал не так, как я написал. по прежнему регулярка переусложнена и ее можно упростить.

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

>>764851

> . А самодельный key value storage через file_get_contents / file_put_contents и файловые мьютексы через flock было написать достаточно быстро.


Он может быть в итоге бутылочным горшылком. Блокировки например не позволяют параллельно его использовать.

Судя по скриншоту у тебя большинство ядер не нагружено. Там и нагрузки-то серьезной не видно. На диск тоже нет нагрузки никакой.

> Пых мне говорит (через профайлинг), что обработка (вплоть до единственного реального echo) идёт 280-500 мс.


Посмотри тогда еще профайлером какие именно функции сколько выполняются. На что уходят эти 500 мс. Или можешь натыкать echo с выводом прошедшего времени. opcache кстати настроен?
>>764866>>764937
#484 #764859
>>764772

ты должен либо передавать id либо использовать автоинкремент.
#485 #764866
>>764858

> Блокировки например не позволяют параллельно его использовать


При чтении там flock set, file_get_contents, flock release. Если туда никто не писал, это должно быть очень быстрым. И, да, я замерял чисто свой kv, и на запись и на чтение параллельно во много процессов. Дело не в нём, он вполне быстрый (только fopen делает, а это само по себе долго, даже если tmpfs)

> Посмотри тогда еще профайлером какие именно функции сколько выполняются


Уже смотрел. Много времени уходит на ob. То есть на
[CODE]
<?php
$ts=[microtime(true)];
ob_start();
$ts[]=microtime(true);
for ($i=0;$i<1000;$i++){
echo mt_rand(0,10000)."\n";
}
$ts[]=microtime(true);
$buf=ob_get_contents(); // Здесь ~300 килобайт в живом коде
$ts[]=microtime(true);
ob_end_clean();
[/CODE]
Вот очень много (~150-170) уходит на ob_get_contents. Уж не знаю с чем это связано. С иммутабельными строками или что там под капотом.

Вообще я забыл сказать, что часть своих профилирований я делал ещё на php 5.6, а после того как переехал на php 7, стало не хватать времени

> opcache кстати настроен?


Я не знаю почему, но он не настроен был из коробки. Я неделю назад его поставил руками и стало ещё шустрее. Вот сейчас у меня как раз 300-500 мс на выполнение кода, а раньше (на php 5.6) там могла быть целая секунда. Но не факт, что дело в PHP. У меня в MySQL 5.5 постоянно висели insert delayed, которые спаунились самописным писателем логов запросов к веб-страницам в memory таблицу mysql (откуда потом отдельный скрипт всё перекладывал в нормальную таблицу. insert delayed доступен только для memory), после переезда на 5.7 они все пропали, видимо код в mysql переписали.
#486 #764891
Совсем запутался. Допустим, у меня есть меппер, в котором есть функция, которая срабатывает по кнопке:
[CODE]
public function getDatetime($ch)
{
$STH = $this->DBH->prepare("SELECT datetime FROM mainTable WHERE ch = :ch");
$STH->bindValue(":ch", $ch);
$STH->execute();
}
[/CODE]
Мне нужно взять значение переменной $ch из инпута. КАК? Я просто уже ничего не понимаю.
>>764905>>764915
#487 #764905
>>764891
$inputCh = $_POST["ch"];
getDatetime($inputCh);

"ch" - имя элемента в HTML форме, задавать через аттрибут name. http://www.w3schools.com/tags/att_input_name.asp
Так же, почитай урок ОПа про обработку форм https://github.com/codedokode/pasta/blob/master/forms.md
>>764908
#488 #764908
>>764905
Но у меня тут маняООП, в этом вся проблема.
>>764915
#489 #764915
>>764908
>>764891
С этим разобрался. Пиздец какой-то, честно говоря...
#490 #764916
>>764866
Вообще я придумал такую систему:
1. nginx кеширует по URL'у
2. PHP отдаёт stub без управляющих элементов, которые появляются, если пользователь залогинился
3. Страница после загрузки обращается через json к PHP, который отдаёт данные. JS меняет элементы, перерисовывает всякую херню и так далее. Таким образом всем отдаётся один контент
4. Если к странице обращается админ, то PHP выдаёт конкретное поле в хидерах, увидев которое, nginx не кеширует эту страницу (там управляющие элементы только для админа сайта, например, удаление камента). Также nginx не кеширует, если обращение сделал бот Гугла/Яндекса (по IP или по User-Agent'у)
5. Страница хранится в памяти nginx в течение N времени

Вы не подскажете, можно ли nginx (без lua-скриптов) настроить так, чтобы он, увидев, что к какому-то урлу обращаются часто (более N раз за L времени), страницу хранил дольше других? Например, просто страницу хранить 90 минут. А к этой странице за час обратились уже 5 раз, её мы сохраним на день.
И можно ли как-то девалидировать запиши в кеше nginx'а (на такой-то странице, например, появился новый комментарий, а значит контент должен уходить другой)?
>>779251
49 Кб, 1280x720
#491 #764937
>>764858

>Ты ведь сделал не так, как я написал.


Исправил все http://ideone.com/BPGuYs

По регуляркам куча материала осталась. Про то как их составлять. Изучить это или можно двигаться дальше?
>>766014>>779252
#492 #764951
Памагити!

Это index.php: http://ideone.com/kCtER4
Это mapper.php: http://ideone.com/dFlDK6

Почему строка <p><?php count($timers); ?></p> ничего не возвращает, хотя таймеров в таблице четыре штуки?
>>764956>>779252
#493 #764956
>>764951
Уточню, что var_dump($timers) возвращает NULL
61 Кб, 700x375
#494 #764965
А есть код, который замазан на пикче? Очень-очень хочется посмотреть как там в 8 строк все упаковано.
#495 #765051
Учитывая, что я тупой и не понял нагугленного, прошу очень маленький пример для моего случая. Есть переменная в php, а я ее хочу передать в javascript. В гугле советуют аякс, но я и правда не понял, мне достаточно будет примера, чтобы все дошло:

<?php
$val = $myClass->getValue();
?>
<script>
myPlugin.start($val);
</script>

Заранее благодарю.
>>765057>>765071
#496 #765057
>>765051
var number = <?php echo $variable ?>;
>>765060>>765079
#497 #765060
>>765057
Не робит(
Отдельно <?php echo $variable ?> работает, а в джаваскрипте нит.
>>765067
#498 #765067
>>765060
Быть такого не может. Переменная точно существует?
>>765068
7 Кб, 706x114
#499 #765068
>>765067
Конечно, я же говорю - переменная печатается вне джаваскрипта, а внутри вот что консолька говорит
>>765070>>765250
#500 #765070
>>765068
Код покажи
>>765074
#501 #765071
>>765051
<div id='lol' data-val=<?php echo $val; ?>>
<script>
var val = $('#lol').attr('data-val')
</script>
>>765090
#503 #765076
>>765074
<?php echo должно быть в кавычках
>>765079
#504 #765077
>>765074
$cst выше раскомментируй, например.
>>765079
#505 #765079
>>765077
Ебанутый? У меня переменная меняется, например. Первый скрин смотри.

>>765076
Што? Я скопировал так, как мне здесь подсказали >>765057
>>765081
#506 #765081
>>765079
Ну значит я неправильно подсказал, заключай в кавычки и не задавай лишних вопросов.
>>765086
2 Кб, 277x39
#507 #765086
>>765081
Мне кажется, ты меня траллируешь. Да, плохо знаю веб, и возможно выгляжу смешно
>>765088>>765090
#508 #765088
>>765086
Ну не так же. Мне что нужно писать подробно? Окей
"<php echo $cst ?>"
>>765097
#509 #765090
>>765086
он тебя троллит. ты получишь строку и больше ничего. делай как батя сказал: >>765071
>>765097
1 Кб, 311x43
#510 #765097
>>765088
Не заработало.

>>765090
Вот это заработало, благодарю, буду пользовать. Но что-то мне подсказывает, что это просто пиздец какой костыль. Припекло с того, что теперь это отображается в сурсах
#511 #765099
>>765097

>Но что-то мне подсказывает, что это просто пиздец какой костыль.


Так и есть. По хорошему надо было аяксом делать запрос на отдельную страницу и получать оттуда то что тебе нужно.
#512 #765100
>>765097
Да как оно могло не заработать? Это ответ с первой ссылки на стаковерфлоу. Я сам почти так же делал, только через шаблонизатор твиг.
>>765250
#513 #765102
>>765097
да я пошутил, конечно это костыль. то решение должно заработать, или как альтернатива
<?php
echo "<script> var val=".$val."</script>";
?>
>>765104>>765250
#514 #765104
>>765102
Во, это уже лучше. Хоть нигде не палится.
#515 #765106
>>765097
а вообще ты что-то неправильно делаешь. для js есть один кошерный способ получить что-то от сервера - ajax. что это за данные? если они отображаются на странице то лучше парсить html, а не такой ерундой страдать.
>>765108>>765250
#516 #765108
>>765106
Я так и понял, изначально думал, что мне как раз с аяксом помогут.

Сама страничка - набор таймеров для разных событий.
#517 #765117
в jquery это проще простого.
$.ajax({
type: 'POST',
url: 'script.php',
data: 2,
success: function(response) { console.log(response)} //выведет 4
});
--------------
<?php
var input = $_POST;
echo 2*input;
?>
могу обосраться с преобразованием типов обычно передают не примитивы а json-объект, но идею ты понел
#518 #765121
>>765117

>var input = $_POST;


>echo 2*input;


Умноение массива на два, пиздато
>>765152
#519 #765124
>>765117

>data: 2,


А это по идее запишет в пост по ключу "2" пустое значение, но не уверен, никогда такое говно не писал
#520 #765152
>>765121
ну мне влом было мастерить идеоне и вспоминать, хрен ли ты докопался?
#521 #765250
>>765117
>>765106
>>765102
>>765100
>>765097

Зачем тащить быдлокод из интернета сюда? Если ты не знаешь php или яваскрипт на достаточном уровне то надо их подучить а не копипастить бездумно то, что написал какой-то быдлокодер. Переменая в скрипт подставляется очень просто. Во-первых, не надо смешивать в кучу JS код и вставки PHP, вынеси их отдельно:

var a = ...;
var b = ...;
doSomething(a, b);

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

В-третьих, данные надо экранировать. В данном случае так, чтобы какие бы значения не были в переменной, они не сломали JS код. Тут есть такие варианты:

- intval для чисел
- json_encode для строк, null, булевых знаечний или массивов

>>765068

Исходник страницы посмотреть и увидеть где ошибка ты не можешь?
>>765289>>765293
#522 #765289
>>765250

>var a = ...;


>var b = ...;


>doSomething(a, b);


Это зачем приплел?
>>765250

>Во-вторых, какой аякс? вы поехавшие?


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

Вообще есть 3 варианта передавать данные для инициализации:
1. Подставлять данные напрямую в JS
2. Подгружать данные через аякс.
3. Подставлять данные в разметку.

>>765250

>В-третьих, данные надо экранировать.


Ничего не надо "экранировать".
>>765292
#523 #765292
>>765289

Какие преимущества дает использование аякса для загрузки данных вместо других подходов вроде вставки их в страницу?

> Ничего не надо "экранировать".


Надо иначе можем получить разновидность XSS.
>>765302
#524 #765293
>>765250

>Зачем тащить быдлокод из интернета сюда?


Никакой не быдлокод, а вполне приемлемый метод.

>var a = ...;


>var b = ...;


>doSomething(a, b);


И дальше что? Как ты тут передал данные из php в js?

>создавать лишние запросы на сервер


Что значит лишние? Чувак описал юзкейс - у него на странице таймеры на js, по их срабатыванию необходимо пообщаться с сервером. Это не лишний, а необходимый запрос.
>>765316
#525 #765302
>>765292

>Какие преимущества дает использование аякса для загрузки данных вместо других подходов вроде вставки их в страницу?


Кэширование кода.
Единый стиль получения данных.
>>765315
#526 #765315
>>765302

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

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

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

Недостатки этого подхода: бессмысленное усложнение кода, увеличение нагрузки на сервер, сильное замедление загрузки страницы. То есть для случаев "блог" например это не годится, а годится только для каких-то приложений, которыми пользователь пользуется часто и где он готов терпеть более медленную загрузку данных. В общем, мне кажется это редко когда оправданно.
>>765565
#527 #765316
>>765293

В его примере был echo, то есть вставка данных в страницу его устраивала. про таймеры по моему ты уже придумывать от себя начал.
>>765777
#528 #765329
>>764866

Ты явно путаешь причину. Вот скрипт:

<?php
$ts=[microtime(true)];
ob_start();
$ts[]=microtime(true);
for ($i = 0; $i < 1000; $i++) {
echo str_repeat(" ", 300);
}
$ts[]=microtime(true);
$buf=ob_get_contents(); // Здесь ~300 килобайт в живом коде
$ts[]=microtime(true);
ob_end_clean();
$start = array_shift($ts);

var_dump(strlen($buf));
foreach ($ts as $value) {
var_dump($value - $start);
}

Я запускал его под Windows, на относительно старом железе и он работает меньше 15 мс (на винде точнее не померять через microtime). Выводит ровно 300 000 байт данных. дело не в ob_get_contents. Однако, возможно в твоем приложении устанавливается функция-фильтр которая работает с буферизованными данными. В таком случае, разумеется, все зависит от скорости ее работы. Почитать про нее можно в мануале http://php.net/manual/ru/function.ob-start.php
>>765338
#529 #765330
>>764866

Насчет логов в mysql: почитай в мануале про bulk insert, там есть особые способы ускорить вставку. Например группировать данные и вставлять большими транзакциями.
>>765338
#530 #765338
>>765329
Само собой я знаю про ob-фильтрацию. Я забыл сказать, что этот код тоже внутри своего ob стоит (моя цмска глушит все echo). Но дело именно в строках. Я замерял без echo внутри for i, падало координально. (А может это пыхомагия, которая видела, что return из функции никуда не идёт и просто не делала return строки)

>>765330
Я знаю, что есть куча причин почему надо вставлять много за раз (как минимум пересборка индексов). Но тут концепция такая: один заход на страницу = один insert. Но заходы вещь некритичная, поэтому insert delayed и memory table. Я хотел это переписать (через очередь сообщений, чтобы побыстрее проходило), но теперь insert delayed не висят и причины переписывать пока тоже нет

Вообще надо перезамерить весь код. После переезда на PHP7 там явно до черта изменилось в профайлинге моего кода
>>765369
#531 #765339
>>764965
Судя по иерархии, там только часть кода.
#532 #765369
>>765338

Выполни мой скрипт который я привел выше. Он выводит 300 кб пробелов и на моем core2duo совсем не тормозит. Если он и на сервере у тебя не тормозит то дело не в ob.

>>764965

Там поиск слов одним выражением через preg_match_all и в цикле вывод неправильных слов с подсветкой букв через preg_replace если память мне не изменяет.
>>765388
#533 #765388
>>765369

> Выполни мой скрипт который я привел выше


/delmenow.php:14:int 300000
/delmenow.php:16:float 3.0994415283203E-6
/delmenow.php:16:float 0.00055408477783203
/delmenow.php:16:float 0.00057101249694824

Но это новый пых, на нём я ещё не замерял где же там тормозит
#534 #765565
>>765315
Кэширование на уровне сервера идет.
Аякс не усложняет код. Уменьшает нагрузку на сервер за счет кэширования. Ускоряет загрузку страниц.
>>765585
#535 #765585
>>765565

Вот я зашел из гугла на твой сайт. Как мне кеширование ускорит загрузку страниц?

Ты говоришь что код не усложняет, но это не совсем так. Как минимум тебе надо:

- добавить jquery
- добавить код отправки запроса
- написать код обработки ошибок
>>765598
#536 #765598
>>765585
Давай бороться, я бэрилдан.
#537 #765599
Вернулся из прокрастинации и продолжаю учебу.

Функции и новый айпад :
http://ideone.com/Mw3lr3

Скажите, пишу как монгол ? Как можно было по-другому написать ?
>>765631>>765649
39 Кб, 1218x699
55 Кб, 537x549
#538 #765627
Недавно спрашивал советов мудрых по Yii2.
Братишка посоветовал сначала запилить Студентов.
Ну а я по официальному руководству запилил, по сути, Студентов на самом Yii2 с помощью Gii.
Это обычный CRUD внутри фреймворка, ничего сверхъестественного.
Все скрипты я разобрал, которые генерируются, там всё более-менее понятно даже мне. До этого простое выведение данных из БД делал внутри фреймворка - тоже всё вроде бы понятно.
Так вот вспоминаются слова братишки о том, что всё, что у меня получится без глубокого изучения, это примитивный CRUD и всё не по ООП.
А что не CRUD и что имеется в виду "не по ООП"? Там нет процедурщины, Gii же генерирует, там ООП в основе.
Короче, немного озадачен теми словами и прошу пояснить этот момент, наверняка братишка тут снова и опять.
Просто мне кажется, вы усложняете многое правильным и последовательным подходом, хотя он и правилен и последователен. Я следовал ему как раз до Студентов.
#539 #765631
>>765599
Зачем k++ перед брейк?

И почему and, а не &&?

>>765627
Тебе будет сложно запилить свой большой модуль или действовать в обход фреймворка.
Так же зная основы проще перекатываться по технологиям и хуесосить всех за то что пишут криво.
>>765649
#540 #765633
>>765627

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

В студентах нет ничего сверхестественного, это задача для изучения основ, работы с таблицами, формами, и тд. Суть задачи не в том чтобы получить таблицу студентов, а чтобы узнать паттерны работы с БД, обработки данных форм итд.

> А что не CRUD и что имеется в виду "не по ООП"? Там нет процедурщины, Gii же генерирует, там ООП в основе.


мы код не видели, но насколько я знаю. gii любит генерировать копипасту, если так, то ее надо убрать. Если ты используешь фреймворк, то ООП в фрейморке - модели, формы и тд.
>>765649
#541 #765638
>>765627

Если ты хочешь делать что-то на фреймворке, тебе бы стоило взять задачу посложнее, например, TestHub: https://gist.github.com/codedokode/8733007

Или например можно придумать какую-то задачу, которая потребует не просто использовать стандартные компоненты Юи, а как-то всерьез переопределить их работу. Всякие деревья, сложные валидации, составные формы, нестандартные виджеты и тд.
>>765649
#542 #765649
>>765599
Оформлено плохо, я думал - гораздо лучше будет это всё.

>$k


Ну что это такое?

>>765631

>Зачем k++ перед брейк?


Иначе у него не посчитает правильно месяцы. Там во втором банке 13 месяцев должно быть.

>Тебе будет сложно запилить свой большой модуль или действовать в обход фреймворка.


Возможно, пока не пробовал ведь.

>>765633
Да, там у меня не всё, что нужно, но просто - в общих чертах.

>Суть задачи не в том чтобы получить таблицу студентов, а чтобы узнать паттерны работы с БД, обработки данных форм итд.


Это я понимаю. Ну, ознакомился сейчас с этим на примере генерируемого Gii.

>Если ты используешь фреймворк, то ООП в фрейморке - модели, формы и тд.


Да, там всё так, по ООП.

>>765638
Спасибо, интересная задача, видел пару попыток её решения.

>Время выполнения: все зависит от тебя, но я бы смотрел на 4-6 недель


Вот тут уже не будет жалко времени, спасибо.
Попробую.
24 Кб, 915x119
#543 #765664
В чём может быть ошибка? Через запятые тоже пробовал перечислять названия строк, тоже самое
>>765666>>765668
#544 #765666
>>765664
Есть специальный SQL-оператор для конкатенации. Погугли.

>>765627

>Так вот вспоминаются слова братишки о том, что всё, что у меня получится без глубокого изучения, это примитивный CRUD и всё не по ООП.



Именно так я не писал. Имел в виду, что дальше CRUD'ов не зайдёшь. Задачки, которые по уровню сложности "дальше CRUD'ов", тебе уже вбросили выше.
>>765682
#545 #765668
>>765664

запятых нет. Майскул же пишет перед каким местом ошибка. Алсо почитай

http://phpclub.ru/mysql/doc/string-syntax.html
http://phpclub.ru/mysql/doc/legal-names.html
>>765682
#546 #765682
>>765668

> ​SELECT FROM `students` WHERE `name`,`sname`,`group_num`,`points`,`gender`,`email`,`b_year`,`is_resident` LIKE `%Хи%` ORDER BY `points` asc LIMIT 0 OFFSET 10


Так то же самое

> Алсо почитай


Заменить ` на ' , ты к этому

>>765666
SELECT
FROM `students` WHERE CONCAT(`name`,`sname`,`group_num`,`points`,`gender`,`email`,`b_year`,`is_resident`) LIKE `%Hi%` ORDER BY `points` asc LIMIT 0 OFFSET 10

> Unknown column '%Hi%' in 'where clause'


Походу он смотрит названия колонок, а не их содердимое
>>765686
#547 #765686
>>765682

>LIKE `%Hi%`


> Unknown column '%Hi%' in 'where clause'



Так `%Hi%` это не строка. Попробуй здесь поставить ' вместо символов `
>>765690
129 Кб, 1119x505
#548 #765690
>>765686
Да, точно. Только вот чё он выводит 0 строк, когда их должно быть 4?

что-то у меня сегодня сложно
>>765702>>765710
#549 #765702
>>765690
OFFSET убери, у ОПа в пасте написано "LIMIT 0, 10 можно читать как LIMIT 0 OFFSET 10".
>>765728
#550 #765710
>>765690
И ещё, тебе нужно столбцы перемежать строками с пробелом. Вот так: name, ' ', sname

Представим, что у тебя регистронезависимый поиск и ты ищешь по всем колонкам строку "голова члена". Так как у тебя итоговый CONCAT будет выглядеть как "ГоловачЛенаИТБ[email protected]", эта срока выберется как подходящая.
>>765713>>765728
#551 #765713
>>765710
Не "голова члена", а "член". Извиняюсь, я спать.
#552 #765723
The SQL query below says "return only 10 records, start on record 16 (OFFSET 15)":
$sql = "SELECT FROM Orders LIMIT 10 OFFSET 15";

You could also use a shorter syntax to achieve the same result:
$sql = "SELECT
FROM Orders LIMIT 15, 10";

Странно, а у меня такая же ошибка, как и у анона выше, если использую LIMIT 0 OFFSET 10 вместо LIMIT 0, 10
#553 #765725
>>759665

> Ты представляешь, как делается редирект? Редирект это отдача в качестве ответа кода 3xx и заголовка Location. Редиректить при ошибке, как и при 404 или 403 - неправильно. Вдобавок, в адресной строке браузера теряется УРЛ и обновить страницу нельзя.



А как нужно? include'ом получается коряво. Средствами Apache? Копипаста с инета не работает
>>765728
#554 #765728
>>765702

зачем убирать? с offset же понятнее

>>765710

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

>>765725

Нужно отдавать нужный код и выводить нужную страницу. как ты это будешь делать, стандарт HTTP не волнует.

Посмотри что с адресной строкой бразера при редирректе происходит.
>>765735>>765748
16 Кб, 1366x300
#555 #765735
>>765728
Ну вот смотри что будет при include() в set_exception_handler
Я не знаю как это можно исправить
>>766531
#556 #765748
>>765728

>зачем убирать? с offset же понятнее



Да. Но глянь на скрины.
>>765749
#558 #765765
>>765749

Так limit 0 знаичт не более 0 записей. Что просил то и получил.
#559 #765777
>>765316
echo там в целях дебага, в реальном кейсе его там конечно же нет. И у меня страница и правда с таймерами, я выше уточнял.

>В-третьих, данные надо экранировать.


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

А вообще я всегда открыт для чего-то нового, и если у тебя есть еще какой-то способ передачи переменных, то говори.
#560 #765910
>>763810

>>Как это вообще, влияет на работу


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


Насмотрелся на личностей, гордо именующих себя линуксоидами, так вот, ни один полноценно по профилю не работал в течение двух-трех первых дней, несмотря даже что линукс с интерфейсом. Как с момента устройства на работу, так и с момента апгрейда железа с переустановкой любимой системы. То что-то не заводится, то права на папки блядь, то понос то золотуха, сидит ковыряется под капотом, когда любой виндоёб просто скачивает XAMPP/Денвер и не ебет мозги ни себе, ни окружающим.
>>765915
#561 #765915
>>765910
В офисах может быть проблема с лицензированием Windows и и любого другого платного софта (пакета офис и прочего). Многие из-за этого в офисы ставят только линукс, ну и от кандидатов на работу требуют умения установить и настроить апач с php, поднять базу и прочего.
24 Кб, 294x386
#562 #766014
>>764965
>>764937
Бамп вопросам.
>>766508
#563 #766323
Какой кретин решил засунуть роуты в Kohana Framework в файл bootstrap.php ?
Это что патерн такой? Я 1.5 часа в коде рылся что бы найти, я чего то не понимаю или просто фреймворк хуйня?
>>779252
349 Кб, 1536x2048
#564 #766363
Что почитать про личные кабинеты на Yii2, про RBAC?
Что посоветуете, отцы?
#565 #766444
Ребят, это норма, что общий обработчик ошибок не ловит исключения типа ErrorException?

https://secure.php.net/manual/ru/class.errorexception.php

Здесь код обработчиков: http://pastebin.com/PGitKBtx
Неймспейсы не используются.
>>766467>>770098
#566 #766467
>>766444
А include 'несуществующий_путь' обработчик ловит. Насколько я понял, это связано с уровнем ошибки, которую выбрасывает require, а именно E_COMPILE_ERROR. Из-за этой ошибки скрипт умирает прежде, чем обработчик ошибок перехватывает ошибку.
Гугл советует использовать register_shutdown_function(), но все мои попытки вызвать throw ErrorException внутри неё безуспешны. Может забить на это? Переделываю студентов.
>>767005>>770097
#567 #766508
>>766014
На мое усмотрение там такая куча материала что прифитнее выучить базовые принципы а дальше по надобности открывать шпаргалку в случае заданий.
#568 #766531
>>765735
Напомню про вопрос. Как реализовать показ заглушки при ошибке?
>>770097
#569 #766820
У меня два файла очень схожи по структуре. Эту копипасту можно как-то сократить? А нужно ли?
https://github.com/TheSidSpears/Students/blob/master/app/controllers/edit.php
https://github.com/TheSidSpears/Students/blob/master/app/controllers/register.php

Я вот думал, например это
$token= (isset($_COOKIE['token'])) ? $_COOKIE['token'] : Util::randHash(20);
setcookie('token',$token,time()+3600,'/',null,false,true);

засунуть в ф-ию Util::token(). Но тогда ф-ия будет работать с куками и устанавливать глобальную переменную, что, наверное, не очень правильно
>>767008
99 Кб, 700x525
#570 #766881
Тут много говорилось о каких-то паттернах проектирования в PHP.
Дайте ссылку на ОПа или на нормальный мануал по паттернам, пожалуйста!
>>767069
https://github.com/TheSidSpears/Students #571 #767003

>>748292


>>755118

https://github.com/TheSidSpears/Students/blob/master/students.sql#L31

> `hash` text NOT NULL,


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

https://github.com/TheSidSpears/Students/blob/master/errors.log
Этот файл надо убрать из репозитория, добавив в .gitignore и сделав git rm с нужными флагами

https://github.com/TheSidSpears/Students/blob/master/config.json
Не стоит делать конфиг слишком большим. В конфиг мы выносим то, что будет менять конечный пользователь. Название папки с контроллерами вряд ли имеет смысл менять.

https://github.com/TheSidSpears/Students/blob/master/public/503.php#L1

> header(' ', true, 503);


Что это за синтаксис? Что за пустой заголовок? По моему это не будет работать. Там надо отправлять заголоок вроде HTTP/1.1 503 xxxx, почитай хотя бы мануал по функции header().

> <a href='index.php'>На главную</a>


У тебя URL главной - это index.php или / ? Желательно иметь для одной страницы один УРЛ.

https://github.com/TheSidSpears/Students/blob/master/public/503.php#L11

> $array=file('errors.log');


ЧТо если файл огромный? Это будет медленно и займет много памяти. Ну и не очень понятно, зачем ты вообще выводишь лог для посетителей сайта.

> for ($i=$count-21; $i < $count; $i++) {


А что если в файле меньше 21 строки? Плюс, ты выводишь данные без экранирования и тут явно может быть XSS если HTML код от злоумышлеенника попадет в сообщение в логе. Ты путаешь язык HTML и простой текстовый файл. В HTML некоторые символы имеют специальное знаечние (например < обозначает начало тега) и нельзя просто так выводить произвольный текст.

Кстати, раз ты путаешься с этим, реши-ка задачку на экранирование отсюда (и заодно прочитай сам урок): https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Экранирование

https://github.com/TheSidSpears/Students/blob/master/public/index.php

> chdir ('../')


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

https://github.com/TheSidSpears/Students/blob/master/app/bootstrap.php#L12
А зачем заводить свой собственный лог? Не лучше ли писать в стандартный лог PHP? ты кстати, знаешь, где он находится?

https://github.com/TheSidSpears/Students/blob/master/app/bootstrap.php#L20

> spl_autoload_register(


Тут незачем делать 2 автозагрузчика, проще сделать один, который проверяет разные пути. А еще лучше, конечно, было бы использовать PSR-4 при выборе названий классов и файлов.

https://github.com/TheSidSpears/Students/tree/master/app/models
Тут в папку свалены разные классы, часть из которых точно не модели - например, FrontController никак моделью не является. Роутер явно не является частью модели. И вообще, MVC не значит что у тебя должно быть ровно 3 папки view, controller и model. Это деление приложения на 3 части, а не файлов на 3 папки.

https://github.com/TheSidSpears/Students/blob/master/app/models/FrontController.php
Тут единственная функция со стеной кода. Учись разбивать код на части и выносить в отдельные функции. Я тут явно вижу функции вроде определения контроллера или вроде вывода шаблона.

> if ($authorized){


> //Для вида


> $userName=$authorized['name'];


Неправильно что переменная модет существовать, а может и нет. Как в таком случае писать надежный код если ты даже не знаешь, есть ли такая переменная?

> //Подключаем контроллер


> if (!empty($controller)){


А если она пусто то что? Выведем белую страницу?

> if (!empty($view)){


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

https://github.com/TheSidSpears/Students/blob/master/app/models/JSON.php
json_decode может вернуть null если в JSON ошибка. Тут нет такой проверки.

Блок кода после if должен быть в фигурных скобках.

https://github.com/TheSidSpears/Students/blob/master/app/models/JSON.php
Название класса мало что говорит о его функции. Надо назвать вроде ConfigLoader.

https://github.com/TheSidSpears/Students/blob/master/app/models/Router.php
Для "игнорирования" query string праивльне использовать функцию parse_url а не самодельный сомнительный код. Он еще и работает неправильно в случае /a/b/c?d=e/f

Далее, ты разбиваешь УРЛ на части и берешь последнюю, а что если УРЛ имеет вид /a/b/c/d/e/f - ты берешь только f, а остальные игнорируются?

> if( ($module=='index.php') or ($module=='')){


Непонятно зачем разрешать УРЛ содержащий index.php? У тебя же возможность задавать произвольные УРЛ есть.

https://github.com/TheSidSpears/Students/blob/master/app/controllers/main.php
Если ты используешь ООП, почему бы и контроллер не сделать классом?

> $db=new DataBase($config['db']);


Это раскидано в нескольких местах кода. Вообще-то идея была, чтобы в bootstrap создать нужные объекты один раз. Ты создаешь несколько соединений с базой данных например, несколько StudentDataGateway. Это не очень логично.

> if($currentPage<=0){$currentPage=1;}


Тебе надо лучше форматировать код. Иф пишется в 3 строки, а не в одну. Также, тут можно было обойтись функцией max.

https://github.com/TheSidSpears/Students/blob/master/app/models/ViewHelper.php
Тут оформление кода ужасное. Что за полотна из пустых строк? Почему скобка на одной строке с заголовком функции?

> $routes = explode('/', $_SERVER['REQUEST_URI']);


> $routes[count($routes)-1]=$url;


Это копипаста (причем неточная) кода из роутера. Почему у тебя разбор УРЛ сделан в 2 разных местах, причем еще и по-разному? Принцип "единой ответственности", когда за каждую задачу отвечает кто-то один, не соблюдается.

> static function html($string,$find=NULL){


По моему экранирование и подсветка совпадений - это две разные функции.
https://github.com/TheSidSpears/Students #571 #767003

>>748292


>>755118

https://github.com/TheSidSpears/Students/blob/master/students.sql#L31

> `hash` text NOT NULL,


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

https://github.com/TheSidSpears/Students/blob/master/errors.log
Этот файл надо убрать из репозитория, добавив в .gitignore и сделав git rm с нужными флагами

https://github.com/TheSidSpears/Students/blob/master/config.json
Не стоит делать конфиг слишком большим. В конфиг мы выносим то, что будет менять конечный пользователь. Название папки с контроллерами вряд ли имеет смысл менять.

https://github.com/TheSidSpears/Students/blob/master/public/503.php#L1

> header(' ', true, 503);


Что это за синтаксис? Что за пустой заголовок? По моему это не будет работать. Там надо отправлять заголоок вроде HTTP/1.1 503 xxxx, почитай хотя бы мануал по функции header().

> <a href='index.php'>На главную</a>


У тебя URL главной - это index.php или / ? Желательно иметь для одной страницы один УРЛ.

https://github.com/TheSidSpears/Students/blob/master/public/503.php#L11

> $array=file('errors.log');


ЧТо если файл огромный? Это будет медленно и займет много памяти. Ну и не очень понятно, зачем ты вообще выводишь лог для посетителей сайта.

> for ($i=$count-21; $i < $count; $i++) {


А что если в файле меньше 21 строки? Плюс, ты выводишь данные без экранирования и тут явно может быть XSS если HTML код от злоумышлеенника попадет в сообщение в логе. Ты путаешь язык HTML и простой текстовый файл. В HTML некоторые символы имеют специальное знаечние (например < обозначает начало тега) и нельзя просто так выводить произвольный текст.

Кстати, раз ты путаешься с этим, реши-ка задачку на экранирование отсюда (и заодно прочитай сам урок): https://github.com/codedokode/pasta/blob/master/soft/web-server.md#Экранирование

https://github.com/TheSidSpears/Students/blob/master/public/index.php

> chdir ('../')


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

https://github.com/TheSidSpears/Students/blob/master/app/bootstrap.php#L12
А зачем заводить свой собственный лог? Не лучше ли писать в стандартный лог PHP? ты кстати, знаешь, где он находится?

https://github.com/TheSidSpears/Students/blob/master/app/bootstrap.php#L20

> spl_autoload_register(


Тут незачем делать 2 автозагрузчика, проще сделать один, который проверяет разные пути. А еще лучше, конечно, было бы использовать PSR-4 при выборе названий классов и файлов.

https://github.com/TheSidSpears/Students/tree/master/app/models
Тут в папку свалены разные классы, часть из которых точно не модели - например, FrontController никак моделью не является. Роутер явно не является частью модели. И вообще, MVC не значит что у тебя должно быть ровно 3 папки view, controller и model. Это деление приложения на 3 части, а не файлов на 3 папки.

https://github.com/TheSidSpears/Students/blob/master/app/models/FrontController.php
Тут единственная функция со стеной кода. Учись разбивать код на части и выносить в отдельные функции. Я тут явно вижу функции вроде определения контроллера или вроде вывода шаблона.

> if ($authorized){


> //Для вида


> $userName=$authorized['name'];


Неправильно что переменная модет существовать, а может и нет. Как в таком случае писать надежный код если ты даже не знаешь, есть ли такая переменная?

> //Подключаем контроллер


> if (!empty($controller)){


А если она пусто то что? Выведем белую страницу?

> if (!empty($view)){


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

https://github.com/TheSidSpears/Students/blob/master/app/models/JSON.php
json_decode может вернуть null если в JSON ошибка. Тут нет такой проверки.

Блок кода после if должен быть в фигурных скобках.

https://github.com/TheSidSpears/Students/blob/master/app/models/JSON.php
Название класса мало что говорит о его функции. Надо назвать вроде ConfigLoader.

https://github.com/TheSidSpears/Students/blob/master/app/models/Router.php
Для "игнорирования" query string праивльне использовать функцию parse_url а не самодельный сомнительный код. Он еще и работает неправильно в случае /a/b/c?d=e/f

Далее, ты разбиваешь УРЛ на части и берешь последнюю, а что если УРЛ имеет вид /a/b/c/d/e/f - ты берешь только f, а остальные игнорируются?

> if( ($module=='index.php') or ($module=='')){


Непонятно зачем разрешать УРЛ содержащий index.php? У тебя же возможность задавать произвольные УРЛ есть.

https://github.com/TheSidSpears/Students/blob/master/app/controllers/main.php
Если ты используешь ООП, почему бы и контроллер не сделать классом?

> $db=new DataBase($config['db']);


Это раскидано в нескольких местах кода. Вообще-то идея была, чтобы в bootstrap создать нужные объекты один раз. Ты создаешь несколько соединений с базой данных например, несколько StudentDataGateway. Это не очень логично.

> if($currentPage<=0){$currentPage=1;}


Тебе надо лучше форматировать код. Иф пишется в 3 строки, а не в одну. Также, тут можно было обойтись функцией max.

https://github.com/TheSidSpears/Students/blob/master/app/models/ViewHelper.php
Тут оформление кода ужасное. Что за полотна из пустых строк? Почему скобка на одной строке с заголовком функции?

> $routes = explode('/', $_SERVER['REQUEST_URI']);


> $routes[count($routes)-1]=$url;


Это копипаста (причем неточная) кода из роутера. Почему у тебя разбор УРЛ сделан в 2 разных местах, причем еще и по-разному? Принцип "единой ответственности", когда за каждую задачу отвечает кто-то один, не соблюдается.

> static function html($string,$find=NULL){


По моему экранирование и подсветка совпадений - это две разные функции.
>>767669
https://github.com/TheSidSpears/Students #572 #767004

>>748292


>>755118

> $reg="/$find/ui";


Ты подставляешь то, что ввел пользователь, в регулярку, но что если там есть специсмволы, например, плюс, звездочка, точка? надо либо использовать str_replace либо экранировать спецсимволы с помощью preg_quote.

https://github.com/TheSidSpears/Students/blob/master/app/models/ViewHelper.php#L51

> $router=new Router();


Опять же, почему-то у тебя создается несколько экземплятров роутера в приложении.

https://github.com/TheSidSpears/Students/blob/master/app/models/ViewHelper.php#L63

> return self::html($url);


Почему функция makeUrl вызывает self::html? А что если нам нужен исходный неискаженный УРЛ (например мы хотим редиректить на него)?

> https://github.com/TheSidSpears/Students/blob/master/app/models/ViewHelper.php#L57


> foreach ($blockedParams as $key => $value) {


> $url.=$key."=".$value."&";


Что если в value содержится символ &, #, ? или какой-то еще, имеющий специальное значение в УРЛ?

https://github.com/TheSidSpears/Students/blob/master/app/models/Util.php#L12

> $result .= $array[mt_rand(0, 35)];


Число 35 надо не вписывать в код, а считать из размера массива.

https://github.com/TheSidSpears/Students/blob/master/app/controllers/edit.php
Этот класс на 90% копипаста класса register.php. Ты не должен копипастить код, надо остановиться и подумать, а как можно избежать дублирования кода? Вообще, регистрация и редактирование это практически одно и то же действие.

Те кто копипастят, не думают что будет с кодом дальше, ведь дальше им же самим придется править или добавлять что-то в несколько копий кода.

> if (isset($_COOKIE['hash'])) { //нет кука с хешем => не выполнять скрипт


> ОП, эту куку нужно как-то проверять?


Надо проверять что она соответствует реальному студенту в БД

> $token= (isset($_COOKIE['token'])) ? $_COOKIE['token'] : Util::randHash(20);


> setcookie('token',$token,time()+3600,'/',null,false,true);


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

> foreach($editStudent as $fieldName=>&$fieldValue){


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

Более того, ты не уничтожил ссылку после цикла. Перечитай мануал про foreach.

Более того, ты еще и ниже второй раз этот код скопипастил. Не копипасть.

Само редактирвоание на мой взгляд, сделано неправильно. Логичнее взять студента из БД, изменить у него часть полей и сохранить обратно. Ты же предполагаешь что все данные о студенте будет в форме. Но это не обязательно так. Что если например позже добавят какие-то скрытые поля которые есть в студенте но не редактируются через форму? Твой код будет их обнулять.

> $table->editStudent($editStudent);


> if( empty($table->userErrors) ){


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

> header(' ', true, 400); //Так, вроде правильней


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

https://github.com/TheSidSpears/Students/blob/master/app/models/DataBase.php
Что делает этот класс? Что он добавляет, чего нет в PDO?

> public function connection(){


Имена функций начинаются с глагола

https://github.com/TheSidSpears/Students/blob/master/app/models/Student.php#L11

> public $name; //string(200)


Этот комментарий может быстро устареть, если поменяют код в валидаторе.

https://github.com/TheSidSpears/Students/blob/master/app/models/StudentDataGateway.php#L38

> if (!$rows->execute()){


> throw new StudentDataGatewayException("Ошибка в ф-ии $func_name: ".__CLASS__);


Если ты используешь ERRMODE_EXCEPTION то PDO сам выкидывает искючения при ошибке. Этот иф не нужен.

https://github.com/TheSidSpears/Students/blob/master/app/models/StudentDataGateway.php#L63

> LIKE '%$search%'");


Это SQL инъекция. Не вставляй данные напрямую в запрос

> $count=$rows->fetchAll(PDO::FETCH_ASSOC);


> return $count[0]["COUNT(*)"];


В PDO есть функция чтобы вернуть первое значение из первой строки.

> foreach ($columns as &$column) {


> $column=$column["Field"];


Есть array_column для этого

> $students[]=new Student();


> $students[count($students)-1]->addInfo($studentRow);


Вместо count(...) лучше просто завести переменную для объекта

> $student=array();


> $student=$studentRow[0];


Есть функция чтобы взять толкьо первую строку результата

> $alredyRegistered=$this->checkEmail($student->email);


> if($alredyRegistered){


> $this->userErrors[]='Такой e-mail уже зарегистрирован';


Разве это не задача валидатора?

> $error_array = $this->db->errorInfo();


> if($this->db->errorCode() != 0000){


Это не надо проверять при ERRMODE_EXCEPTION

> //Исключение совпадения e-mail'ов разных юзеров


> $currentStudentData=$this->getStudentByHash($student->hash);


Это делается гораздо проще: надо просто искать по условию WHERE email = ? AND id <> ?
https://github.com/TheSidSpears/Students #572 #767004

>>748292


>>755118

> $reg="/$find/ui";


Ты подставляешь то, что ввел пользователь, в регулярку, но что если там есть специсмволы, например, плюс, звездочка, точка? надо либо использовать str_replace либо экранировать спецсимволы с помощью preg_quote.

https://github.com/TheSidSpears/Students/blob/master/app/models/ViewHelper.php#L51

> $router=new Router();


Опять же, почему-то у тебя создается несколько экземплятров роутера в приложении.

https://github.com/TheSidSpears/Students/blob/master/app/models/ViewHelper.php#L63

> return self::html($url);


Почему функция makeUrl вызывает self::html? А что если нам нужен исходный неискаженный УРЛ (например мы хотим редиректить на него)?

> https://github.com/TheSidSpears/Students/blob/master/app/models/ViewHelper.php#L57


> foreach ($blockedParams as $key => $value) {


> $url.=$key."=".$value."&";


Что если в value содержится символ &, #, ? или какой-то еще, имеющий специальное значение в УРЛ?

https://github.com/TheSidSpears/Students/blob/master/app/models/Util.php#L12

> $result .= $array[mt_rand(0, 35)];


Число 35 надо не вписывать в код, а считать из размера массива.

https://github.com/TheSidSpears/Students/blob/master/app/controllers/edit.php
Этот класс на 90% копипаста класса register.php. Ты не должен копипастить код, надо остановиться и подумать, а как можно избежать дублирования кода? Вообще, регистрация и редактирование это практически одно и то же действие.

Те кто копипастят, не думают что будет с кодом дальше, ведь дальше им же самим придется править или добавлять что-то в несколько копий кода.

> if (isset($_COOKIE['hash'])) { //нет кука с хешем => не выполнять скрипт


> ОП, эту куку нужно как-то проверять?


Надо проверять что она соответствует реальному студенту в БД

> $token= (isset($_COOKIE['token'])) ? $_COOKIE['token'] : Util::randHash(20);


> setcookie('token',$token,time()+3600,'/',null,false,true);


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

> foreach($editStudent as $fieldName=>&$fieldValue){


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

Более того, ты не уничтожил ссылку после цикла. Перечитай мануал про foreach.

Более того, ты еще и ниже второй раз этот код скопипастил. Не копипасть.

Само редактирвоание на мой взгляд, сделано неправильно. Логичнее взять студента из БД, изменить у него часть полей и сохранить обратно. Ты же предполагаешь что все данные о студенте будет в форме. Но это не обязательно так. Что если например позже добавят какие-то скрытые поля которые есть в студенте но не редактируются через форму? Твой код будет их обнулять.

> $table->editStudent($editStudent);


> if( empty($table->userErrors) ){


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

> header(' ', true, 400); //Так, вроде правильней


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

https://github.com/TheSidSpears/Students/blob/master/app/models/DataBase.php
Что делает этот класс? Что он добавляет, чего нет в PDO?

> public function connection(){


Имена функций начинаются с глагола

https://github.com/TheSidSpears/Students/blob/master/app/models/Student.php#L11

> public $name; //string(200)


Этот комментарий может быстро устареть, если поменяют код в валидаторе.

https://github.com/TheSidSpears/Students/blob/master/app/models/StudentDataGateway.php#L38

> if (!$rows->execute()){


> throw new StudentDataGatewayException("Ошибка в ф-ии $func_name: ".__CLASS__);


Если ты используешь ERRMODE_EXCEPTION то PDO сам выкидывает искючения при ошибке. Этот иф не нужен.

https://github.com/TheSidSpears/Students/blob/master/app/models/StudentDataGateway.php#L63

> LIKE '%$search%'");


Это SQL инъекция. Не вставляй данные напрямую в запрос

> $count=$rows->fetchAll(PDO::FETCH_ASSOC);


> return $count[0]["COUNT(*)"];


В PDO есть функция чтобы вернуть первое значение из первой строки.

> foreach ($columns as &$column) {


> $column=$column["Field"];


Есть array_column для этого

> $students[]=new Student();


> $students[count($students)-1]->addInfo($studentRow);


Вместо count(...) лучше просто завести переменную для объекта

> $student=array();


> $student=$studentRow[0];


Есть функция чтобы взять толкьо первую строку результата

> $alredyRegistered=$this->checkEmail($student->email);


> if($alredyRegistered){


> $this->userErrors[]='Такой e-mail уже зарегистрирован';


Разве это не задача валидатора?

> $error_array = $this->db->errorInfo();


> if($this->db->errorCode() != 0000){


Это не надо проверять при ERRMODE_EXCEPTION

> //Исключение совпадения e-mail'ов разных юзеров


> $currentStudentData=$this->getStudentByHash($student->hash);


Это делается гораздо проще: надо просто искать по условию WHERE email = ? AND id <> ?
19 Кб, 859x156
30 Кб, 1264x341
#573 #767005
>>764853
>>764855

Спасибо большое за ответы!

> Существуют другие методы например HEAD. Массивы $_POST и $_GET существуют независимо и могут быть заполнены оба в некоторых случаях.


Разделил на bodyParams и queryParams в классе Request: https://github.com/applejacky/students/blob/master/app/Lib/Request.php
Добавил PUT и DELETE, немножко поковырял curl, теперь можно делать так:
curl -X DELETE http://test.loc/student/12
Разумеется, это только для демонстрации работы метода DELETE. Алсо, получилось зарегаться через curl и изменить профиль: https://github.com/applejacky/students/blob/master/util/curl_rest_test.sh

>> Попытался сделать DI-контейнер похожим на Pimple, до сих пор не знаю, хорошая ли это идея;


> Гм, а почему бы тогда сразу pimple и не взять?


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

>> В валидаторе студента 2 метода: validate и checkEmailUnique. Их пришлось разделить так как в случае с обновлением данных проверять email на уникальность не нужно.


> Вообще-то при обновлении тоже надо проверять. Иначе человек заменит email на уже существующий у другого студента.


У меня есть проверка в шаблоне, если пользователь обновляет профиль, то инпуты с паролем и email'ом не отображаются: https://github.com/applejacky/students/blob/master/app/View/form/index.phtml#L48
В контроллер приходит массив данных о студенте без пароля и email, этот массив мапится на существующего студента у которого есть email и password.
Как мне кажется, не очень хорошо, что email и password можно так просто поменять. Зависящие от них токены тоже менять придётся. Поэтому я лишил пользователя возможности менять email и пароль.

> И кстати, почему ты не сделал просто метод match(Request) в классе Route?


Ну у меня и так роут сам себя валидирует, а тут ещё и предоставить ему возможность проверять себя на соответствие Request'у. Это лучше, чем подход с RouteRequestMatcher'ом?
Алсо, сейчас в последнем только один метод: https://github.com/applejacky/students/blob/master/app/Routing/RouteRequestMatcher.php

> Насчет классов Request, Route - они подозрительно напоминают классы из компонентов Симфони.


Ты мне советовал посмотреть реализацию роутинга в компонентах Symfony, поэтому мои классы похожи.

> Может лучше было оттуда их и взять?


Я ньюфаг, какой Symfony? Я когда студентов начинал писать, то не понимал как работает многостраничное приложение, не знал как регистрировать и запоминать пользователя, не работал с неймспейсами, композером и так далее.
Мне очень нравится документация этого фреймворка и я обязательно до него доберусь, но студентов хочу сделать на велосипедах.
Алсо, вот хочу я использовать symfony/validation в файлообменнике, ищу большую-красную-кнопку вменяемый гайд, но ничего не нахожу.
https://symfony.com/doc/current/book/validation.html
https://github.com/symfony/validator
Где тут описано использование symfony/validation как standalone компонента?

>> if (is_callable($value)) {


> Тут надо использовать тайп хинт callable


Не получилось. Пик 1.

>> https://github.com/applejacky/students/blob/master/app/Controller/Controller.php#L23


> тут не сделана обработка исключений в процессе вывода шаблона. У тебя все, что успело вывестись, вывалится на экран.


Сделал обработчик ошибок по-человечески и теперь вроде всё норм. На пике 2 - результат обращения к несуществующей переменной из шаблона. Только в методе view пришлось заменить require на include, причины описаны здесь: >>766467

>> if ($recordsPerPage > $recordsCount) {


>>$recordsPerPage = 5;


>> }


> Логика немного непонятна. тут нет ошибки?


$recordsPerPage приходит из GET-параметров. Сейчас сделал по-другому: если пользователь запрашивает 20 студентов на страницу, а в базе всего 10, то просто отображаем всех студентов.
А если у меня в базе over9000 студентов, а пользователь просит over9000+1, то все они вывалятся в браузер. И тут браузер, наверное, упадёт. Поэтому и я выставлял 5 студентов на страницу, если пользователь просит слишком много.

> лучше сделать как описано в моему алгоритме работы с формами. Вместо 4 однотипных методов, для форм регистрации и редактирования достаточно одного общего метода.


Сделал. В результате избавился от однотипности, но получил сложность ввиду множественных ветвлений. Для наглядности залил в виде паст.
До: http://paste.ofcode.org/D5ZFbX5E5aaeqBkApKaF2b
После: http://paste.ofcode.org/rHP8sLyfNnqxsYBK7aNdzC

Алсо из-за объединения я теперь не могу в роутах сделать так:
POST /student FormController@postRegister

У меня теперь доступен только метод postRegisterOrUpdate, а ведь для обновления данных о ресурсе нужно использовать метод PUT. Можно делать вот так, но это выглядит как-то странно:
'PUT', '/student', 'Form@postRegisterOrUpdate';
'POST', '/student', 'Form@postRegisterOrUpdate';

Я даже название не смог подобрать для этого метод нормальное, потому что он делает 2 разных дела.
Могу сделать ['PUT', 'POST'], '/student', 'FormController@postRegisterOrUpdate', вроде лучше, но всё равно выглядит как-то странно.

https://github.com/applejacky/students/blob/master/app/Helper/StringGenerator.php#L18

> Не очень понятно почему этот метод тут, а не в классе авторизации.


Переименовал названия аргументов с password, login на string1, string2: https://github.com/applejacky/students/blob/master/app/Helper/StringGenerator.php#L20
В таком случае можно оставлять этот метод в классе StringGenerator?
Метод просто генерирует мешанину из 2-х строк.

Вопросы:
1. Чтобы реализовать разлогинивание по CSRF-токену нужно передавать этот CSRF-токен в каждый вид (не дёргать же из шаблона глобальные переменные?), чтобы иметь возможность в шаблоне генерировать ссылку вида /logout?token<?= $csrfToken ?>.
Есть 2 стула:
- В каждом методе, который выводит шаблон, а не редиректит куда-то, нужно передавать csrf_token. Если будут появляться ещё методы и контроллеры, то нужно опять копипастить.
- Возложить передачу токена на базовый контроллер. Плюс в том, что нет копипасты, минус в том, что непонятно почему базовый контроллер отвечает за CSRF.

2. В случае с curl'ом хотелось бы, чтобы action, к примеру, не редиректил после регистрации, выплёвывая стену html-кода, а отдавал Response::HTTP_CREATED. Это нужно как-то по Content-type реквеста определять, каким будет Response? Например, если Content-type: application/json, то возвращать $response->withStatus(Response::HTTP_CREATED), если text/html - заполнять тело ответа страницей или делать редирект.

3. Хотелось бы, чтобы display_errors настраивался сразу в сonfig.ini для конкретного проекта, чтобы не изменять глобально значение в php.ini
Директива display_erros доступна глобально по всему проекту, почему нельзя использовать ini_set('display_errors', 1) в начале фронтконтроллера?
19 Кб, 859x156
30 Кб, 1264x341
#573 #767005
>>764853
>>764855

Спасибо большое за ответы!

> Существуют другие методы например HEAD. Массивы $_POST и $_GET существуют независимо и могут быть заполнены оба в некоторых случаях.


Разделил на bodyParams и queryParams в классе Request: https://github.com/applejacky/students/blob/master/app/Lib/Request.php
Добавил PUT и DELETE, немножко поковырял curl, теперь можно делать так:
curl -X DELETE http://test.loc/student/12
Разумеется, это только для демонстрации работы метода DELETE. Алсо, получилось зарегаться через curl и изменить профиль: https://github.com/applejacky/students/blob/master/util/curl_rest_test.sh

>> Попытался сделать DI-контейнер похожим на Pimple, до сих пор не знаю, хорошая ли это идея;


> Гм, а почему бы тогда сразу pimple и не взять?


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

>> В валидаторе студента 2 метода: validate и checkEmailUnique. Их пришлось разделить так как в случае с обновлением данных проверять email на уникальность не нужно.


> Вообще-то при обновлении тоже надо проверять. Иначе человек заменит email на уже существующий у другого студента.


У меня есть проверка в шаблоне, если пользователь обновляет профиль, то инпуты с паролем и email'ом не отображаются: https://github.com/applejacky/students/blob/master/app/View/form/index.phtml#L48
В контроллер приходит массив данных о студенте без пароля и email, этот массив мапится на существующего студента у которого есть email и password.
Как мне кажется, не очень хорошо, что email и password можно так просто поменять. Зависящие от них токены тоже менять придётся. Поэтому я лишил пользователя возможности менять email и пароль.

> И кстати, почему ты не сделал просто метод match(Request) в классе Route?


Ну у меня и так роут сам себя валидирует, а тут ещё и предоставить ему возможность проверять себя на соответствие Request'у. Это лучше, чем подход с RouteRequestMatcher'ом?
Алсо, сейчас в последнем только один метод: https://github.com/applejacky/students/blob/master/app/Routing/RouteRequestMatcher.php

> Насчет классов Request, Route - они подозрительно напоминают классы из компонентов Симфони.


Ты мне советовал посмотреть реализацию роутинга в компонентах Symfony, поэтому мои классы похожи.

> Может лучше было оттуда их и взять?


Я ньюфаг, какой Symfony? Я когда студентов начинал писать, то не понимал как работает многостраничное приложение, не знал как регистрировать и запоминать пользователя, не работал с неймспейсами, композером и так далее.
Мне очень нравится документация этого фреймворка и я обязательно до него доберусь, но студентов хочу сделать на велосипедах.
Алсо, вот хочу я использовать symfony/validation в файлообменнике, ищу большую-красную-кнопку вменяемый гайд, но ничего не нахожу.
https://symfony.com/doc/current/book/validation.html
https://github.com/symfony/validator
Где тут описано использование symfony/validation как standalone компонента?

>> if (is_callable($value)) {


> Тут надо использовать тайп хинт callable


Не получилось. Пик 1.

>> https://github.com/applejacky/students/blob/master/app/Controller/Controller.php#L23


> тут не сделана обработка исключений в процессе вывода шаблона. У тебя все, что успело вывестись, вывалится на экран.


Сделал обработчик ошибок по-человечески и теперь вроде всё норм. На пике 2 - результат обращения к несуществующей переменной из шаблона. Только в методе view пришлось заменить require на include, причины описаны здесь: >>766467

>> if ($recordsPerPage > $recordsCount) {


>>$recordsPerPage = 5;


>> }


> Логика немного непонятна. тут нет ошибки?


$recordsPerPage приходит из GET-параметров. Сейчас сделал по-другому: если пользователь запрашивает 20 студентов на страницу, а в базе всего 10, то просто отображаем всех студентов.
А если у меня в базе over9000 студентов, а пользователь просит over9000+1, то все они вывалятся в браузер. И тут браузер, наверное, упадёт. Поэтому и я выставлял 5 студентов на страницу, если пользователь просит слишком много.

> лучше сделать как описано в моему алгоритме работы с формами. Вместо 4 однотипных методов, для форм регистрации и редактирования достаточно одного общего метода.


Сделал. В результате избавился от однотипности, но получил сложность ввиду множественных ветвлений. Для наглядности залил в виде паст.
До: http://paste.ofcode.org/D5ZFbX5E5aaeqBkApKaF2b
После: http://paste.ofcode.org/rHP8sLyfNnqxsYBK7aNdzC

Алсо из-за объединения я теперь не могу в роутах сделать так:
POST /student FormController@postRegister

У меня теперь доступен только метод postRegisterOrUpdate, а ведь для обновления данных о ресурсе нужно использовать метод PUT. Можно делать вот так, но это выглядит как-то странно:
'PUT', '/student', 'Form@postRegisterOrUpdate';
'POST', '/student', 'Form@postRegisterOrUpdate';

Я даже название не смог подобрать для этого метод нормальное, потому что он делает 2 разных дела.
Могу сделать ['PUT', 'POST'], '/student', 'FormController@postRegisterOrUpdate', вроде лучше, но всё равно выглядит как-то странно.

https://github.com/applejacky/students/blob/master/app/Helper/StringGenerator.php#L18

> Не очень понятно почему этот метод тут, а не в классе авторизации.


Переименовал названия аргументов с password, login на string1, string2: https://github.com/applejacky/students/blob/master/app/Helper/StringGenerator.php#L20
В таком случае можно оставлять этот метод в классе StringGenerator?
Метод просто генерирует мешанину из 2-х строк.

Вопросы:
1. Чтобы реализовать разлогинивание по CSRF-токену нужно передавать этот CSRF-токен в каждый вид (не дёргать же из шаблона глобальные переменные?), чтобы иметь возможность в шаблоне генерировать ссылку вида /logout?token<?= $csrfToken ?>.
Есть 2 стула:
- В каждом методе, который выводит шаблон, а не редиректит куда-то, нужно передавать csrf_token. Если будут появляться ещё методы и контроллеры, то нужно опять копипастить.
- Возложить передачу токена на базовый контроллер. Плюс в том, что нет копипасты, минус в том, что непонятно почему базовый контроллер отвечает за CSRF.

2. В случае с curl'ом хотелось бы, чтобы action, к примеру, не редиректил после регистрации, выплёвывая стену html-кода, а отдавал Response::HTTP_CREATED. Это нужно как-то по Content-type реквеста определять, каким будет Response? Например, если Content-type: application/json, то возвращать $response->withStatus(Response::HTTP_CREATED), если text/html - заполнять тело ответа страницей или делать редирект.

3. Хотелось бы, чтобы display_errors настраивался сразу в сonfig.ini для конкретного проекта, чтобы не изменять глобально значение в php.ini
Директива display_erros доступна глобально по всему проекту, почему нельзя использовать ini_set('display_errors', 1) в начале фронтконтроллера?
>>767027
#574 #767008

>>748292


>>755118

https://github.com/TheSidSpears/Students/blob/master/app/views/auth_form.php
br вернй признак того, что ты не знаешь CSS. Обрати внимание, в ОП посте есть задачи по CSS.

https://github.com/TheSidSpears/Students/blob/master/app/views/student_form.php
Тут стоит добавить html5 валидацию, хотя бы required например.

> <?php if($s->is_resident): ?>


> <input type="radio" name="is_resident" value="resident" checked> Местный


> <?php else: ?>


> <input type="radio" name="is_resident" value="resident"> Местный


Не требуется копипастить input, хватит <?= $resident ? ' checked ' : '' ?>

https://github.com/TheSidSpears/Students/tree/master/app/views
тут у тебя много файлов и их надо хотя бы по папкам организровать как-то

>>766820

Регистрация и редактирования это по сути одно и то же и должен быть 1 контроллер и 1 вью для них.

> засунуть в ф-ию Util::token(). Но тогда ф-ия будет работать с куками и устанавливать глобальную переменную, что, наверное, не очень правильно


надо вынести всю работу с CSRF в класс.
#575 #767027
>>767005

> Ну у меня и так роут сам себя валидирует, а тут ещё и предоставить ему возможность проверять себя на соответствие Request'у. Это лучше, чем подход с RouteRequestMatcher'ом?


Не знаю, можно и так и так сделать. И чтобы сам себя матчил или чтобы снаружи это делалось.

> Алсо, вот хочу я использовать symfony/validation в файлообменнике, ищу большую-красную-кнопку вменяемый гайд, но ничего не нахожу.


http://symfony.com/components/Validator но тут нет доков, так что придется читать тут: https://symfony.com/doc/current/book/validation.html

В принципе, разница только в том, что в Сифмони объект валидатора получается через $this->get('validator'), а ты будешь создавать его через new или через ValidationBuilder, придется немного порыться в коде и понять как его создать и как заставить прочитать аннотации или конфиг. Если будет сложно, напиши, я тоже гляну.

> > Тут надо использовать тайп хинт callable


> Не получилось. Пик 1.


Да, тут я ошибся, при наследовании можно только расширять класс или метод, но не сужать его, в соовтетсвии с принципом Лисков (класс-потомок всегда можно использовать вместо предка).

> После: http://paste.ofcode.org/rHP8sLyfNnqxsYBK7aNdzC


Вообще, в моем алгоритме POST и GET обрабатывает один метод. тобы не было стены кода, надо разбивать его на более мелкие функции.

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

> Алсо из-за объединения я теперь не могу в роутах сделать так:


> POST /student FormController@postRegister


Это проблема твоего роутера

> У меня теперь доступен только метод postRegisterOrUpdate, а ведь для обновления данных о ресурсе нужно использовать метод PUT.


Вообще, нет.

http://ru.stackoverflow.com/questions/193978/Разница-между-put-и-post

PUT используется для обновления ресурса. но идентификатор ресурса должен быть в URL в этом случае (/student/xxxx). POST же это общий метод для изменения чего-то на сервере.

В спецификации я вижу такое: https://tools.ietf.org/html/rfc7231#section-4.3.4

> The PUT method requests that the state of the target resource be


> created or replaced with the state defined by the representation


> enclosed in the request message payload. A successful PUT of a given


> representation would suggest that a subsequent GET on that same


> target resource will result in an equivalent representation being


> sent in a 200 (OK) response.


PUT создает или заменяет ресурс переданными данными.

> Переименовал названия аргументов с password, login на string1, string2:


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

> 1. Чтобы реализовать разлогинивание по CSRF-токену нужно передавать этот CSRF-токен в каждый вид (не дёргать же из шаблона глобальные переменные?),


Можно организовать передачу "глобальных" для шаблона переменных, которые передаются всегда.

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


Можно на базовый или фронт-контроллер. Там всегда есть такие переменные, например информация о залогиненном пользователе.

> 2. В случае с curl'ом хотелось бы, чтобы action, к примеру, не редиректил после регистрации, выплёвывая стену html-кода,


Можно добавить флаг курлу не следовать далее при редиректе.

> Это нужно как-то по Content-type реквеста определять, каким будет Response?


Это плохая идея так как затрудняет отладку. Такие вещи лучше передавать явно, например через GET параметр, но в данном случае проще передать флаг курлу.

> 3. Хотелось бы, чтобы display_errors настраивался сразу в сonfig.ini для конкретного проекта, чтобы не изменять глобально значение в php.ini


Флаг можно менять не только в php.ini, но и в конфиге апача для данного хоста, в htaccess, в php-fpm. Изобретать велосипед не требуется.

> почему нельзя использовать ini_set('display_errors', 1) в начале фронтконтроллера?


Как ты собрался отключать это на продакшене? Руками код каждый раз править?
#575 #767027
>>767005

> Ну у меня и так роут сам себя валидирует, а тут ещё и предоставить ему возможность проверять себя на соответствие Request'у. Это лучше, чем подход с RouteRequestMatcher'ом?


Не знаю, можно и так и так сделать. И чтобы сам себя матчил или чтобы снаружи это делалось.

> Алсо, вот хочу я использовать symfony/validation в файлообменнике, ищу большую-красную-кнопку вменяемый гайд, но ничего не нахожу.


http://symfony.com/components/Validator но тут нет доков, так что придется читать тут: https://symfony.com/doc/current/book/validation.html

В принципе, разница только в том, что в Сифмони объект валидатора получается через $this->get('validator'), а ты будешь создавать его через new или через ValidationBuilder, придется немного порыться в коде и понять как его создать и как заставить прочитать аннотации или конфиг. Если будет сложно, напиши, я тоже гляну.

> > Тут надо использовать тайп хинт callable


> Не получилось. Пик 1.


Да, тут я ошибся, при наследовании можно только расширять класс или метод, но не сужать его, в соовтетсвии с принципом Лисков (класс-потомок всегда можно использовать вместо предка).

> После: http://paste.ofcode.org/rHP8sLyfNnqxsYBK7aNdzC


Вообще, в моем алгоритме POST и GET обрабатывает один метод. тобы не было стены кода, надо разбивать его на более мелкие функции.

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

> Алсо из-за объединения я теперь не могу в роутах сделать так:


> POST /student FormController@postRegister


Это проблема твоего роутера

> У меня теперь доступен только метод postRegisterOrUpdate, а ведь для обновления данных о ресурсе нужно использовать метод PUT.


Вообще, нет.

http://ru.stackoverflow.com/questions/193978/Разница-между-put-и-post

PUT используется для обновления ресурса. но идентификатор ресурса должен быть в URL в этом случае (/student/xxxx). POST же это общий метод для изменения чего-то на сервере.

В спецификации я вижу такое: https://tools.ietf.org/html/rfc7231#section-4.3.4

> The PUT method requests that the state of the target resource be


> created or replaced with the state defined by the representation


> enclosed in the request message payload. A successful PUT of a given


> representation would suggest that a subsequent GET on that same


> target resource will result in an equivalent representation being


> sent in a 200 (OK) response.


PUT создает или заменяет ресурс переданными данными.

> Переименовал названия аргументов с password, login на string1, string2:


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

> 1. Чтобы реализовать разлогинивание по CSRF-токену нужно передавать этот CSRF-токен в каждый вид (не дёргать же из шаблона глобальные переменные?),


Можно организовать передачу "глобальных" для шаблона переменных, которые передаются всегда.

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


Можно на базовый или фронт-контроллер. Там всегда есть такие переменные, например информация о залогиненном пользователе.

> 2. В случае с curl'ом хотелось бы, чтобы action, к примеру, не редиректил после регистрации, выплёвывая стену html-кода,


Можно добавить флаг курлу не следовать далее при редиректе.

> Это нужно как-то по Content-type реквеста определять, каким будет Response?


Это плохая идея так как затрудняет отладку. Такие вещи лучше передавать явно, например через GET параметр, но в данном случае проще передать флаг курлу.

> 3. Хотелось бы, чтобы display_errors настраивался сразу в сonfig.ini для конкретного проекта, чтобы не изменять глобально значение в php.ini


Флаг можно менять не только в php.ini, но и в конфиге апача для данного хоста, в htaccess, в php-fpm. Изобретать велосипед не требуется.

> почему нельзя использовать ini_set('display_errors', 1) в начале фронтконтроллера?


Как ты собрался отключать это на продакшене? Руками код каждый раз править?
>>767066
19 Кб, 200x218
#576 #767058

>>в 95% случаев геттеры/сеттеры генерятся IDE



А что так можно было? Пользуетесь? В каком редакторе?
>>767059
#577 #767059
>>767058

Мой сниппет для саблайма, запускается нажатием gs + Tab: https://gist.github.com/codedokode/cd2f41c8dcf1237fde4b
#578 #767064
Решил вкатиться и от безделья для общего развития упороть погромирование.

http://ideone.com/G1IqpJ
Все правильно делаю анон? вроде все компилируется
>>767481>>779252
121 Кб, 580x381
#579 #767066
>>767027

>Вообще, в моем алгоритме POST и GET обрабатывает один метод.


Тогда надо ещё одно условие в action'е. Я только ради того, чтобы избавится от этого условия начал писать роутер. В общем, у меня пик.

>Также, мне не нравится что там в один и тот же шаблон передаются разные наборы переменных, и часть переименных может отстутствоать.


В конечном итоге передаются одни и те же переменные.
https://github.com/applejacky/students/blob/master/app/Controller/Controller.php#L18
Есть 2 переменные, которые опциональны для передачи из потомков контроллера, но в базовом контроллере они таки получают значение:
1) переменная, отвечающая за название страницы. Если переменная из контроллера-наследника не передана, то базовый контроллер ставит значение этой переменной в 'Default';
2) логическая переменная $isUserLoggedIn. По дефолту базовый контроллер ставит ей false. Её нужно передавать в каждый вид, так как от неё зависит смена надписи 'Вход/Обновить профиль' в навбаре.
Вот к ним-то я и добавлю CSRF-токен тогда.

>PUT используется для обновления ресурса. но идентификатор ресурса должен быть в URL


Да, я упустил это.

>> POST /student FormController@postRegister


> Это проблема твоего роутера



Но ведь во фреймворках в основном используется примерно такая схема:
GET /res ResController@getCreate
GET /res ResController@getUpdate
POST /res ResController@postCreate
PUT /res/X ResController@postUpdate(X)
DELETE /res/X ResController@delete(X)
Так можно было сделать до объединения методов регистрации/обновления. Я понимаю, что регистрация/обновление очень похожи и их бы нужно собрать, но в моём случае, из-за разделения на GET и POST, это приводит к нечитабельным ветвлениям. А если убрать разделение на GET и POST, то тогда и роутер можно выкинуть. Но тогда и не о каком REST не может быть и речи.

В общем, вот так можно оставлять?
GET /student FormController@getRegisterOrUpdate
POST /student FormController@postRegisterOrUpdate
PUT /res/X FormController@postUpdate(X)
Или вернуть как было?

>Как ты собрался отключать это на продакшене? Руками код каждый раз править?


Выставлять значение в config.ini
В slim'e же можно передать в конструктор класса App значение 'displayErrorDetails' => true.

>> Переименовал названия аргументов с password, login на string1, string2:


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


Вот теперь до меня дошло, это ведь из-за md5() всё. Перенесу метод в другой класс.

> Можно добавить флаг курлу не следовать далее при редиректе.


В любом случае нужно как-то оповестить клиент статусом 201, что создание ресурса произошло успешно. А у меня сейчас редирект там.

>> Это нужно как-то по Content-type реквеста определять, каким будет Response?


> Это плохая идея так как затрудняет отладку. Такие вещи лучше передавать явно, например через GET параметр, но в данном случае проще передать флаг курлу.



Имел в виду в action'е делать следующее:
Если request->getContenType == application/json, то вернуть response(statusCode)
Если request->getContentType == application/json, то вернуть response(htmlBody, statusCode)
121 Кб, 580x381
#579 #767066
>>767027

>Вообще, в моем алгоритме POST и GET обрабатывает один метод.


Тогда надо ещё одно условие в action'е. Я только ради того, чтобы избавится от этого условия начал писать роутер. В общем, у меня пик.

>Также, мне не нравится что там в один и тот же шаблон передаются разные наборы переменных, и часть переименных может отстутствоать.


В конечном итоге передаются одни и те же переменные.
https://github.com/applejacky/students/blob/master/app/Controller/Controller.php#L18
Есть 2 переменные, которые опциональны для передачи из потомков контроллера, но в базовом контроллере они таки получают значение:
1) переменная, отвечающая за название страницы. Если переменная из контроллера-наследника не передана, то базовый контроллер ставит значение этой переменной в 'Default';
2) логическая переменная $isUserLoggedIn. По дефолту базовый контроллер ставит ей false. Её нужно передавать в каждый вид, так как от неё зависит смена надписи 'Вход/Обновить профиль' в навбаре.
Вот к ним-то я и добавлю CSRF-токен тогда.

>PUT используется для обновления ресурса. но идентификатор ресурса должен быть в URL


Да, я упустил это.

>> POST /student FormController@postRegister


> Это проблема твоего роутера



Но ведь во фреймворках в основном используется примерно такая схема:
GET /res ResController@getCreate
GET /res ResController@getUpdate
POST /res ResController@postCreate
PUT /res/X ResController@postUpdate(X)
DELETE /res/X ResController@delete(X)
Так можно было сделать до объединения методов регистрации/обновления. Я понимаю, что регистрация/обновление очень похожи и их бы нужно собрать, но в моём случае, из-за разделения на GET и POST, это приводит к нечитабельным ветвлениям. А если убрать разделение на GET и POST, то тогда и роутер можно выкинуть. Но тогда и не о каком REST не может быть и речи.

В общем, вот так можно оставлять?
GET /student FormController@getRegisterOrUpdate
POST /student FormController@postRegisterOrUpdate
PUT /res/X FormController@postUpdate(X)
Или вернуть как было?

>Как ты собрался отключать это на продакшене? Руками код каждый раз править?


Выставлять значение в config.ini
В slim'e же можно передать в конструктор класса App значение 'displayErrorDetails' => true.

>> Переименовал названия аргументов с password, login на string1, string2:


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


Вот теперь до меня дошло, это ведь из-за md5() всё. Перенесу метод в другой класс.

> Можно добавить флаг курлу не следовать далее при редиректе.


В любом случае нужно как-то оповестить клиент статусом 201, что создание ресурса произошло успешно. А у меня сейчас редирект там.

>> Это нужно как-то по Content-type реквеста определять, каким будет Response?


> Это плохая идея так как затрудняет отладку. Такие вещи лучше передавать явно, например через GET параметр, но в данном случае проще передать флаг курлу.



Имел в виду в action'е делать следующее:
Если request->getContenType == application/json, то вернуть response(statusCode)
Если request->getContentType == application/json, то вернуть response(htmlBody, statusCode)
>>767069>>767071
#580 #767069
>>767066

>GET /res ResController@getUpdate


Здесь, наверное /res/update

>>766881
В шапке указана книга Зандстры по ООП в PHP + есть ссылка на сайт designpatterns.
>>767333
#581 #767071
>>767066

>Если request->getContenType == application/json, то вернуть response(statusCode)


>Если request->getContentType == application/json, то вернуть response(htmlBody, statusCode)



Не так, я ошибся. Вот так:
Если request->getContenType == application/json, то вернуть response(statusCode)
Если request->getContentType == text/html, то вернуть response(htmlBody, statusCode)

Извиняюсь за то, что наплодил ответов. Посты перечитываю несколько раз, но, похоже, у меня диагноз.
>>767098
#582 #767098
>>767071

Плохо по-разному реагировать на разный content-type, это сильно усложняет отладку так как разница неочевидна на первый взгляд. Лучше делать разный URL.
>>767107
#583 #767107
>>767098
Например, добавляя префикс api в путь?
Тогда я понимаю это так:
PUT /api/res/X ResController@update(X)
POST /res/X ResController@update(X)
А update(X) уже возвращает нужный response в зависимости от наличия/отсутствия префикса. Однако в каждом action'е по-прежнему будут проверки. Было бы круто, если бы action возвращал какой-то более общий response, который во фронтконтроллере перед ->send() выбирал, что отправлять клиенту, исходя из наличия/отсутствия префикса. В студентах я тогда не буду это реализовывать, а в файлообменнике на Slim можно попробовать, там как раз есть middleware. Должно подойти.
>>767160
#584 #767126
https://github.com/foobar1643/filehosting закончил локализацию и защиту от CSRF.

Список языков я захардкодил в LanguageHelper, перевел полностью все приложение на английский, если родной язык пользователя (определяется по заголовку HTTP_ACCEPT_LANGUAGE) отличается от текущего, выводится сообщение о том что сайт доступен на родном языке пользователя (если он доступен, конечно же), так же для разных языков сделал разные ссылки (с этим было больше всего проблем). По переводу - для того чтобы вытащить строки из .twig файлов используется CLI скрипт https://github.com/foobar1643/filehosting/blob/master/cli-tools/template-extractor.php который создает из шаблонов кэш (который является .php файлами), этот кэш можно импортировать в Poedit и переводить.

CSRF guard я сделал таким же middleware, только теперь он использует куки с фиксированным именем и не генерирует новый токен после каждого запроса. Время жизни куки и и длинну токена можно задать при создании объекта.

Дальше буду переходить к изучению PHPUnit и автоматизированного тестирования. Только вот мне не очень понятно что тут можно тестировать кроме сервисов по добавлению\удалению файлов и комментариев.
#585 #767149
>>767126

> , этот кэш можно импортировать в Poedit и переводить.


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

>>767126

> Дальше буду переходить к изучению PHPUnit и автоматизированного тестирования. Только вот мне не очень понятно что тут можно тестировать кроме сервисов по добавлению\удалению файлов и комментариев.


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

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

Юнит-тесты тестируют отдельные функции или классы в изоляции от остального кода. Ими ты проверяешь что функция или класс выполняет свою работу. Тут да, не все получится протестировать, например, контроллеры юнит-тестами не протестируешь.

Если ты сомневаешься, можешь составить план тестирования (что именно тестируешь).
#586 #767160
>>767107

Ну вообще, обычно REST API делают отдельным набором контроллеров. И поведение там немного другое. Например, при ошибке мы можем отдавать JSON, а не HTML страницу. Другой способ авторизации, например без использования кук, заголовком Authorization.

То ест не факт что получится и будет удобно одним контроллером это обслужить.

Там еще обычно желательно иметь документацию и есть инструменты вроде swagger ( http://petstore.swagger.io/ демо ) для ее создания. В идеале хорошо бы нужные данные как-то генерировать автоматически. То есть где-то есть описание метода, где-то описание формата входных параметров (например JSON Schema или аннотации в модели), и из этого генерируется документация.

> Было бы круто, если бы action возвращал какой-то более общий response, который во фронтконтроллере перед ->send() выбирал, что отправлять клиенту,


Мне кажется, лучше развивать сервисный слой так, чтобы контроллер был как можно тоньше. А для АПИ можно вообще как-то это все обобщить, например сделать классы-обработчики запросов к АПИ, наследующиеся от базового.

Не надо делать 2 слоя контроллеров.
#587 #767189
>>767126

> 'messageFormatter' => new \MessageFormatter(\Locale::getDefault(), _("{0, plural, =0{No downloads} one{# download} other{# downloads}}")),



Ой, это не очень практично. если ты будешь каждое сообщение так в контроллере формировать. Я имел в виду сделать так: в контроллере мы создаем например объект

new Translator('ru_RU')

А в шаблоне используем его:

{{ tr.format('....', { number: 100 }) }}

Или же сделать кастомную функцию:

{{ translate('.....', { number: 100 }) }}

> 'csrf_token' => FigRequestCookies::get($request, "csrf_token")->getValue()]);


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

> const PATH_TO_LOCALES = "/var/www/filehosting/locale";


Путь лучше как-то относительно корня проекта вычислять

Тут https://github.com/foobar1643/filehosting/blob/master/app/Helper/LanguageHelper.php что-то много публичных методов. Трудно понять как работает класс. И Request нужен почти в каждом втором - может стоит его передавать через конструктор?

> $serverParams = $request->getServerParams();


> $httpLanguage = isset($serverParams['HTTP_ACCEPT_LANGUAGE']) ? $serverParams['HTTP_ACCEPT_LANGUAGE'] : NULL;


А там нет метода вроде getHeader() или getHeaders()->get() ?

С локалью на мой взгляд сделано не оень удачно: https://github.com/foobar1643/filehosting/blob/master/app/Middleware/LocaleMiddleware.php#L32

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

И наконец это не позволяет нам извлекать фразы на разных языках без возни с переключением локалей.

Лучше использовать для переключения языка textdomain. Он лишен перечисленных недостатков.

Тут https://github.com/foobar1643/filehosting/blob/master/app/Middleware/CsrfMiddleware.php ты продлеваешь токен, если он уже есть? Иначе он может закончиться совсем неожиданно.

Насчет тестирования - тестировать тут можно много чего. Те же Middleware, хелперы, валидатор как минимум.
#587 #767189
>>767126

> 'messageFormatter' => new \MessageFormatter(\Locale::getDefault(), _("{0, plural, =0{No downloads} one{# download} other{# downloads}}")),



Ой, это не очень практично. если ты будешь каждое сообщение так в контроллере формировать. Я имел в виду сделать так: в контроллере мы создаем например объект

new Translator('ru_RU')

А в шаблоне используем его:

{{ tr.format('....', { number: 100 }) }}

Или же сделать кастомную функцию:

{{ translate('.....', { number: 100 }) }}

> 'csrf_token' => FigRequestCookies::get($request, "csrf_token")->getValue()]);


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

> const PATH_TO_LOCALES = "/var/www/filehosting/locale";


Путь лучше как-то относительно корня проекта вычислять

Тут https://github.com/foobar1643/filehosting/blob/master/app/Helper/LanguageHelper.php что-то много публичных методов. Трудно понять как работает класс. И Request нужен почти в каждом втором - может стоит его передавать через конструктор?

> $serverParams = $request->getServerParams();


> $httpLanguage = isset($serverParams['HTTP_ACCEPT_LANGUAGE']) ? $serverParams['HTTP_ACCEPT_LANGUAGE'] : NULL;


А там нет метода вроде getHeader() или getHeaders()->get() ?

С локалью на мой взгляд сделано не оень удачно: https://github.com/foobar1643/filehosting/blob/master/app/Middleware/LocaleMiddleware.php#L32

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

И наконец это не позволяет нам извлекать фразы на разных языках без возни с переключением локалей.

Лучше использовать для переключения языка textdomain. Он лишен перечисленных недостатков.

Тут https://github.com/foobar1643/filehosting/blob/master/app/Middleware/CsrfMiddleware.php ты продлеваешь токен, если он уже есть? Иначе он может закончиться совсем неожиданно.

Насчет тестирования - тестировать тут можно много чего. Те же Middleware, хелперы, валидатор как минимум.
>>767728
#588 #767215
>>767126

В cli-tools по моему синтаксис получился несколько избыточный:

> --add-file -f <option>


Почему нельзя убрать -f отсюда? getopt понимает синтаксис с двоеточием для длинных опций вроде бы.

> copy($filepath, self::TEMP_FILENAME);


> $uploadedFile = new Slim\Http\UploadedFile(self::TEMP_FILENAME, pathinfo($filepath, PATHINFO_BASENAME));


Имя временного файла надо генерировать через http://php.net/manual/ru/function.tempnam.php

А вообще конечно было былучше если бы временный файл не требовался.

Тут https://github.com/foobar1643/filehosting/blob/master/app/Database/FileMapper.php#L96 не стоило заморачиваться с генерацией кучи плейсхолдеров - проще было заэкранировать данные и подставить напрямую.

Вот здесь видна явная ошибка локализации:

https://github.com/foobar1643/filehosting/blob/master/templates/file.twig#L47

> {% trans %}To view this video please enable JavaScript, and consider upgrading to a web browser that{% endtrans %}


> <a href="http://videojs.com/html5-video-support/" target="_blank">{% trans %}supports HTML5 video{% endtrans %}</a>


Нельзя разрывать предложение на 2 части. Во-первых, они могут оказаться далеко и после перевода они не состыкуются (или они могут достаться разным переводчикам). Во-вторых, в других языках может быть другой порядок слов - например, в японском порядок слов будет не "web broser that supports HTML5 video", а "HTML5 video supporting browser".

Надо бы обходиться без разрыва предложения.

Вот еще скользкое место:

https://github.com/foobar1643/filehosting/blob/master/templates/file.twig#L89

> {% trans %}Send{% endtrans %}


Как это перевести, не зная контекста? Отправить? Послать? Послан? Для таких случаев в формате gettext предусмотрена возможность добавлять комментарии, например "Button to submit a comment". Было бы хорошо если бы они поддерживались у тебя.

Аналогично слова вроде Download - загрузить? загрузка? Загрузок? Save = сохранить? спасти? сэкономить?

Отдельно еще существует проблема перевода JS строк. В более сложном случае надо было бы писать свою функцию перевода для JS, свой коллектор строк и экспортер, который экспортирует JS-переводы в js-файл.

> If you want to change language, you can do so on the{% endtrans %}


> <a href="/{{ lang }}/settings/">{% trans %}settings page{% endtrans %}


Дружелюбнее было бы конечно сразу давать ссылку/кнопку для переключения....

> <a href="/{{ lang }}/file/{{ popularFile.id }}/">{{ popularFile.name }}</a>


Так тебе приходится руками всюду вписывать этот lang. Надо было использовать класс для генерации URL - тогда это можно было бы сделать централизованно.
#588 #767215
>>767126

В cli-tools по моему синтаксис получился несколько избыточный:

> --add-file -f <option>


Почему нельзя убрать -f отсюда? getopt понимает синтаксис с двоеточием для длинных опций вроде бы.

> copy($filepath, self::TEMP_FILENAME);


> $uploadedFile = new Slim\Http\UploadedFile(self::TEMP_FILENAME, pathinfo($filepath, PATHINFO_BASENAME));


Имя временного файла надо генерировать через http://php.net/manual/ru/function.tempnam.php

А вообще конечно было былучше если бы временный файл не требовался.

Тут https://github.com/foobar1643/filehosting/blob/master/app/Database/FileMapper.php#L96 не стоило заморачиваться с генерацией кучи плейсхолдеров - проще было заэкранировать данные и подставить напрямую.

Вот здесь видна явная ошибка локализации:

https://github.com/foobar1643/filehosting/blob/master/templates/file.twig#L47

> {% trans %}To view this video please enable JavaScript, and consider upgrading to a web browser that{% endtrans %}


> <a href="http://videojs.com/html5-video-support/" target="_blank">{% trans %}supports HTML5 video{% endtrans %}</a>


Нельзя разрывать предложение на 2 части. Во-первых, они могут оказаться далеко и после перевода они не состыкуются (или они могут достаться разным переводчикам). Во-вторых, в других языках может быть другой порядок слов - например, в японском порядок слов будет не "web broser that supports HTML5 video", а "HTML5 video supporting browser".

Надо бы обходиться без разрыва предложения.

Вот еще скользкое место:

https://github.com/foobar1643/filehosting/blob/master/templates/file.twig#L89

> {% trans %}Send{% endtrans %}


Как это перевести, не зная контекста? Отправить? Послать? Послан? Для таких случаев в формате gettext предусмотрена возможность добавлять комментарии, например "Button to submit a comment". Было бы хорошо если бы они поддерживались у тебя.

Аналогично слова вроде Download - загрузить? загрузка? Загрузок? Save = сохранить? спасти? сэкономить?

Отдельно еще существует проблема перевода JS строк. В более сложном случае надо было бы писать свою функцию перевода для JS, свой коллектор строк и экспортер, который экспортирует JS-переводы в js-файл.

> If you want to change language, you can do so on the{% endtrans %}


> <a href="/{{ lang }}/settings/">{% trans %}settings page{% endtrans %}


Дружелюбнее было бы конечно сразу давать ссылку/кнопку для переключения....

> <a href="/{{ lang }}/file/{{ popularFile.id }}/">{{ popularFile.name }}</a>


Так тебе приходится руками всюду вписывать этот lang. Надо было использовать класс для генерации URL - тогда это можно было бы сделать централизованно.
#589 #767333
>>767069

>Зандстры


Оо, точно, спасибо!
Начинал её читать, но потом столкнулся со сложнотой в ООП и перестал.
Точно, там же шаблоны и вот это всё.
Ну и тот сайт тоже посмотрю, спасибо.
Лиличка #590 #767366
ОП, проверь задачу, пожалуйста

http://ideone.com/tcJqI0
>>770094
#591 #767481
>>767064

>if


>if


>elseif


Нет логики.
Лучше

>if


>elseif


>else

#592 #767522
>>753595 (OP)
ОПче, что за хуйня? Yii, Symphony, Doctrine, Slim, Лар(в)ав(р)ель, апи вордпресса, не дохуища ли? Это все взаимозаменяемые фреймворки об одном и том же или они для разных задач? Я не вижу, чтобы в вакансиях, кроме совсем ебанутых, требовались одновременно Симфони и Yii
>>767718>>770094
#593 #767581
>>753595 (OP)
Ты что-нибудь слышал про пхп девелоп, wxphp, phpgtk? Пиздануто пытаться писать на пхэпхэ десктопные софтины или норм?
>>767718>>770094
#594 #767669
>>767003

> https://github.com/TheSidSpears/Students/blob/master/public/503.php#L1


> header(' ', true, 503);


> Что это за синтаксис? Что за пустой заголовок? По моему это не будет работать. Там надо отправлять заголоок вроде HTTP/1.1 503 xxxx, почитай хотя бы мануал по функции header().



Видел такой вариант на тостере, сейчас не найду, но чувак даже обосновывал, почему так правильней. Главное - 503 заголовок он передаёт, проверял

> chdir ('../')


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


Не очень понял. Мне в начале каждого адреса такую шнагу прописывать __DIR__.'/../ ?
>>767718>>770094
#595 #767718
>>767669

>Не очень понял. Мне в начале каждого адреса такую шнагу прописывать __DIR__.'/../ ?


Это из разрядка хороших практик. Представь, что ты на директрорию выше/ниже перенёс файл, который include'ит другой файл по относительному пути. Тогда тебе ещё придётся править относительный путь в перенесённом файле. А если бы использовал абсолютный путь к файлу, то ничего менять не пришлось бы.

>Видел такой вариант на тостере, сейчас не найду, но чувак даже обосновывал, почему так правильней. Главное - 503 заголовок он передаёт, проверял


Звучит как "так правильно, сам не помню почему, обосновывать не буду".

>>767522
>>767581

> хуйня


> дохуища


> ебанутых


> Пиздануто


> пхэпхэ


Ты прям из падика сюда пришёл? Перечисленные тобой обёртки над тулкитами для GUI пригодны разве что для личных нужд, никакой серьёзный софт на них не пишется.

> Я не вижу, чтобы в вакансиях, кроме совсем ебанутых, требовались одновременно Симфони и Yii


Я видел часто. Одногруппник работает джуном за 30k, пишет почти на всём, что ты перечислил + заставляют писать ещё на куче других CMS и фреймворках. Бывает, просто говорят так: "Следующий проект будет на X, разберись в нём за недельку, где находить время на это время - думай сам". И это обыденно, к тому же при должном опыте в смежных технологиях это не так уж и сложно.
#596 #767728
>>767189

> Я имел в виду сделать так: в контроллере мы создаем например объект


> new Translator('ru_RU')


Я не очень понимаю как в таком случае переводить эти строки через gettext. Сейчас у меня вот эта строка

>_("{0, plural, =0{No downloads} one{# download} other{# downloads}}")


Получается через gettext и при разных языках она будет разная. А если делать такой объект, то функция форматирования будет выглядеть как-то так

>{{ tr.format('download', { number: 2}) }}


Тогда получается что остальные варианты через gettext не задать?
Единственный вариант который могу придумать это такой:

>{{ tr.format('{0, plural, =0{No downloads} one{# download} other{# downloads}}', { number: 2}) }}


Он подойдет?

>А вообще конечно было былучше если бы временный файл не требовался.


В слиме при использовании функции moveTo оригинальный файл удаляется. https://github.com/slimphp/Slim/blob/3.x/Slim/Http/UploadedFile.php#L202 Я создаю временный чтобы не городить велосипедов с копированием в хелперах.
>>770094
someApprentice #597 #768205
А про меня не забыли? >>755591
57 Кб, 775x583
#598 #768310
В общем суть такова.
Мне 23 и я вообще не соображаю в программировании и, в колледже, уже начал тупить когда в паскале начались слова типа "массив". Сейчас работаю эникеем_техподдержкой, немного понимаю в винде, линуксе, сетях.
Не хочу заниматься заправкой картриджей и прочим дерьмом.
Когда читаю резюме на 25-35к джун пхп там какие-то непонятные для меня слова типа ООП, МVC и что-то про паттерны и красоту кода (для которых, видимо, нужно читать отдельные книжки)

Сейчас прохожу хтмл_академи, что дальше? Реально ли вкатиться (не занимаясь дизайном сайтов) и за какой срок? Везде требуют опыт работы с коммерческими проектами, который я не могу получить ПОТОМУ ЧТО ВЕЗДЕ ТРЕБУЮТ ОПЫТ.

Но это пожалуй не важно - самое важное это сколько времени необходимо чтобы вкатиться (разумеется учитывая что не фултайм дроч книжек, так как работа, я же не мильйонер сидеть дома 24/7 читать книжки) и КАКИЕ книжки читать.
Спасибо.
>>768946
#599 #768312
>>755591

> В задаче написано что множить сущности не желательно, это касается класса валидации для формы редактирования? Старый класс валидации всегда будет выдавать ошибку о том что такая почта уже занята, если её не поменять.


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

> Так же это касается паролей, даже если их заполнить теми же самыми данным, то всё равно сгенерируется новый хэш и токен, и авторизация сломается, потому что в куках находиться не актуальный токен. Как обойти обновление полей которые мы не хотим обновлять?


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

> Нужна ли валидация и список ошибок для формы поиска?


Да вообще не особо. Если форма содержит не-пробелы - делаем поиск, если не содержит - не делаем.

Этот класс https://github.com/someApprentice/Students/blob/master/app/Model/Entity/Search.php на мой взгляд не особо нужен.

> Как избавиться от $_GET['input'] в URL?


Не избавляться. А вообще, можно попробовать сделать button / input без названия и посмотреть что будет.

> А разве это не обязанность контроллера работать с $_GET данными?


Да, просто я имел в виду что index.php это и есть контроллер.

> >Для поиска по всем колонкам можно применить оператор LIKE к соединенным через пробел значениям столбцов.


> А можно простой пример такого запроса? У меня не получилось составить...


WHERE CONCAT(...) LIKE ....

> А почему в примере без плейсхолдера написано? Это только в рамках простого примера?


Там и значение жестко прописано, а не из переменно берется. Потому плейсхолдер не требуется. Это просто для примера.

> а как быть с формами? Допустим есть форма поиска с методом get и, насколько я знаю, её нельзя заставить отправлять этот запрос с помощью urlencode().


А зачем? Форму заполняет и отправляет пользователь ведь.
#599 #768312
>>755591

> В задаче написано что множить сущности не желательно, это касается класса валидации для формы редактирования? Старый класс валидации всегда будет выдавать ошибку о том что такая почта уже занята, если её не поменять.


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

> Так же это касается паролей, даже если их заполнить теми же самыми данным, то всё равно сгенерируется новый хэш и токен, и авторизация сломается, потому что в куках находиться не актуальный токен. Как обойти обновление полей которые мы не хотим обновлять?


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

> Нужна ли валидация и список ошибок для формы поиска?


Да вообще не особо. Если форма содержит не-пробелы - делаем поиск, если не содержит - не делаем.

Этот класс https://github.com/someApprentice/Students/blob/master/app/Model/Entity/Search.php на мой взгляд не особо нужен.

> Как избавиться от $_GET['input'] в URL?


Не избавляться. А вообще, можно попробовать сделать button / input без названия и посмотреть что будет.

> А разве это не обязанность контроллера работать с $_GET данными?


Да, просто я имел в виду что index.php это и есть контроллер.

> >Для поиска по всем колонкам можно применить оператор LIKE к соединенным через пробел значениям столбцов.


> А можно простой пример такого запроса? У меня не получилось составить...


WHERE CONCAT(...) LIKE ....

> А почему в примере без плейсхолдера написано? Это только в рамках простого примера?


Там и значение жестко прописано, а не из переменно берется. Потому плейсхолдер не требуется. Это просто для примера.

> а как быть с формами? Допустим есть форма поиска с методом get и, насколько я знаю, её нельзя заставить отправлять этот запрос с помощью urlencode().


А зачем? Форму заполняет и отправляет пользователь ведь.
>>768546
#600 #768314
>>753629

тоже не сахар

>>753632

Пикрелейтед это дамп БД. Погугли как импортировать дамп, хотя не знаю, поможет ли это тебе.
http://w99953g4.bget.ru/evently/ #601 #768317
>>753660

Ох, у тебя опять какой-то визуально перегруженный и тяжелочитаемый макет (это конечно претензия к дизайнеру, а не к тебе). Что подтверждает анимированная надпись "scroll down". Дизайнер сделал макет который выглядит как одностраничный сайт и вынужден объяснять что там внизу что-то еще есть.

Твой сайт постоянно ест от 5 до 10% CPU когда страница неподвижна. Попробуй покрутить, попереключать страницу, а затем открыть в отладчике Хрома вкладку timeline и записать несколько секунд. У меня например там какое-то нереальное число таймеров (242 срабатывания за секунду). Часто такое бывает при неправильном написании или подключении плагинов у людей которые плохо знают JS. Осваивай timeline и профайлер.

Более того, кастомная прокрутка, которую ты используешь, вообще плохо работает. Я привык что если я резко провожу пальцем по тачпаду то прокрутка получается сильнее, но твой плагин ее замедляет. Это неудобно. Я вообще не понимаю, зачем это нужно. Ну хочется тебе поменять внешний вид полосы прокрутки, ну поменяй, а зачем делать ее медленнее? Это ты сайт для людей с замедленным сознанием пишешь?

И я не понимаю, какая выгода от более тонкой линейки прокрутки. Толстую линейку можно перетащить мышью, тонкую нельзя. В чем выгода? Да, такая линейка прокрутки есть на макбуках, но там взамен есть удобный тачпад с кучей функций. Более того, если говорить о блоке "15 October Business Conference" то там вообще от линейки прокрутки один вред, удобнее было бы вывести весь список как есть. Прокрутка внутри прокрутки это ад с точки зрения юзабилити. И на мобильных платформах далеко не все пользователи знают как прокручивать такие блоки.

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

В разделе Sponsors стрелки прокручивают блок в противоположную сторону. И вообще, по моему задвигать спонсоров за блок прокрутки, где их никто не увидит (я никогда не жму на такие стрелки) неуважительно к ним.

Тут http://w99953g4.bget.ru/evently/js/ajax.js ты попытался сделать отправку форм аяксом, но не все учел. Прочитай этот урок: https://github.com/codedokode/pasta/blob/master/js/ajax.md

У тебя нет ни индикации прогресса, ни обработки ошибок, ни блокировки кнопки отправки.

Не уверен что хорошая идея выводить ошибки вверху страницы так как они оторваны от формы, если прокрутить страницу то вообще непонятно к чему относятся. Хотя.... кто знает.

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

Я еще тут бегло посмотрел и вот что я вижу:

- анимация при прокрутке. Анимация привлекает внимание, но какой смысл привлекать внимание к блокам, которые только что выехали снизу? Я и так вижу, что они выехали.
- если прокрутить страницу до раздела Speakers и попробовать выделить слово "vestibulum" во втором абзаце текста, то оно не выделяется. Почему? Потому что там див из слайдера с opacity = 0. Див может быть не виден, но он все равно там есть, он блокирует доступ к тексту, который лежит под ним. Если тебе интересно, то это див с классом "mCustomScrollBox mCS-light mCSB_vertical mCSB_inside"

> <h1 class="header__promo-header header-promo">london</h1>


> <h2 class="header__promo-header header-promo-caption">business <strong>conference</strong></h2>


По моему, заголовок страницы "London Business Conference", а не "London". Теги h1, h2 это не теги для задания размера текста, а теги для смысловой разметки содержимого.

Я вижу, ты везде используешь SVG. А изучал ли ты уровень поддержки SVG? Можешь ли назвать проблемы которые связаны с его использованием? Нельзя использовать такие сложные технологии без предварительного изучения, если конечно тебе не наплевать на результат.

Тем более что у тебя не просто SVG картинка, а используется инлайново вставленный код. Вот например какие проблемы я видел, когда рассматривал вариант использовать SVG в своем учебнике:

- стандарт SVG развивается и браузеры не поддерживают все фичи, которые поддерживают редакторы. Более того, иногда фичи, которые планировалось добавить в стандарт, отменяют. Например, форматирование текста которое есть в inkscape, в итоге убрали из стандарта и заверстанный в блок текст в браузере не отображается
- информации о том какие именно фичи поддерживаются какими бразерами, толком нигде нет. Каких-то автоматических скриптов-проверяльщиков для SVG картинки тоже нет. Непонятно как в таких условиях рисовать картинки, если неизвестно отобразится ли она и где.
- есть куча багов рендеринга, найти причину которым я не смог. Пример: в Хроме текст отображается нормально, на Андроиде все строчки наезжают друг на друга. Почему - непонятно, вроде никаких навороченных фич не используется.
- у тебя нет никакого фоллбека для браузеров, не поддерживающих SVG. Я вообще не понимаю, зачем так делают. Видимо хотят, чтобы как можно меньше людей могло прочитать их сайт, чтобы он отображался на как можно меньшем числе устройств. Что движет этими людьми, я не понимаю.
- непонятно, насколько их можно использовать в background-image

Я для себя сделал вывод, что сейчас SVG прямо на сайте использовать нельзя (и возможно, никогда не будет можно). Его можно использовать в подготовке картинок, но на сам сайт выгоднее ставить старые добрые PNG и джипеги (возможно, автоматически отрендеренные из SVG).

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

> <p class="p p--common-alt">


Что это за страное название? ЧТо за класс "p"?

Вот это файл тяжеловато читать: http://w99953g4.bget.ru/evently/js/sliders.js И код странный. Вот например, зачем так писать?

> zoomOut.attr('class','list-slider__item animated zoomOut');


А что будет, когда в верстке добавят новый класс? Твой код перезапишет его и он исчезнет. Почему не используешь add/removeClass?

И вообще, почему в слайдерах так много кода? Там нельзя разве обойтись средствами CSS? В мое время слайдер либо анимировал какой-нибудь scrollLeft либо просто переставлял классы на 2 элементах. Вот например, возьмем спонсоров. Там достаточно сделать див с overflow hidden и анимироват ему scrollLeft, единственная сложность - если нам надо закольцевать прокрутку.

Вообще, код читать тяжеловато. Вот как например понять, какой код отвечает за тот или иной слайдер? Я вижу слайдер в HTML коде, но какая функция его инициализиурет - непонятно. Как ее найти тоже непонятно. У тебя еще относительно маленький макет, а если бы это был большой сайт с кучей страниц и разделов?

Вообще, у тебя в яваскриптах какие-то стены кода без разбиения на части, например: http://w99953g4.bget.ru/evently/js/map.js

Тут вообще eval: http://w99953g4.bget.ru/evently/js/smooth-scroll.js

> setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);


Ну что за ерунда? Во-первых, надо использовать тут анонимную фнукцию, во-вторых, у тебя же jquery есть. И вообще, setTimeout не дает никаких гарантий что он будет вызываться с нужным интервалом. И для анимации есть requestAnimationFrame.

В общем, я тебе советую исправить все эти проблемы.
http://w99953g4.bget.ru/evently/ #601 #768317
>>753660

Ох, у тебя опять какой-то визуально перегруженный и тяжелочитаемый макет (это конечно претензия к дизайнеру, а не к тебе). Что подтверждает анимированная надпись "scroll down". Дизайнер сделал макет который выглядит как одностраничный сайт и вынужден объяснять что там внизу что-то еще есть.

Твой сайт постоянно ест от 5 до 10% CPU когда страница неподвижна. Попробуй покрутить, попереключать страницу, а затем открыть в отладчике Хрома вкладку timeline и записать несколько секунд. У меня например там какое-то нереальное число таймеров (242 срабатывания за секунду). Часто такое бывает при неправильном написании или подключении плагинов у людей которые плохо знают JS. Осваивай timeline и профайлер.

Более того, кастомная прокрутка, которую ты используешь, вообще плохо работает. Я привык что если я резко провожу пальцем по тачпаду то прокрутка получается сильнее, но твой плагин ее замедляет. Это неудобно. Я вообще не понимаю, зачем это нужно. Ну хочется тебе поменять внешний вид полосы прокрутки, ну поменяй, а зачем делать ее медленнее? Это ты сайт для людей с замедленным сознанием пишешь?

И я не понимаю, какая выгода от более тонкой линейки прокрутки. Толстую линейку можно перетащить мышью, тонкую нельзя. В чем выгода? Да, такая линейка прокрутки есть на макбуках, но там взамен есть удобный тачпад с кучей функций. Более того, если говорить о блоке "15 October Business Conference" то там вообще от линейки прокрутки один вред, удобнее было бы вывести весь список как есть. Прокрутка внутри прокрутки это ад с точки зрения юзабилити. И на мобильных платформах далеко не все пользователи знают как прокручивать такие блоки.

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

В разделе Sponsors стрелки прокручивают блок в противоположную сторону. И вообще, по моему задвигать спонсоров за блок прокрутки, где их никто не увидит (я никогда не жму на такие стрелки) неуважительно к ним.

Тут http://w99953g4.bget.ru/evently/js/ajax.js ты попытался сделать отправку форм аяксом, но не все учел. Прочитай этот урок: https://github.com/codedokode/pasta/blob/master/js/ajax.md

У тебя нет ни индикации прогресса, ни обработки ошибок, ни блокировки кнопки отправки.

Не уверен что хорошая идея выводить ошибки вверху страницы так как они оторваны от формы, если прокрутить страницу то вообще непонятно к чему относятся. Хотя.... кто знает.

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

Я еще тут бегло посмотрел и вот что я вижу:

- анимация при прокрутке. Анимация привлекает внимание, но какой смысл привлекать внимание к блокам, которые только что выехали снизу? Я и так вижу, что они выехали.
- если прокрутить страницу до раздела Speakers и попробовать выделить слово "vestibulum" во втором абзаце текста, то оно не выделяется. Почему? Потому что там див из слайдера с opacity = 0. Див может быть не виден, но он все равно там есть, он блокирует доступ к тексту, который лежит под ним. Если тебе интересно, то это див с классом "mCustomScrollBox mCS-light mCSB_vertical mCSB_inside"

> <h1 class="header__promo-header header-promo">london</h1>


> <h2 class="header__promo-header header-promo-caption">business <strong>conference</strong></h2>


По моему, заголовок страницы "London Business Conference", а не "London". Теги h1, h2 это не теги для задания размера текста, а теги для смысловой разметки содержимого.

Я вижу, ты везде используешь SVG. А изучал ли ты уровень поддержки SVG? Можешь ли назвать проблемы которые связаны с его использованием? Нельзя использовать такие сложные технологии без предварительного изучения, если конечно тебе не наплевать на результат.

Тем более что у тебя не просто SVG картинка, а используется инлайново вставленный код. Вот например какие проблемы я видел, когда рассматривал вариант использовать SVG в своем учебнике:

- стандарт SVG развивается и браузеры не поддерживают все фичи, которые поддерживают редакторы. Более того, иногда фичи, которые планировалось добавить в стандарт, отменяют. Например, форматирование текста которое есть в inkscape, в итоге убрали из стандарта и заверстанный в блок текст в браузере не отображается
- информации о том какие именно фичи поддерживаются какими бразерами, толком нигде нет. Каких-то автоматических скриптов-проверяльщиков для SVG картинки тоже нет. Непонятно как в таких условиях рисовать картинки, если неизвестно отобразится ли она и где.
- есть куча багов рендеринга, найти причину которым я не смог. Пример: в Хроме текст отображается нормально, на Андроиде все строчки наезжают друг на друга. Почему - непонятно, вроде никаких навороченных фич не используется.
- у тебя нет никакого фоллбека для браузеров, не поддерживающих SVG. Я вообще не понимаю, зачем так делают. Видимо хотят, чтобы как можно меньше людей могло прочитать их сайт, чтобы он отображался на как можно меньшем числе устройств. Что движет этими людьми, я не понимаю.
- непонятно, насколько их можно использовать в background-image

Я для себя сделал вывод, что сейчас SVG прямо на сайте использовать нельзя (и возможно, никогда не будет можно). Его можно использовать в подготовке картинок, но на сам сайт выгоднее ставить старые добрые PNG и джипеги (возможно, автоматически отрендеренные из SVG).

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

> <p class="p p--common-alt">


Что это за страное название? ЧТо за класс "p"?

Вот это файл тяжеловато читать: http://w99953g4.bget.ru/evently/js/sliders.js И код странный. Вот например, зачем так писать?

> zoomOut.attr('class','list-slider__item animated zoomOut');


А что будет, когда в верстке добавят новый класс? Твой код перезапишет его и он исчезнет. Почему не используешь add/removeClass?

И вообще, почему в слайдерах так много кода? Там нельзя разве обойтись средствами CSS? В мое время слайдер либо анимировал какой-нибудь scrollLeft либо просто переставлял классы на 2 элементах. Вот например, возьмем спонсоров. Там достаточно сделать див с overflow hidden и анимироват ему scrollLeft, единственная сложность - если нам надо закольцевать прокрутку.

Вообще, код читать тяжеловато. Вот как например понять, какой код отвечает за тот или иной слайдер? Я вижу слайдер в HTML коде, но какая функция его инициализиурет - непонятно. Как ее найти тоже непонятно. У тебя еще относительно маленький макет, а если бы это был большой сайт с кучей страниц и разделов?

Вообще, у тебя в яваскриптах какие-то стены кода без разбиения на части, например: http://w99953g4.bget.ru/evently/js/map.js

Тут вообще eval: http://w99953g4.bget.ru/evently/js/smooth-scroll.js

> setTimeout("window.scrollTo(0, "+leapY+")", timer * speed);


Ну что за ерунда? Во-первых, надо использовать тут анонимную фнукцию, во-вторых, у тебя же jquery есть. И вообще, setTimeout не дает никаких гарантий что он будет вызываться с нужным интервалом. И для анимации есть requestAnimationFrame.

В общем, я тебе советую исправить все эти проблемы.
>>768540
http://w99953g4.bget.ru/evently/ #602 #768318
>>753660

> Кроссбраузерностью по-прежнему не занимаюсь.


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

> В старых ослах даже не хочу открывать и вообще не знаю как с этой темой совладать. Как можно запомнить какие из сотен разных правил/значений как себя ведут в десятках проблемных версий разных браузеров?


По ИЕ у меня есть гайд для начинающих: https://gist.github.com/codedokode/855e3970124687b26a1c

Есть стандарты. Если брать например стандарт CSS2.1 то худо-бедно он поддерживается даже в ИЕ8.

По поводу других браузеров - есть сайт http://caniuse.com/. Дождись там 97-98% поддержки и используй. Это значит что технологии которые появлились в последние лет 5 можно использовать только с возмодностью фоллбека. Также, всегда старайся предусмотреть фоллбек. Например:

- ИЕ8 не умеет скруглять уголки - пусть будут квадратные, не надо ничего усложнять
- выводим SVG картинку через object с фоллбеком на PNG внутри либо через srcset (не уверен что это работает, я тестироал и по моему там что-то было не так)
- ставим такие цвета чтобы даже если картинка не загрузилась, текст был контрастным и читался
- пишем по несколько css правил подряд - старые браузеры прочтут первое, новые - оба и второе перекроет первое.

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

Помни что есть куча разных устройств, которые никогда не обновятся. Старый компьютер, где не идут новые браузеры. Андроид, который не обновляется в принципе. "умный" телевизор с браузером. И так далее.
>>768540
#603 #768400
ОП, я не понимат.
https://gist.github.com/codedokode/3f6063edf0a2227eb313
Чем марджины на флоатах принципиально отличаются от марджинов на не флоатах?
>>768504
#604 #768504
>>768400

Хороший вопрос. Я тут задумался, а где есть разница, и кое-что пришло мне в голову. Сравним поведение флоата и блочного элемента с width = auto.

Правый маргин на флоате влияет на расталкивание текста и инлайн-блоков в элементе, поверх которого он находится. Но на блочном элементе правый маргин будет растягивать/сужать сам элемент.

А вот левые маргины ведут себя одинаково: в обоих случаях они сдвигают левую границу элемента.
>>768614
175 Кб, 1200x560
99 Кб, 600x630
#605 #768540
>>768317
Привет, спасибо за отзыв.

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


Это готовый плагин так работает, всмысле помимо изменения внешнего вида тормозит скрол.

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


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

>В разделе Sponsors стрелки прокручивают блок в противоположную сторону


Левая стрелка - влево, правая - вправо, так и задумано/

>У тебя нет ни индикации прогресса, ни обработки ошибок, ни блокировки кнопки отправки.


Лень было, да и там всего по три поля.

>Но слайдеры в мобильной версии получились неудачные. например, в разделе Speakers ты можешь прокрутить до фото и переклчюать их, но при этом не видно что меняется блок с описанием


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

>Анимация привлекает внимание, но какой смысл привлекать внимание к блокам, которые только что выехали снизу? Я и так вижу, что они выехали.


Просто нескучный эффект. Часто вижу на промо-сайтах

>попробовать выделить слово


Когда-то натыкался на это, забыл исправить.

>По моему, заголовок страницы "London Business Conference", а не "London"


Может быть.

>ты везде используешь SVG. А изучал ли ты уровень поддержки SVG?


Читал попутно. Я намерено использовал самый крутой и моднейший способ вставки без оглядки на совместимость. Он позволяет рулить svg из css, например изменять цвет заливки фигуры. Вот у меня там несколько одинаковых по форме, но разного цвета иконок социальных в разных местах встречаются. В png-спрайт надо добавлять три разных иконки разных цветов и потом их крутить в background-position. При вставке через <svg><use ...sprite.svg#icon-facebook></svg> в самом svg-спрайте такая иконка-фигура всего одна и ее можно раскрашивать в css.
Зачем так? Показать на собеседовании какой я крутой. Вот смотрите, даже на ютабе, в гугле и вк иконокнет и мыло за 2300, а я вот так умею. Разумеется с оговоркой что если в ТЗ будут старые браузеры я подсуну им png, просто тут лень было так как проект учебный.

>ЧТо за класс "p"?


Тоже самое что и тег р, paragraph, наиболее общие правила для абзацов. Что-то типа классов .link, .btn и т. д.

>Вообще, у тебя в яваскриптах какие-то стены кода без разбиения на части, например: http://w99953g4.bget.ru/evently/js/map.js


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

>Тут вообще eval: http://w99953g4.bget.ru/evently/js/smooth-scroll.js


Это сворованный скрипт, не читал его, только скорость подобрал.

>Твой код перезапишет его и он исчезнет. Почему не используешь add/removeClass?


Знаю про этом. Уже не помню какая именно но была сложность с add/remove.

>В мое время слайдер либо анимировал какой-нибудь scrollLeft либо просто переставлял классы на 2 элементах


Я и так и так делаю. Спикеры например листаются перестановкой классов, а споносоры смещением дивов. Вот слайдер споносоров на 2 пике, по-моему тут абсолютный минимум кода.
>>768318
Не, ну я не такой уж нуб) Нагуглить какое свойство где поддерживается могу.
Просто, блин, так мурыжить каждую кнопочку и блочок постоянно заглядывать в справочник и дописывать сопли для ослов 6-7 и отказываться от современных решений когда фолбек невозможен это отстой. Из средств позиционирования там вообще походу кроме флоатов а то и таблиц ничего не останется. Если на работе скажут - тогда да, а пока учусь ну его в пень. Ну и поглядывая на вакансии я все чаще вижу что пишут что-то типа 'мучать ие 8- не будем'. Да и в конце концов, я вообще не в версталы собираюсь, прост творческий кризис в php, решил отвлечься на фронт.
175 Кб, 1200x560
99 Кб, 600x630
#605 #768540
>>768317
Привет, спасибо за отзыв.

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


Это готовый плагин так работает, всмысле помимо изменения внешнего вида тормозит скрол.

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


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

>В разделе Sponsors стрелки прокручивают блок в противоположную сторону


Левая стрелка - влево, правая - вправо, так и задумано/

>У тебя нет ни индикации прогресса, ни обработки ошибок, ни блокировки кнопки отправки.


Лень было, да и там всего по три поля.

>Но слайдеры в мобильной версии получились неудачные. например, в разделе Speakers ты можешь прокрутить до фото и переклчюать их, но при этом не видно что меняется блок с описанием


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

>Анимация привлекает внимание, но какой смысл привлекать внимание к блокам, которые только что выехали снизу? Я и так вижу, что они выехали.


Просто нескучный эффект. Часто вижу на промо-сайтах

>попробовать выделить слово


Когда-то натыкался на это, забыл исправить.

>По моему, заголовок страницы "London Business Conference", а не "London"


Может быть.

>ты везде используешь SVG. А изучал ли ты уровень поддержки SVG?


Читал попутно. Я намерено использовал самый крутой и моднейший способ вставки без оглядки на совместимость. Он позволяет рулить svg из css, например изменять цвет заливки фигуры. Вот у меня там несколько одинаковых по форме, но разного цвета иконок социальных в разных местах встречаются. В png-спрайт надо добавлять три разных иконки разных цветов и потом их крутить в background-position. При вставке через <svg><use ...sprite.svg#icon-facebook></svg> в самом svg-спрайте такая иконка-фигура всего одна и ее можно раскрашивать в css.
Зачем так? Показать на собеседовании какой я крутой. Вот смотрите, даже на ютабе, в гугле и вк иконокнет и мыло за 2300, а я вот так умею. Разумеется с оговоркой что если в ТЗ будут старые браузеры я подсуну им png, просто тут лень было так как проект учебный.

>ЧТо за класс "p"?


Тоже самое что и тег р, paragraph, наиболее общие правила для абзацов. Что-то типа классов .link, .btn и т. д.

>Вообще, у тебя в яваскриптах какие-то стены кода без разбиения на части, например: http://w99953g4.bget.ru/evently/js/map.js


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

>Тут вообще eval: http://w99953g4.bget.ru/evently/js/smooth-scroll.js


Это сворованный скрипт, не читал его, только скорость подобрал.

>Твой код перезапишет его и он исчезнет. Почему не используешь add/removeClass?


Знаю про этом. Уже не помню какая именно но была сложность с add/remove.

>В мое время слайдер либо анимировал какой-нибудь scrollLeft либо просто переставлял классы на 2 элементах


Я и так и так делаю. Спикеры например листаются перестановкой классов, а споносоры смещением дивов. Вот слайдер споносоров на 2 пике, по-моему тут абсолютный минимум кода.
>>768318
Не, ну я не такой уж нуб) Нагуглить какое свойство где поддерживается могу.
Просто, блин, так мурыжить каждую кнопочку и блочок постоянно заглядывать в справочник и дописывать сопли для ослов 6-7 и отказываться от современных решений когда фолбек невозможен это отстой. Из средств позиционирования там вообще походу кроме флоатов а то и таблиц ничего не останется. Если на работе скажут - тогда да, а пока учусь ну его в пень. Ну и поглядывая на вакансии я все чаще вижу что пишут что-то типа 'мучать ие 8- не будем'. Да и в конце концов, я вообще не в версталы собираюсь, прост творческий кризис в php, решил отвлечься на фронт.
#606 #768546
>>768312

>> В задаче написано что множить сущности не желательно, это касается класса валидации для формы редактирования? Старый класс валидации всегда будет выдавать ошибку о том что такая почта уже занята, если её не поменять.


>Значит надо исправить его чтобы он не сравнивал свою почту со своей, а только с другими.


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

>>768312

>> Так же это касается паролей, даже если их заполнить теми же самыми данным, то всё равно сгенерируется новый хэш и токен, и авторизация сломается, потому что в куках находиться не актуальный токен. Как обойти обновление полей которые мы не хотим обновлять?


>Сделать параметр какой-то который предается валидатору.


А что за параметр? Который сообщает игнорировать те или иные поля? Так придётся переделывать весь класс валидации, не проще ли помножить сущность и сделать новый?

Да и дело даже не в самом в валидаторе, а в запросе БД, т.к. он составлен так, что нам всегда нужно будет отправлять все данные из формы\сущности (https://github.com/someApprentice/Students/blob/master/app/Model/Gateway/StudentGateway.php#L103-L114), а хотелось бы что если в форме какое-то поле было пустым, то и запрос в БД составлялся без этого поля. Как составляются такие запросы? Неужели нужно писать отдельный метод который на основе сущности будет составлять запрос? Да и как этот метод сделать универсальным, ведь запросы могут быть разными (UPDATE\INSERT\SELECT\...)? Принимать в аргументы тип запроса а потом через case "ТИПЗАПРОСА" составлять сам запрос?

>>768312

>Этот класс https://github.com/someApprentice/Students/blob/master/app/Model/Entity/Search.php на мой взгляд не особо нужен.


Хм, значит сущности нужны только если у них есть какие-то особенные методы или много свойств?

>>768312

>> А разве это не обязанность контроллера работать с $_GET данными?


>Да, просто я имел в виду что index.php это и есть контроллер.


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

>>768312

>> а как быть с формами? Допустим есть форма поиска с методом get и, насколько я знаю, её нельзя заставить отправлять этот запрос с помощью urlencode().


>А зачем? Форму заполняет и отправляет пользователь ведь.


Оказалось что запрос сам как-то кодируется при отправке формы. Просто браузер в адресной строке отображал процентное кодирование в нормальном формате, и было не понятно почему при отправке формы в адресной строке можно использовать кириллицу, а в php нужно кодировать.
#606 #768546
>>768312

>> В задаче написано что множить сущности не желательно, это касается класса валидации для формы редактирования? Старый класс валидации всегда будет выдавать ошибку о том что такая почта уже занята, если её не поменять.


>Значит надо исправить его чтобы он не сравнивал свою почту со своей, а только с другими.


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

>>768312

>> Так же это касается паролей, даже если их заполнить теми же самыми данным, то всё равно сгенерируется новый хэш и токен, и авторизация сломается, потому что в куках находиться не актуальный токен. Как обойти обновление полей которые мы не хотим обновлять?


>Сделать параметр какой-то который предается валидатору.


А что за параметр? Который сообщает игнорировать те или иные поля? Так придётся переделывать весь класс валидации, не проще ли помножить сущность и сделать новый?

Да и дело даже не в самом в валидаторе, а в запросе БД, т.к. он составлен так, что нам всегда нужно будет отправлять все данные из формы\сущности (https://github.com/someApprentice/Students/blob/master/app/Model/Gateway/StudentGateway.php#L103-L114), а хотелось бы что если в форме какое-то поле было пустым, то и запрос в БД составлялся без этого поля. Как составляются такие запросы? Неужели нужно писать отдельный метод который на основе сущности будет составлять запрос? Да и как этот метод сделать универсальным, ведь запросы могут быть разными (UPDATE\INSERT\SELECT\...)? Принимать в аргументы тип запроса а потом через case "ТИПЗАПРОСА" составлять сам запрос?

>>768312

>Этот класс https://github.com/someApprentice/Students/blob/master/app/Model/Entity/Search.php на мой взгляд не особо нужен.


Хм, значит сущности нужны только если у них есть какие-то особенные методы или много свойств?

>>768312

>> А разве это не обязанность контроллера работать с $_GET данными?


>Да, просто я имел в виду что index.php это и есть контроллер.


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

>>768312

>> а как быть с формами? Допустим есть форма поиска с методом get и, насколько я знаю, её нельзя заставить отправлять этот запрос с помощью urlencode().


>А зачем? Форму заполняет и отправляет пользователь ведь.


Оказалось что запрос сам как-то кодируется при отправке формы. Просто браузер в адресной строке отображал процентное кодирование в нормальном формате, и было не понятно почему при отправке формы в адресной строке можно использовать кириллицу, а в php нужно кодировать.
>>770003
#607 #768563
Привет, почему при переопределении переменных в классе потомке, поля дублируются, а не переопределяются?

есть абстрактный класс Profession в котором есть поля:
private $salaryRate = 0; // базовая ставка
private $coffeeRate = 0; // кол-во выпиваемого кофе

От него наследуется класс Marketer, в котором переопределяются эти поля:
private $salaryRate = 400; // базовая ставка
private $coffeeRate = 15; // кол-во выпиваемого кофе

А var_dump показывает, что поля не переопределились а продублировались?

["salaryRate":"Marketer":private]=>
int(400)
["coffeeRate":"Marketer":private]=>
int(15)
["salaryRate":"Profession":private]=>
int(0)
["coffeeRate":"Profession":private]=>
int(0)
>>768573
#608 #768573
>>768563

Приватное поле принадлежит только одному классу. Его нельзя переопрделеить. Потому это не одно переопределенное поле, а 2 разных поля с одинаковым названием.
#609 #768614
>>768504

>Правый маргин на флоате влияет на расталкивание текста и инлайн-блоков в элементе, поверх которого он находится. Но на блочном элементе правый маргин будет растягивать/сужать сам элемент.


Я протестировал. Одинаковое предсказуемое поведение вышло. Правый марджин на флоате также растягивает/сужает флоат-блок.
>>768617
#610 #768617
>>768614

Плохо тестировал: https://jsfiddle.net/L41xne7f/

Увеличение правого маргина на обычном блоке сужает сам блок.
Увеличение правого маргина на флоате расталкивает текст дальше.
>>768685
#611 #768685
>>768617
https://jsfiddle.net/hxxebptq/
Ну естественно сужает обычный блок так как у него ширина все место занимает, а у флоата ширина по контенту. Попробуй во флоат контент на всю ширину вставить.
>>768761
#612 #768761
>>768685

Разница все же есть, когда контента мало. Обычный блок по умолчанию растягивается на максимальную ширину в родительском стакане, а флоат - на максимальную ширину своего содержимого с учетом ограничения родителя и минимальной ширины содержимого.
>>768767
#613 #768767
>>768761
Но это уже float behavior идет, а не поведение марджинов.
https://github.com/nsdvw/TestHub #614 #768780
>>755118
>>757712

Что-то у тебя в README ничего не сказано про выбор dev/prod окружения. Где это задается. я помню, разворачивал твой проект, и по моему на это наткнулся, что не для того окружения что-то сделал. Например, композер генерирует bootstrap cache для dev, а сайт работает с prod, точнее не работает по этой причине.

И как его тестировать-то? Ни одна кнопка на главной не работает же. Попробовал загрузить данные из fixtures - получаю ошибку:

> [Doctrine\DBAL\Exception\SyntaxErrorException]


> An exception occurred while executing 'DELETE FROM user':


> SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "user"


> LINE 1: DELETE FROM user


USER это ключевое слово, его в postgres надо как-то экранировать. По идее оно должно бы экранировать само, но по факту ничего не экранируется. В мануале доктрины что-то мутно упомянуто на эту тему: http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/basic-mapping.html#quoting-reserved-words

Также, есть такой баг: https://github.com/doctrine/doctrine2/issues/2409

Я попробовал в аннотации прописать имя таблицы user как ORM\Table(name="""user"""), но в ответ на это он начал падать с ошибкой

> SQLSTATE[42602]: Invalid name: 7 ERROR: invalid name syntax


> LINE 1: SELECT NEXTVAL('"user"_id_seq')


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

Подключил mysql, загрузил тестовые данные, открыл https://nsdvw-testhub-codedokode.c9users.io/test/1/preface и нажатие кнопки ведет почему-то на https://nsdvw-testhub-codedokode.c9users.io/app_dev.php/test/1/start . Пришлось руками исправлять адрес в форме.

Вообще, я сразу советую сделать отдельный класс для генерации URL. Там в Симфони есть функция path() в твиге, которая генериурет УРЛ из роутера, но на мой взгляд свой класс дает гораздо больше гибкости, например ты можешь писать штуки вроде function getStartTestUrl(Test $test).

Команда

> Run tests


> $ php phpunit.phar


Тоже не заработала, так как не скачан phpunit. Вообще, его можно указать в композере в require-dev, либо предупредить что надо его скачать.

В общем, после ковыряния настроек тесты выполнились успешно.

Также, я смотрю, продакшен и дев-конфиги оба используют parameters.yml, а тестовый - не использует. Почему так? Какая вообще логика в разнесении параметров?

Далее, вопрос с логгированием. Надо проверить как и куда логгируются следующие вещи:

- PHP Notice, пример: $a = []; $a['test'];
- PHP Error, пример: callNonExistentFunction()
- Exception, пример throw new Exception("test");

Проверить надо в dev, test и prod окружениях, для CLI команд и веб-скриптов. Если ты точно знаешь ответы, что и куда логгируется, то конечно можно не проверять. Я например не знаю. На практике очень часто сталкиваюсь что в разных проектах логи идут непонятно куда, никто их не смотрит и ошибки не исправляет.

Вообще, мне не нравится идея что ошибки пишутся непонятно куда. Чем тебе стандартный лог PHP не нравится?

В ридми ты пишешь:

> Create database


> $ php bin/console doctrine:database:create


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

В конфиге я вижу:

> twig:


> debug: "%kernel.debug%"


> strict_variables: "%kernel.debug%"


strict_variables определяет считать ли ошибкой обращение к несуществующей переменной. Почему в продакшене выбрана опция "и так сойдет"? Что, это уже не ошибка считается?

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

Обрабатывается ли у тебя ввод дробных чисел через запятую, как принято в России? через точку?

https://github.com/nsdvw/TestHub/blob/master/app/Resources/views/test/preface.html.twig#L19

> В тесте {{ wordCase(questionsCount, ['вопрос', 'вопроса', 'вопросов']) }},


О, велосипед для склонения слов. Вот я уже писал на эту тему в посте >>761042

--------

Кроме варианта писать функцию склонения руками, есть еще вариант раскурить расширение Intl: http://php.net/manual/ru/book.intl.php

Оно скопировано с Явы и там есть функция, которая позволяет делать в строку подстановки с учетом правил языка. Например: http://php.net/manual/ru/messageformatter.formatmessage.php

--------

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

Вообще, я бы тебе советовал немного изучить локализацию, библиотеки gettext и Intl.

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

https://github.com/nsdvw/TestHub/blob/master/app/Resources/views/test/question.html.twig#L27

> {% if question.type is same as('text') %}


> {% include 'test/text_question.html.twig' %}


Не удобнее ли использовать макросы для разных типов форм вместо инклюдов?

В контроллере https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Controller/TestController.php ты бы мог вместо постоянного написания $this->getDoctrine()->getManager(); сделать поле $this->em, аналогично для других популярных сервисов.

Не очень понял это место в startAction. Стоило бы добавить комментарий (о, и кстати, стоило бы наверно покрыть эту фичу тестом, так как это неочевидная штука которую легко сломать).

> if ($this->get('test_service')->hasActiveAttempt($user, $test)) {


> return $this->redirectToRoute('preface', ['testID' => $test->getId()]);



Ты создаешь временного пользователя в prefaceAction. Но по моему логичнее создавать его в startAction, так как это ПОСТ запрос, и логичнее изменения какие-то в базу вносить в нем. Для тестирования кук можно просто сделать куку has_cookies=1 или даже вынести это в отдельный мини-сервис CookieTester.
https://github.com/nsdvw/TestHub #614 #768780
>>755118
>>757712

Что-то у тебя в README ничего не сказано про выбор dev/prod окружения. Где это задается. я помню, разворачивал твой проект, и по моему на это наткнулся, что не для того окружения что-то сделал. Например, композер генерирует bootstrap cache для dev, а сайт работает с prod, точнее не работает по этой причине.

И как его тестировать-то? Ни одна кнопка на главной не работает же. Попробовал загрузить данные из fixtures - получаю ошибку:

> [Doctrine\DBAL\Exception\SyntaxErrorException]


> An exception occurred while executing 'DELETE FROM user':


> SQLSTATE[42601]: Syntax error: 7 ERROR: syntax error at or near "user"


> LINE 1: DELETE FROM user


USER это ключевое слово, его в postgres надо как-то экранировать. По идее оно должно бы экранировать само, но по факту ничего не экранируется. В мануале доктрины что-то мутно упомянуто на эту тему: http://doctrine-orm.readthedocs.io/projects/doctrine-orm/en/latest/reference/basic-mapping.html#quoting-reserved-words

Также, есть такой баг: https://github.com/doctrine/doctrine2/issues/2409

Я попробовал в аннотации прописать имя таблицы user как ORM\Table(name="""user"""), но в ответ на это он начал падать с ошибкой

> SQLSTATE[42602]: Invalid name: 7 ERROR: invalid name syntax


> LINE 1: SELECT NEXTVAL('"user"_id_seq')


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

Подключил mysql, загрузил тестовые данные, открыл https://nsdvw-testhub-codedokode.c9users.io/test/1/preface и нажатие кнопки ведет почему-то на https://nsdvw-testhub-codedokode.c9users.io/app_dev.php/test/1/start . Пришлось руками исправлять адрес в форме.

Вообще, я сразу советую сделать отдельный класс для генерации URL. Там в Симфони есть функция path() в твиге, которая генериурет УРЛ из роутера, но на мой взгляд свой класс дает гораздо больше гибкости, например ты можешь писать штуки вроде function getStartTestUrl(Test $test).

Команда

> Run tests


> $ php phpunit.phar


Тоже не заработала, так как не скачан phpunit. Вообще, его можно указать в композере в require-dev, либо предупредить что надо его скачать.

В общем, после ковыряния настроек тесты выполнились успешно.

Также, я смотрю, продакшен и дев-конфиги оба используют parameters.yml, а тестовый - не использует. Почему так? Какая вообще логика в разнесении параметров?

Далее, вопрос с логгированием. Надо проверить как и куда логгируются следующие вещи:

- PHP Notice, пример: $a = []; $a['test'];
- PHP Error, пример: callNonExistentFunction()
- Exception, пример throw new Exception("test");

Проверить надо в dev, test и prod окружениях, для CLI команд и веб-скриптов. Если ты точно знаешь ответы, что и куда логгируется, то конечно можно не проверять. Я например не знаю. На практике очень часто сталкиваюсь что в разных проектах логи идут непонятно куда, никто их не смотрит и ошибки не исправляет.

Вообще, мне не нравится идея что ошибки пишутся непонятно куда. Чем тебе стандартный лог PHP не нравится?

В ридми ты пишешь:

> Create database


> $ php bin/console doctrine:database:create


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

В конфиге я вижу:

> twig:


> debug: "%kernel.debug%"


> strict_variables: "%kernel.debug%"


strict_variables определяет считать ли ошибкой обращение к несуществующей переменной. Почему в продакшене выбрана опция "и так сойдет"? Что, это уже не ошибка считается?

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

Обрабатывается ли у тебя ввод дробных чисел через запятую, как принято в России? через точку?

https://github.com/nsdvw/TestHub/blob/master/app/Resources/views/test/preface.html.twig#L19

> В тесте {{ wordCase(questionsCount, ['вопрос', 'вопроса', 'вопросов']) }},


О, велосипед для склонения слов. Вот я уже писал на эту тему в посте >>761042

--------

Кроме варианта писать функцию склонения руками, есть еще вариант раскурить расширение Intl: http://php.net/manual/ru/book.intl.php

Оно скопировано с Явы и там есть функция, которая позволяет делать в строку подстановки с учетом правил языка. Например: http://php.net/manual/ru/messageformatter.formatmessage.php

--------

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

Вообще, я бы тебе советовал немного изучить локализацию, библиотеки gettext и Intl.

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

https://github.com/nsdvw/TestHub/blob/master/app/Resources/views/test/question.html.twig#L27

> {% if question.type is same as('text') %}


> {% include 'test/text_question.html.twig' %}


Не удобнее ли использовать макросы для разных типов форм вместо инклюдов?

В контроллере https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Controller/TestController.php ты бы мог вместо постоянного написания $this->getDoctrine()->getManager(); сделать поле $this->em, аналогично для других популярных сервисов.

Не очень понял это место в startAction. Стоило бы добавить комментарий (о, и кстати, стоило бы наверно покрыть эту фичу тестом, так как это неочевидная штука которую легко сломать).

> if ($this->get('test_service')->hasActiveAttempt($user, $test)) {


> return $this->redirectToRoute('preface', ['testID' => $test->getId()]);



Ты создаешь временного пользователя в prefaceAction. Но по моему логичнее создавать его в startAction, так как это ПОСТ запрос, и логичнее изменения какие-то в базу вносить в нем. Для тестирования кук можно просто сделать куку has_cookies=1 или даже вынести это в отдельный мини-сервис CookieTester.
https://github.com/nsdvw/TestHub #615 #768782
>>755118
>>757712

Некоторые вещи вроде этого

> $questionsCount = $this->get('test_service')->getQuestionsCount($test);


наверно было бы удобнее сделать не в сервисе, а в самом классе Test

> $form = $this->resolveForm($question, ['attempt_id' => $attemptID]);


здесь кстати интересный вопрос, а нельзя ли решить это на уровне FormType, то есть создать свой Type который поддерживает все виды вопросов и динамически отключает/включает поля в зависимости от типа вопроса. Либо подключает одну из 4 вложенных форм для разных типов ответов. Ты не рассматривал такой вариант?

$formType = new AnswerForm($answer);
$form = $this->createForm($formType, ....); // не помню точный синтаксис

А там примерно такой код:

1) первый вариант

if ($this->type == QUESTION_WITH_NUMBER) {
// для числового ответа подключаем поле ввода числа
$builder->add('numericAnswer', 'number', ...);
}

2) второй вариант с подформами:

$builder->add('answerType', 'hidden', ...);

if ($this->type == QUESTION_WITH_NUMBER) {
// для числового ответа подключаем соотв. форму
$builder->add('numericAnswer', new NumericAnswerType, ...);
}

Второй вариает потребует разобраться с особенностями маппинга полей формы на сущности. Тут тебе надо замапить numericAnswer на ту же сущность, а answerType не мапить вообще.

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

И еще странно, что у тебя в результате ответа на вопрос получается массив Answers. Мне казалось, там по логике должен быть один Answer, у которого может быть несколько AnswerChoices для ответа с чекбоксами.

Насчет flush - ты ставишь его везде, но ведь по идее это коммит транзакции. Может он должен быть только в конце action в контроллере? Вот в этом цикле

> foreach ($answers as $answer) {


> $repo->save($answer);



Явно делается не одна, а много транзакций, что плохо. Мне вообще этот метод save не нравится, по идее в случае с ORM нам достаточно изменить граф объектов в памяти и вызвать flush(). Правда не очень понятно, должны ли функции создания всяких объектов вызывать persist.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/DBAL/Platform.php
Тут есть ли правильное экранирование имени таблицы?

Насчет Fixtures - имей в виду что есть и другие способы описывать эти тестовые данные, например в YML: https://github.com/khepin/KhepinYamlFixturesBundle - может это позволит записывать их более лаконично (хотя и не позволяет вызывать сервисы).

И кстати, как я помню, еще Faker умеет заполнять модели как-то автоматически.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Repository/AnswerRepository.php#L65
Микрооптимизация: если сущность нужна только для простановки ссылки, можно загружать только прокси от нее через $em->getReference().

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Attempt.php#L16
Такую константу лучше назвать STATUS_ACTIVE. И использовать ее ниже:

> private $status = "active";



https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Question.php#L88

> if ($this->variants->toArray() === []) {


там же можно вызвать $this->variants->count()

> $variants = $this->getVariants()->toArray();


> foreach ($variants as $variant) {


Можно по моему напрямую перебирать ArrayCollection так как она поддерживает Iterator или что-то в этом роде, проверь исходники.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Question.php#L145

> public function setVariants($variants)


Это не setVariants, а addVariants

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Question.php#L129

> public function setAnswers($answers)


Очень неудачная функция, в нее нельзя передать массив например. Лучше делать clear() и затем через foreach добавлять.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Test.php#L42

> @ORM\Column(name="time_limit", type="integer", options={"default"=0})


> private $timeLimit;


Если по умолчанию 0, то и выставь такое значение для поля

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/User.php
Тут заданы уникальные ключи, например для email? да и просто индексы для поиска?

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Variant.php#L138

> @return string


> public function getIsRight()


по моему тут логичнее возвращать bool.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Form/Type/VariantAnswerForm.php#L11

> $data = $builder->getData();


Не обязательно использовать тут массив $data. можно просто сделать у класса методы вроде setIsMultiple() или передавать эти переменные в конструктор. Ты можешь вручную создать свой FormType:

$formType = new VariantAnswerForm(....);

и передать любые параметры.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Service/Calculator.php#L91
Не логичнее ли этот метод было сделать в классе Question или Answer? Чтобы методы проверки для разных классов были бы в них самих?

Вот все эти if/esleif плохи тем, что увеличивают объем работы при добавлении нового типа вопроса.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Twig/AppExtension.php#L81
Что-то у тебя тут сложно сделано определение формы слов. Там 3 или 4 ветки всего достаточно.

https://github.com/nsdvw/TestHub/blob/master/tests/TestHubBundle/TestCase.php
Тут ты делаешь doctrine:fixtures:load перед каждым тестом, но для многих тестов это не нужно. Наверно стоит сделать разные базовые классы либо отдельный метод который вызывается явно.

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

https://github.com/nsdvw/TestHub/blob/master/tests/TestHubBundle/Service/CalculatorTest.php
здесь я вижу такие слабые места:

- id тестов в базе жестко прописан
- если поменять данные в fixtures, тесты отвалятся

Возможно выгоднее было бы в тесте создавать нужные данные.

> $this->assertInternalType('integer', $maxMark);


> $this->assertEquals(30, $maxMark)


Вместо 2 строк можно использовать одну: https://phpunit.de/manual/current/en/appendixes.assertions.html#appendixes.assertions.assertSame

>>757712

> что такое REST


можно почитать тут: https://ru.wikipedia.org/wiki/REST

Идея там не только в УРЛ, но еще и например в том, что все нужные данные передаются явно, и надо избегать всяких сессий и подобных способов сохранять состояние.
https://github.com/nsdvw/TestHub #615 #768782
>>755118
>>757712

Некоторые вещи вроде этого

> $questionsCount = $this->get('test_service')->getQuestionsCount($test);


наверно было бы удобнее сделать не в сервисе, а в самом классе Test

> $form = $this->resolveForm($question, ['attempt_id' => $attemptID]);


здесь кстати интересный вопрос, а нельзя ли решить это на уровне FormType, то есть создать свой Type который поддерживает все виды вопросов и динамически отключает/включает поля в зависимости от типа вопроса. Либо подключает одну из 4 вложенных форм для разных типов ответов. Ты не рассматривал такой вариант?

$formType = new AnswerForm($answer);
$form = $this->createForm($formType, ....); // не помню точный синтаксис

А там примерно такой код:

1) первый вариант

if ($this->type == QUESTION_WITH_NUMBER) {
// для числового ответа подключаем поле ввода числа
$builder->add('numericAnswer', 'number', ...);
}

2) второй вариант с подформами:

$builder->add('answerType', 'hidden', ...);

if ($this->type == QUESTION_WITH_NUMBER) {
// для числового ответа подключаем соотв. форму
$builder->add('numericAnswer', new NumericAnswerType, ...);
}

Второй вариает потребует разобраться с особенностями маппинга полей формы на сущности. Тут тебе надо замапить numericAnswer на ту же сущность, а answerType не мапить вообще.

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

И еще странно, что у тебя в результате ответа на вопрос получается массив Answers. Мне казалось, там по логике должен быть один Answer, у которого может быть несколько AnswerChoices для ответа с чекбоксами.

Насчет flush - ты ставишь его везде, но ведь по идее это коммит транзакции. Может он должен быть только в конце action в контроллере? Вот в этом цикле

> foreach ($answers as $answer) {


> $repo->save($answer);



Явно делается не одна, а много транзакций, что плохо. Мне вообще этот метод save не нравится, по идее в случае с ORM нам достаточно изменить граф объектов в памяти и вызвать flush(). Правда не очень понятно, должны ли функции создания всяких объектов вызывать persist.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/DBAL/Platform.php
Тут есть ли правильное экранирование имени таблицы?

Насчет Fixtures - имей в виду что есть и другие способы описывать эти тестовые данные, например в YML: https://github.com/khepin/KhepinYamlFixturesBundle - может это позволит записывать их более лаконично (хотя и не позволяет вызывать сервисы).

И кстати, как я помню, еще Faker умеет заполнять модели как-то автоматически.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Repository/AnswerRepository.php#L65
Микрооптимизация: если сущность нужна только для простановки ссылки, можно загружать только прокси от нее через $em->getReference().

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Attempt.php#L16
Такую константу лучше назвать STATUS_ACTIVE. И использовать ее ниже:

> private $status = "active";



https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Question.php#L88

> if ($this->variants->toArray() === []) {


там же можно вызвать $this->variants->count()

> $variants = $this->getVariants()->toArray();


> foreach ($variants as $variant) {


Можно по моему напрямую перебирать ArrayCollection так как она поддерживает Iterator или что-то в этом роде, проверь исходники.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Question.php#L145

> public function setVariants($variants)


Это не setVariants, а addVariants

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Question.php#L129

> public function setAnswers($answers)


Очень неудачная функция, в нее нельзя передать массив например. Лучше делать clear() и затем через foreach добавлять.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Test.php#L42

> @ORM\Column(name="time_limit", type="integer", options={"default"=0})


> private $timeLimit;


Если по умолчанию 0, то и выставь такое значение для поля

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/User.php
Тут заданы уникальные ключи, например для email? да и просто индексы для поиска?

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Entity/Variant.php#L138

> @return string


> public function getIsRight()


по моему тут логичнее возвращать bool.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Form/Type/VariantAnswerForm.php#L11

> $data = $builder->getData();


Не обязательно использовать тут массив $data. можно просто сделать у класса методы вроде setIsMultiple() или передавать эти переменные в конструктор. Ты можешь вручную создать свой FormType:

$formType = new VariantAnswerForm(....);

и передать любые параметры.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Service/Calculator.php#L91
Не логичнее ли этот метод было сделать в классе Question или Answer? Чтобы методы проверки для разных классов были бы в них самих?

Вот все эти if/esleif плохи тем, что увеличивают объем работы при добавлении нового типа вопроса.

https://github.com/nsdvw/TestHub/blob/master/src/TestHubBundle/Twig/AppExtension.php#L81
Что-то у тебя тут сложно сделано определение формы слов. Там 3 или 4 ветки всего достаточно.

https://github.com/nsdvw/TestHub/blob/master/tests/TestHubBundle/TestCase.php
Тут ты делаешь doctrine:fixtures:load перед каждым тестом, но для многих тестов это не нужно. Наверно стоит сделать разные базовые классы либо отдельный метод который вызывается явно.

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

https://github.com/nsdvw/TestHub/blob/master/tests/TestHubBundle/Service/CalculatorTest.php
здесь я вижу такие слабые места:

- id тестов в базе жестко прописан
- если поменять данные в fixtures, тесты отвалятся

Возможно выгоднее было бы в тесте создавать нужные данные.

> $this->assertInternalType('integer', $maxMark);


> $this->assertEquals(30, $maxMark)


Вместо 2 строк можно использовать одну: https://phpunit.de/manual/current/en/appendixes.assertions.html#appendixes.assertions.assertSame

>>757712

> что такое REST


можно почитать тут: https://ru.wikipedia.org/wiki/REST

Идея там не только в УРЛ, но еще и например в том, что все нужные данные передаются явно, и надо избегать всяких сессий и подобных способов сохранять состояние.
66 Кб, 1280x720
#616 #768847
>>769949
#617 #768946
>>768310
Просто берешь и вкатываешься, ничего сложного же. А вообще да, придется учить ООП, MVC, красоту кода, архитектуру и другие сложные вещи. Теперь большой секрет - самый ценный ресурс это твое время, пока оно у тебя есть, можно выучить хоть что угодно и пройти любое собеседование. На работе у тебя этого времени уже не будет, а выполнять ты будешь по большей части однообразные задачи вроде натягивания шкур на вордпресс, которые тебя никак не продвинут. Поэтому многие программисты на работах застревают как в болоте, просто времени нет пробовать все новое и современное. Так что пока у тебя время есть, пользуйся, осваивай технологии из вакансий, читай книжки (в шапке кстати хорошие) и пиши красивый код с нормальной архитектурой. Потом тупо идешь, и рассказываешь о своих навыках на собеседовании, показываешь тестовые проекты на гитхабе, и тебя берут. Так и становятся программистами.
>>768973
#618 #768973
>>768946

>осваивай технологии из вакансий


Без базы он игрушка базы.
#619 #769194
Давно не виделись! Наконец-то сессия подошла к концу.

http://ideone.com/8PBPes // Антикризиные меры (версия 2)

Внес изменения в Антикризисные меры, по прошлым комментариям. Убрал новый класс NewAnalyst, который использовал для повышения ставки. Сделал с помощью метода переназначения поля salaryRate внутри Profession.
Убрал статические методы, попробовал парсить регуляркой ранг при создании сотрудников.
Изменил алгоритм в первом наборе антикризисных мер, выглядит сложнее, т.к. пришлось сортировать массив работников по рангу. И т.д.
>>769992
#620 #769691
Какими соображениями руководствоваться при выборе типа наследования (в базе)?
Вот у Фаулера три типа наследования, и какой мне выбрать?
Выбираю sti, потому что одна таблица без всяких джойнов.
Зачем нужны остальные типы наследования (concrete и class ti), в чем преимущество?
Предположим, избегают null-полей. Встает вопрос, чем плохи null-поля?
Погуглил, оказывается в mysql null таки занимает место (8 штук null в одной записи занимает 1 байт).

Кроме этой оптимизации может есть еще какие-нибудь соображения в пользу паттернов с кучей таблиц?
Хорошо, допустим нас не устраивает количество места, занимаемое на диске null-значениями (1 мегабайт на миллион записей это очень много, у нас ведь дискета вместо ssd).
Что дальше, какой из двух многотабличных паттернов выбрать?
В случае class ti (если я правильно понял дурацкую схему с какими-то футболистами и крикетистами) есть одна таблица, куда сохраняются общие для всех классов поля, и по одной дополнительной на каждый класс. Это получается нужно сначала вставить часть данных в эту общую таблицу, затем оставшиеся данные вместе с полученным идентификатором вставить в соответствующую классу таблицу? То есть тут вдобавок еще и транзакция.
В случае concrete ti нет никаких общих таблиц, для каждого класса отдельная таблица, где хранятся все данные.
Тогда какой смысл вообще в существовании class ti? Тут и транзакция, и внешний ключ, еще один джойн.

Я просто пытаюсь понять, в какой ситуации какой патерн применять, не тыкать же наугад.

update: пришлось лезть в первоисточник, то есть к Фаулеру.
Говорит, проблема с concrete ti в том, что при изменении класса модели придется править структуру всех связанных таблиц.
class ti - много джойнов.
sti - wasted space (неужели это так существенно?)

Наверное, на практике нужно не полениться создать все 3 варианта и протестировать производительность, потому что пока непонятно что брать.
>>769920
#621 #769920
>>769691

class ti это когда на каждый класс, включая базовые, делается таблица. Поля не дублируются (поле name хранится в таблице базового класса). concrete ti это когда таблица делается только для конкретных классов, а не для базовых. Поля базового класса (вроде name) дублируются во всех наследниках.

> Какими соображениями руководствоваться


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

> Зачем нужны остальные типы наследования (concrete и class ti), в чем преимущество?


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

> Погуглил, оказывается в mysql null таки занимает место (8 штук null в одной записи занимает 1 байт).


Неправильно погуглил. 1 бит занимает флаг наличия NULL в определенной колонке. А также, нужно место под значение этой колонки. Например 4 байта для INT, 8 байтов для BIGINT, N x 3 для строки типа CHAR, и тд. То есть int(10) DEFAULT NULL для одной строки займет 4 байта + 1 бит на флаг наличия NULL.

В БД как правило используются записи фиксированного размера так, чтобы каждая строчка таблицы имела в файле одинаковую длину. Это позволяет быстро найти расположение N-й строки. То есть неважно, NULL там или не NULL, места это займет одинаково.

Однако динамические поля типа VARCHAR, TEXT, обычно реализуются так: в строке закладывается N байт для коротких текстов, если текст не вмещается туда, то он помещается в отдельную область.

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

> Тогда какой смысл вообще в существовании class ti? Тут и транзакция, и внешний ключ, еще один джойн.


Возможность разрешить ставить внешние ключи только на класс и его наследников. Отсутствие дублирования поля из базового класса во всех наследниках.

> Говорит, проблема с concrete ti в том, что при изменении класса модели придется править структуру всех связанных таблиц.


Не считаю это большой проблемой, так как это происходит редко, а не постоянно.

> sti - wasted space (неужели это так существенно?)


Зависит от состава полей. Сами по себе 4 или 40 мегабайт на диске не страшны. Но если лишних полей много, то все ухудшается. Строчки начинают занимать больше байт, дольше грузятся с диска, занимают больше памяти (и с большей вероятностью в нее не поместятся). То есть 2-3 поля это не страшно. А если там 30 лишних полей?

Я могу привести еще такой пример. Допустим у нас есть большая таблица с 50 полями (инфа о пользователе в соцсети). Хорошо ли это? Ведь когда ты пишешь SELECT * FROM ... выбираются все поля. Если ты используешь ORM вроде доктрины, то мапятся все поля, и ты вынужден выбирать сущность с 50 полями (что наверно будет медленнее чем сущность с 10 полями, хотя это стоит проверять тестом). То есть ты выбираешь пользователя, который оставил сообщение на стене, и выбираются все 50 полей, хотя нам нужны только id, имя и аватарка.

В такой ситуации может быть есть смысл разбить таблицу на 2 - базовая информация о пользователе (которая нужна почти везде) и подробная.

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


Ты смотри, как тебе удобно будет писать запросы, работает ли это с твоим фреймворком, удобно ли ставить внешние ключи и тд.
#621 #769920
>>769691

class ti это когда на каждый класс, включая базовые, делается таблица. Поля не дублируются (поле name хранится в таблице базового класса). concrete ti это когда таблица делается только для конкретных классов, а не для базовых. Поля базового класса (вроде name) дублируются во всех наследниках.

> Какими соображениями руководствоваться


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

> Зачем нужны остальные типы наследования (concrete и class ti), в чем преимущество?


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

> Погуглил, оказывается в mysql null таки занимает место (8 штук null в одной записи занимает 1 байт).


Неправильно погуглил. 1 бит занимает флаг наличия NULL в определенной колонке. А также, нужно место под значение этой колонки. Например 4 байта для INT, 8 байтов для BIGINT, N x 3 для строки типа CHAR, и тд. То есть int(10) DEFAULT NULL для одной строки займет 4 байта + 1 бит на флаг наличия NULL.

В БД как правило используются записи фиксированного размера так, чтобы каждая строчка таблицы имела в файле одинаковую длину. Это позволяет быстро найти расположение N-й строки. То есть неважно, NULL там или не NULL, места это займет одинаково.

Однако динамические поля типа VARCHAR, TEXT, обычно реализуются так: в строке закладывается N байт для коротких текстов, если текст не вмещается туда, то он помещается в отдельную область.

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

> Тогда какой смысл вообще в существовании class ti? Тут и транзакция, и внешний ключ, еще один джойн.


Возможность разрешить ставить внешние ключи только на класс и его наследников. Отсутствие дублирования поля из базового класса во всех наследниках.

> Говорит, проблема с concrete ti в том, что при изменении класса модели придется править структуру всех связанных таблиц.


Не считаю это большой проблемой, так как это происходит редко, а не постоянно.

> sti - wasted space (неужели это так существенно?)


Зависит от состава полей. Сами по себе 4 или 40 мегабайт на диске не страшны. Но если лишних полей много, то все ухудшается. Строчки начинают занимать больше байт, дольше грузятся с диска, занимают больше памяти (и с большей вероятностью в нее не поместятся). То есть 2-3 поля это не страшно. А если там 30 лишних полей?

Я могу привести еще такой пример. Допустим у нас есть большая таблица с 50 полями (инфа о пользователе в соцсети). Хорошо ли это? Ведь когда ты пишешь SELECT * FROM ... выбираются все поля. Если ты используешь ORM вроде доктрины, то мапятся все поля, и ты вынужден выбирать сущность с 50 полями (что наверно будет медленнее чем сущность с 10 полями, хотя это стоит проверять тестом). То есть ты выбираешь пользователя, который оставил сообщение на стене, и выбираются все 50 полей, хотя нам нужны только id, имя и аватарка.

В такой ситуации может быть есть смысл разбить таблицу на 2 - базовая информация о пользователе (которая нужна почти везде) и подробная.

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


Ты смотри, как тебе удобно будет писать запросы, работает ли это с твоим фреймворком, удобно ли ставить внешние ключи и тд.
Ответы #622 #769949
>>768847
>>760508

> W5.1(Циклы и айфон в кредит)


> Исправлено: http://ideone.com/L6aoa6


Верно, хотя можно еще заменить if на min/max и чуть сократить код.

> W5.2(Циклы и айфон в кредит)


> Исправлено: http://ideone.com/v5HZxH


Верно, хотя $bill += $bill*0.1; можно записать и через *=

> Строки, хакеры и шифровки (На словах ты Лев Толстой


> Исправлено: http://ideone.com/KRk3Cf


Верно

> Строки, хакеры и шифровки (Палиндром


> Исправлено: http://ideone.com/5e8zEf


Верно

> Функции и новый айпад http://ideone.com/shMxHY


> Исправлено: http://ideone.com/Ioflg2


Верно

> Регулярные выражения


> Исправлено: http://ideone.com/QqtN4d


Ох, опять не так. Я имел в виде выводить например такой список:

[✓] +7123456789 правильный
[✓] 123456789 неправильный
[❌] +723456789 неправильный

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

Ну вообще, это мелочи, можешь просто учесть это на будущее.

> Регулярные выражения


> Исправлено: https://ideone.com/2fLm31


Ты перестарался - в именах доменах нет подчеркиваний, а вот в имени пользователя перед @ может быть и подчеркивание и плюс (и другие сложные знаки которые нас не интересуют). Если что, статьи по теме (делать то, что там описано, не надо!):

- https://habrahabr.ru/post/274985/
- https://habrahabr.ru/post/175375/
- https://habrahabr.ru/post/55820/
- https://habrahabr.ru/post/224623/
- https://habrahabr.ru/post/280798/

> Регулярные выражения https://ideone.com/gDM38S


Почти верно, но вот тут есть проблемка:

> * +(a |но )


Ты ждешь что после союза будет пробел, но там может быть знак вопроса, запятая, и тд.

> Регулярные выражения https://ideone.com/t8Mq2K


Тут слово "зделал" будет заменено даже если оно - част другого слова, например, "разделать тушу на части". И та же проблема с пробелом после а/но.

> Регулярные выражения http://ideone.com/BPGuYs


Вполне нормальное решение.

> Промежуточные версии:


> http://ideone.com/jicK9b


на мой взгляд не очень удачно что там ограничен список латинских букв. Вдруг ты какую-то букву пропустишь.
Ответы #622 #769949
>>768847
>>760508

> W5.1(Циклы и айфон в кредит)


> Исправлено: http://ideone.com/L6aoa6


Верно, хотя можно еще заменить if на min/max и чуть сократить код.

> W5.2(Циклы и айфон в кредит)


> Исправлено: http://ideone.com/v5HZxH


Верно, хотя $bill += $bill*0.1; можно записать и через *=

> Строки, хакеры и шифровки (На словах ты Лев Толстой


> Исправлено: http://ideone.com/KRk3Cf


Верно

> Строки, хакеры и шифровки (Палиндром


> Исправлено: http://ideone.com/5e8zEf


Верно

> Функции и новый айпад http://ideone.com/shMxHY


> Исправлено: http://ideone.com/Ioflg2


Верно

> Регулярные выражения


> Исправлено: http://ideone.com/QqtN4d


Ох, опять не так. Я имел в виде выводить например такой список:

[✓] +7123456789 правильный
[✓] 123456789 неправильный
[❌] +723456789 неправильный

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

Ну вообще, это мелочи, можешь просто учесть это на будущее.

> Регулярные выражения


> Исправлено: https://ideone.com/2fLm31


Ты перестарался - в именах доменах нет подчеркиваний, а вот в имени пользователя перед @ может быть и подчеркивание и плюс (и другие сложные знаки которые нас не интересуют). Если что, статьи по теме (делать то, что там описано, не надо!):

- https://habrahabr.ru/post/274985/
- https://habrahabr.ru/post/175375/
- https://habrahabr.ru/post/55820/
- https://habrahabr.ru/post/224623/
- https://habrahabr.ru/post/280798/

> Регулярные выражения https://ideone.com/gDM38S


Почти верно, но вот тут есть проблемка:

> * +(a |но )


Ты ждешь что после союза будет пробел, но там может быть знак вопроса, запятая, и тд.

> Регулярные выражения https://ideone.com/t8Mq2K


Тут слово "зделал" будет заменено даже если оно - част другого слова, например, "разделать тушу на части". И та же проблема с пробелом после а/но.

> Регулярные выражения http://ideone.com/BPGuYs


Вполне нормальное решение.

> Промежуточные версии:


> http://ideone.com/jicK9b


на мой взгляд не очень удачно что там ограничен список латинских букв. Вдруг ты какую-то букву пропустишь.
Вектор #623 #769992
>>769194

> http://ideone.com/8PBPes // Антикризиные меры (версия 2)



> // Присвоение профессии сотруднику


> $this->profession = $profession;


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

Хуже того, там ниже комментарии не соответствуют функциям.

> public function __construct($profession


Тут бы нужен тайп хинт

> $tmpxRank = $this->rankSalary[$this->rank];


Название плохое, почему не просто salaryMultiplier ?

>class Manager extends Profession


> protected $salaryRate = 500; // базовая ставка


> public function getProduct()


А почему одно из значений сделано абстрактным методом, а другое - полем? Разве не логично для всех 3 полей сделать абстр. методы? Чтобы гарантированно не забыли их переопределить?

> public function findDepartamentByName($name = null)


> {


> $result; // ссылка на департамент или массив департаментов


Что это за синтаксис такой? На мой взгляд, это обращение к несуществующей пока переменной $result.

> // Если сотрудник соответствует профессии


> if ($employee->getProfession()->getName() == $profession) {


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

> $profession != 'all'


По идее эту строку тоже надо бы заменить на константу например с названием FIND_ANY

> class AnticrisisCommittee


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

> // Клонирует компанию


> public function cloneCompany($company)


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

> // Запрашивавем все департаменты в компании


> $departaments = $this->companyClone->findDepartamentByName();


Тут название не соответствует смыслу функции. Наверно лучше было сделать отдельный метод getAllDepartments.

> // Исключаем из списка босса


> foreach ($engineers as $key => $engineer) {


Это можно еще сделать через array_filter: $x = array_filter($x, function (...) {...});

> sort($engineers);


Очень странная сортировка. Объекты это не числа, чтобы их так сортировать. В данном случае логичнее применить usort где будет указана функция с критерием сортировки по рангу. Или, если ты хотел перенумеровать массив (а зачем?), то надо использовать более быстрый array_values.

> // Сортируем массив работников по рангу по возрастанию


> // Внешний цикл повторяется до тех пор,


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

> / Берем первые 40% через array_slice


> $engineers = array_slice($engineers, $dismissingEngineers);


Неправильно, так ты отберешь 60%

> public function setSalaryRate($salary)


> {


> $this->profession->setSalaryRate($salary);


Вот здесь у нас серьезная проблема. Что, если все работники содержат ссылку на один и тот же объект профессии? Тогда этот метод меняет зарплату всех этих работников. Я вижу, у тебя так и сделано.

Ты читал внимательно раздел про копирование объектов? Когда ты передаешь объект професссии, его копии не делается, все работники содержат ссылку на один и тот же объект.

Ты можешь конечно создавать каждому работнику новый объект профессии. Но это не очень соответствует логике ООП (почему одна профессия представлена множеством, а не одним объектом?), хотя в данной задаче и приемлемо, если объявить, что это не "профессия", а "информация о должности работника". Но тогда остается другая проблема: а как гарантировать что пользователь не передаст один объект профессии нескольким работникам? Я думаю, выходом могла бы быть замена агрегации и композиции. Если ты читал мой урок по ООП то должен помнить, что разница между ними в том, где создаются вложенные объекты и могут ли они существовать отдельно.

> // Если таковых нет, переходим к следующему департаменту


> if (!$analysts) continue;


В общем-то эта строка не нужна.

> // Находим аналитика самого высокого ранга


> // Повторяем для всех рангов, начиная с самого высокого


> for ($rank = 3; $rank > 0; $rank--) {


по моему проще взять всех аналитиков, отсортировать по рангу и взять верхнего

> // Назначаем Аналитика шефом


> $analyst->setСhief(1);


> // Снимаем с должности текущего шефа


> $chiefEmployee->setСhief(0);


Это явно нарушение инкапсуляции. Разве замена босса - это не задача департамента? Ты же вместо этого должен копировать сложный код каждый раз как захочешь его поменять.

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

// Ищем всех работников выше 2 ранга
$people = $department->findPeople(function ($e) { return $e->getRank() > 2; })

Как ты думаешь? А для поиска босса наверно лучше сделать отдельную функцию.

> // Выводим статистику на печать


> public function printStat($message)


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

> // Достаем название профессии из вакансии


> $professionIndex = mb_substr($vacancyName, 0, 2);


> $profession = $professions[$professionIndex];


> // Достаем ранг и из вакансии


> preg_match ('/\d/', $vacancyName, $matches1);


Вообще регуляркой можно достать сразу название, ранг и количество из строки вроде '3me1boss' - через $matches[1], [2] и тд
Вектор #623 #769992
>>769194

> http://ideone.com/8PBPes // Антикризиные меры (версия 2)



> // Присвоение профессии сотруднику


> $this->profession = $profession;


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

Хуже того, там ниже комментарии не соответствуют функциям.

> public function __construct($profession


Тут бы нужен тайп хинт

> $tmpxRank = $this->rankSalary[$this->rank];


Название плохое, почему не просто salaryMultiplier ?

>class Manager extends Profession


> protected $salaryRate = 500; // базовая ставка


> public function getProduct()


А почему одно из значений сделано абстрактным методом, а другое - полем? Разве не логично для всех 3 полей сделать абстр. методы? Чтобы гарантированно не забыли их переопределить?

> public function findDepartamentByName($name = null)


> {


> $result; // ссылка на департамент или массив департаментов


Что это за синтаксис такой? На мой взгляд, это обращение к несуществующей пока переменной $result.

> // Если сотрудник соответствует профессии


> if ($employee->getProfession()->getName() == $profession) {


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

> $profession != 'all'


По идее эту строку тоже надо бы заменить на константу например с названием FIND_ANY

> class AnticrisisCommittee


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

> // Клонирует компанию


> public function cloneCompany($company)


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

> // Запрашивавем все департаменты в компании


> $departaments = $this->companyClone->findDepartamentByName();


Тут название не соответствует смыслу функции. Наверно лучше было сделать отдельный метод getAllDepartments.

> // Исключаем из списка босса


> foreach ($engineers as $key => $engineer) {


Это можно еще сделать через array_filter: $x = array_filter($x, function (...) {...});

> sort($engineers);


Очень странная сортировка. Объекты это не числа, чтобы их так сортировать. В данном случае логичнее применить usort где будет указана функция с критерием сортировки по рангу. Или, если ты хотел перенумеровать массив (а зачем?), то надо использовать более быстрый array_values.

> // Сортируем массив работников по рангу по возрастанию


> // Внешний цикл повторяется до тех пор,


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

> / Берем первые 40% через array_slice


> $engineers = array_slice($engineers, $dismissingEngineers);


Неправильно, так ты отберешь 60%

> public function setSalaryRate($salary)


> {


> $this->profession->setSalaryRate($salary);


Вот здесь у нас серьезная проблема. Что, если все работники содержат ссылку на один и тот же объект профессии? Тогда этот метод меняет зарплату всех этих работников. Я вижу, у тебя так и сделано.

Ты читал внимательно раздел про копирование объектов? Когда ты передаешь объект професссии, его копии не делается, все работники содержат ссылку на один и тот же объект.

Ты можешь конечно создавать каждому работнику новый объект профессии. Но это не очень соответствует логике ООП (почему одна профессия представлена множеством, а не одним объектом?), хотя в данной задаче и приемлемо, если объявить, что это не "профессия", а "информация о должности работника". Но тогда остается другая проблема: а как гарантировать что пользователь не передаст один объект профессии нескольким работникам? Я думаю, выходом могла бы быть замена агрегации и композиции. Если ты читал мой урок по ООП то должен помнить, что разница между ними в том, где создаются вложенные объекты и могут ли они существовать отдельно.

> // Если таковых нет, переходим к следующему департаменту


> if (!$analysts) continue;


В общем-то эта строка не нужна.

> // Находим аналитика самого высокого ранга


> // Повторяем для всех рангов, начиная с самого высокого


> for ($rank = 3; $rank > 0; $rank--) {


по моему проще взять всех аналитиков, отсортировать по рангу и взять верхнего

> // Назначаем Аналитика шефом


> $analyst->setСhief(1);


> // Снимаем с должности текущего шефа


> $chiefEmployee->setСhief(0);


Это явно нарушение инкапсуляции. Разве замена босса - это не задача департамента? Ты же вместо этого должен копировать сложный код каждый раз как захочешь его поменять.

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

// Ищем всех работников выше 2 ранга
$people = $department->findPeople(function ($e) { return $e->getRank() > 2; })

Как ты думаешь? А для поиска босса наверно лучше сделать отдельную функцию.

> // Выводим статистику на печать


> public function printStat($message)


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

> // Достаем название профессии из вакансии


> $professionIndex = mb_substr($vacancyName, 0, 2);


> $profession = $professions[$professionIndex];


> // Достаем ранг и из вакансии


> preg_match ('/\d/', $vacancyName, $matches1);


Вообще регуляркой можно достать сразу название, ранг и количество из строки вроде '3me1boss' - через $matches[1], [2] и тд
>>770125>>770821
#624 #770003
>>768546

> Тогда для метода валидатора нужно будет добавить аргумент с id.


> А как будущие разработчики поймут зачем здесь этот аргумент? Даже если бы он был не обязательным, я бы не сразу понял зачем методу проверки имейла нужно что-то кроме имейла


назови его "пропуститьПользователяСИд" и напиши комментарий перед функцией.

> А что за параметр? Который сообщает игнорировать те или иные поля? Так придётся переделывать весь класс валидации, не проще ли помножить сущность и сделать новый?


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

> Да и дело даже не в самом в валидаторе, а в запросе БД, т.к. он составлен так, что нам всегда нужно будет отправлять все данные из формы\сущности


Значит надо его исправить.

> а хотелось бы что если в форме какое-то поле было пустым, то и запрос в БД составлялся без этого поля.


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

> Как составляются такие запросы? Неужели нужно писать отдельный метод который на основе сущности будет составлять запрос?


Вообще, в данном случае можно написать вспомогательный метод вида

updateRecord($id, [
'name' => ...,
'birthday' => ...
]);

Который сгенерирует запрос в зависимости от аргументов. А вообще, для случаев, когда запрос строится в зависимости от условий, есть паттерн Query Builder, хотя на мой взгляд он тут не нужен.

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

В твоем случае есть такой контроллер: https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php (кстати редактирование и регистрацию надо бы объединить в один метод). Там есть код

> $registerStudentForm = new RegisterStudentForm();


> $registerStudentForm->setStudent($student);


....

> $registerStudentForm->fillDataFromArray($_POST);


> $errors = $this->validations->validRegisterStudentForm($registerStudentForm);


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

"режимы" вполне нормальная вещь - например, может быть такое, что пользователь может редактировать один набор полей, а модератор - другой. Не делать же 2 формы для такого, проще сделать 2 режима для одной формы или валидатора.

Плюс, ниже, где стоит

> $registerStudentForm->setStudentPassword();



Надо добавить проверку

Если (форма->парольУказан) {
форма->поменятьПароль;
авторизатор->обновитьАвтоизацию;
}

И как я сказал выше, объединить функции редактирования и регистрации в одну. А то копипаста получается.

> Хм, значит сущности нужны только если у них есть какие-то особенные методы или много свойств?


Тут важно обходиться без фанатизма. В теории, мы можем сделать каждую строку отдельной сущностью:

$name = new Name('Иванов');
$year = new Year(1980);

Но какой в этом смысл? Это просто усложнение кода.

Что касается сущности Search, то ее можно оставить. Если в будущем будут появляться дополнительные критерии поиска, то в нее удобно будет их добавлять в виде новых полей и сущность будет представлять собой информацию о поисковом запросе.

Но вот нужно ли там поле result- я не уверен. Вот смотри, из 2 вариантов кода:

$query = new Search(....);
.....

$searchEngine->find($query);

и такого:

$results = $searchEngine->find($query);

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

В общем, я думаю, это можно оставить как есть.

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



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

А так да, почему, нет? В простом приложении можно писать код контрллера прямо в register.php:

require __DIR__....bootstrap.php

$students = $mapper->getStudents(...);
$view->render('students.phtml');

Но например при таком подходе нельзя разбить контроллер на несколько методов, нельзя использовать наследование и тд.

В более сложных приложениях конечно ты будешь использовать роутер и классы-контроллеры.

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


Браузер сам кодирует и ГЕТ и ПОСТ формы, а PHP их прозрачно для тебя раскодирует и кладет в $_GET/$_POST. Не надо ничего делать для этого.

И да, ты прав, браузер может отображать УРЛ в искаженном виде. Чтобы увидеть полный УРЛ, скопируй его и вставь в текстовый редактор.
#624 #770003
>>768546

> Тогда для метода валидатора нужно будет добавить аргумент с id.


> А как будущие разработчики поймут зачем здесь этот аргумент? Даже если бы он был не обязательным, я бы не сразу понял зачем методу проверки имейла нужно что-то кроме имейла


назови его "пропуститьПользователяСИд" и напиши комментарий перед функцией.

> А что за параметр? Который сообщает игнорировать те или иные поля? Так придётся переделывать весь класс валидации, не проще ли помножить сущность и сделать новый?


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

> Да и дело даже не в самом в валидаторе, а в запросе БД, т.к. он составлен так, что нам всегда нужно будет отправлять все данные из формы\сущности


Значит надо его исправить.

> а хотелось бы что если в форме какое-то поле было пустым, то и запрос в БД составлялся без этого поля.


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

> Как составляются такие запросы? Неужели нужно писать отдельный метод который на основе сущности будет составлять запрос?


Вообще, в данном случае можно написать вспомогательный метод вида

updateRecord($id, [
'name' => ...,
'birthday' => ...
]);

Который сгенерирует запрос в зависимости от аргументов. А вообще, для случаев, когда запрос строится в зависимости от условий, есть паттерн Query Builder, хотя на мой взгляд он тут не нужен.

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

В твоем случае есть такой контроллер: https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php (кстати редактирование и регистрацию надо бы объединить в один метод). Там есть код

> $registerStudentForm = new RegisterStudentForm();


> $registerStudentForm->setStudent($student);


....

> $registerStudentForm->fillDataFromArray($_POST);


> $errors = $this->validations->validRegisterStudentForm($registerStudentForm);


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

"режимы" вполне нормальная вещь - например, может быть такое, что пользователь может редактировать один набор полей, а модератор - другой. Не делать же 2 формы для такого, проще сделать 2 режима для одной формы или валидатора.

Плюс, ниже, где стоит

> $registerStudentForm->setStudentPassword();



Надо добавить проверку

Если (форма->парольУказан) {
форма->поменятьПароль;
авторизатор->обновитьАвтоизацию;
}

И как я сказал выше, объединить функции редактирования и регистрации в одну. А то копипаста получается.

> Хм, значит сущности нужны только если у них есть какие-то особенные методы или много свойств?


Тут важно обходиться без фанатизма. В теории, мы можем сделать каждую строку отдельной сущностью:

$name = new Name('Иванов');
$year = new Year(1980);

Но какой в этом смысл? Это просто усложнение кода.

Что касается сущности Search, то ее можно оставить. Если в будущем будут появляться дополнительные критерии поиска, то в нее удобно будет их добавлять в виде новых полей и сущность будет представлять собой информацию о поисковом запросе.

Но вот нужно ли там поле result- я не уверен. Вот смотри, из 2 вариантов кода:

$query = new Search(....);
.....

$searchEngine->find($query);

и такого:

$results = $searchEngine->find($query);

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

В общем, я думаю, это можно оставить как есть.

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



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

А так да, почему, нет? В простом приложении можно писать код контрллера прямо в register.php:

require __DIR__....bootstrap.php

$students = $mapper->getStudents(...);
$view->render('students.phtml');

Но например при таком подходе нельзя разбить контроллер на несколько методов, нельзя использовать наследование и тд.

В более сложных приложениях конечно ты будешь использовать роутер и классы-контроллеры.

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


Браузер сам кодирует и ГЕТ и ПОСТ формы, а PHP их прозрачно для тебя раскодирует и кладет в $_GET/$_POST. Не надо ничего делать для этого.

И да, ты прав, браузер может отображать УРЛ в искаженном виде. Чтобы увидеть полный УРЛ, скопируй его и вставь в текстовый редактор.
>>773222
#625 #770018
>>768540

> Это готовый плагин так работает,


Это плагин так работает, но для заказчика или пользователя будет выглядеть что это ты криворукий. Значит надо выбрать другой плагин или написать свой. Ну и вообще, например в Хроме есть встроенные средства для кастомизации линейки прокрутки. Ты бы мог использовать в нем их, вообще не вешая яваскриптов. А в других браузрах - вешать.

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


> Это вроде обычное поведение для карты.


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

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

>>У тебя нет ни индикации прогресса, ни обработки ошибок, ни блокировки кнопки отправки.


> Лень было, да и там всего по три поля.


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

Отсутствие индикации это ненормально. Вот ты нажал кнопку и ничего не происходит - как понять, что это значит? Система должна реагировать на действия пользователя иначе создается ощущение что сайт "тормозит", "глючит" и тд.

> Да, это так. Но а как их еще сделаешь?


Поместить текст поверх картинки? Уменьшить картинку? Ты верстальщик, ты и думай как. Мне кажется, эта картинка там не очень и важна, ее можно уменьшить.

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


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

> Я намерено использовал самый крутой и моднейший способ вставки без оглядки на совместимость.


Ты сайт верстаешь для пользователей или для себя одного? Такое допустимо только когда есть контролируемая среда - например, встроенный в приложение браузер известной версии или корпоративное правило запрещающее использовать что-то кроме ИЕ9.

У неправильное мышление, на мой взгляд. HTML и CSS создавались чтобы обеспечить отображение документа на как можно большем числе устройств. Ты поступаешь ровно наоборот. В верстке ты можешь использовать модные возможности, но не забудь тогда сделать фоллбек для старых браузеров.

> Зачем так? Показать на собеседовании какой я крутой.


Ты же понимаешь. что "крутым" это посчитает только тот, кто плохо понимает принципы HTML. Я например помню как в этом разделе кто-то жаловался, что в Яндексе от него требовали верстать пример под максимальное число браузеров и спрашивали про особенности старой Оперы.

Искусство именно в том, чтобы делать "крутые" вещи не жертвуя другими принципами. SVG на страницу поставить любой может. А сделать чтобы это в итоге везде работало без багов и код не выглядел как лапша - не любой.

> >ЧТо за класс "p"?


> Тоже самое что и тег р, paragraph, наиболее общие правила для абзацов.


Тогда по моему проще использовать тег p в селекторе, возможно в сочетании с родительским классом.

> Это сворованный скрипт, не читал его, только скорость подобрал.


Воровал бы хорошие скрипты хотя бы, а лучше -писал бы свои. Я когда был начинающим, старался по хардкору все на чистом JS писать. С поддержкой ИЕ разумеется.

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


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

> Ну и поглядывая на вакансии я все чаще вижу что пишут что-то типа 'мучать ие 8- не будем'.


Это можно прочесть как "в ИЕ9 все должно работать"

Вообще, что касается древних ИЕ, у меня когда-то была такая мысль - чтобы не мучаться, просто отдавать им голый ХТМЛ без КСС и ЖС. Прочесть тексты можно (если верстка семантичная), картинки посмотреть можно, а остальное это уже проблемы юзеров этого антиквариата.

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

Еще, я помню, я когда-то заморачивался с написанием генератора CSS для кнопок, там идея была такая: для новых браузеров делаем кнопки через CSS3, для старья - генерируем на основе CSS3 картинку с тенями, скруглениями и тд. Это может и перебор, но если постоянно занимаешься версткой - почему бы и не автоматизировать свой труд.
#625 #770018
>>768540

> Это готовый плагин так работает,


Это плагин так работает, но для заказчика или пользователя будет выглядеть что это ты криворукий. Значит надо выбрать другой плагин или написать свой. Ну и вообще, например в Хроме есть встроенные средства для кастомизации линейки прокрутки. Ты бы мог использовать в нем их, вообще не вешая яваскриптов. А в других браузрах - вешать.

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


> Это вроде обычное поведение для карты.


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

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

>>У тебя нет ни индикации прогресса, ни обработки ошибок, ни блокировки кнопки отправки.


> Лень было, да и там всего по три поля.


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

Отсутствие индикации это ненормально. Вот ты нажал кнопку и ничего не происходит - как понять, что это значит? Система должна реагировать на действия пользователя иначе создается ощущение что сайт "тормозит", "глючит" и тд.

> Да, это так. Но а как их еще сделаешь?


Поместить текст поверх картинки? Уменьшить картинку? Ты верстальщик, ты и думай как. Мне кажется, эта картинка там не очень и важна, ее можно уменьшить.

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


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

> Я намерено использовал самый крутой и моднейший способ вставки без оглядки на совместимость.


Ты сайт верстаешь для пользователей или для себя одного? Такое допустимо только когда есть контролируемая среда - например, встроенный в приложение браузер известной версии или корпоративное правило запрещающее использовать что-то кроме ИЕ9.

У неправильное мышление, на мой взгляд. HTML и CSS создавались чтобы обеспечить отображение документа на как можно большем числе устройств. Ты поступаешь ровно наоборот. В верстке ты можешь использовать модные возможности, но не забудь тогда сделать фоллбек для старых браузеров.

> Зачем так? Показать на собеседовании какой я крутой.


Ты же понимаешь. что "крутым" это посчитает только тот, кто плохо понимает принципы HTML. Я например помню как в этом разделе кто-то жаловался, что в Яндексе от него требовали верстать пример под максимальное число браузеров и спрашивали про особенности старой Оперы.

Искусство именно в том, чтобы делать "крутые" вещи не жертвуя другими принципами. SVG на страницу поставить любой может. А сделать чтобы это в итоге везде работало без багов и код не выглядел как лапша - не любой.

> >ЧТо за класс "p"?


> Тоже самое что и тег р, paragraph, наиболее общие правила для абзацов.


Тогда по моему проще использовать тег p в селекторе, возможно в сочетании с родительским классом.

> Это сворованный скрипт, не читал его, только скорость подобрал.


Воровал бы хорошие скрипты хотя бы, а лучше -писал бы свои. Я когда был начинающим, старался по хардкору все на чистом JS писать. С поддержкой ИЕ разумеется.

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


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

> Ну и поглядывая на вакансии я все чаще вижу что пишут что-то типа 'мучать ие 8- не будем'.


Это можно прочесть как "в ИЕ9 все должно работать"

Вообще, что касается древних ИЕ, у меня когда-то была такая мысль - чтобы не мучаться, просто отдавать им голый ХТМЛ без КСС и ЖС. Прочесть тексты можно (если верстка семантичная), картинки посмотреть можно, а остальное это уже проблемы юзеров этого антиквариата.

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

Еще, я помню, я когда-то заморачивался с написанием генератора CSS для кнопок, там идея была такая: для новых браузеров делаем кнопки через CSS3, для старья - генерируем на основе CSS3 картинку с тенями, скруглениями и тд. Это может и перебор, но если постоянно занимаешься версткой - почему бы и не автоматизировать свой труд.
#626 #770021
>>768540

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

Я пока варианта лучше чем "генерировать пнг из свг" не нашел для себя.
#627 #770031
>>768540

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

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

В случае же с маргином, не знаю, будет ли задействовано аппаратное ускорение.
#628 #770037
>>768540

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

Это конечно сложно, вот тут я пробовал например экспериментировать с разными способами вставки картинок: http://codedokode.github.io/files/2/

Если тебе все это интересно, я тебе тоже советую разобраться с особенностями SVG, версиями, поддержкой, способами вставки и тд. А просто вставить картинку, скопировав код, любой может.
#629 #770094
>>767728

> Я не очень понимаю как в таком случае переводить эти строки через gettext. Сейчас у меня вот эта строка


>>_("{0, plural, =0{No downloads} one{# download} other{# downloads}}")


> Получается через gettext и при разных языках она будет разная. А если делать такой объект, то функция форматирования будет выглядеть как-то так


gettext нужен только для получения перевода строки. В нем нет нормальной возможности склонять или менять слова.

Тут есть 2 варианта - либо ты вызываешь gettext вручную:

$tr->format(_('text', $args);

Либо это делает format()

$tr->format('text', $args);

От этого будет зависеть алгоритм работы сборщика строк для перевода, как их искать в коде.

я кстати еще вспомнил интересную штуку: фраза может меняться в зависимости от пола пользователя:

Ты получил подарок от Ивана
Ты получила подарок от Ивана

Вроде TextFormatter такое позволяет. Я кстати когда-то придумывал свой синтаксис и свой форматтер, то ли тогда не было Intl то ли я о нем не знал.

> Единственный вариант который могу придумать это такой:


>>{{ tr.format('{0, plural, =0{No downloads} one{# download} other{# downloads}}', { number: 2}) }}


> Он подойдет?


Подойдет.

>>767669

> Мне в начале каждого адреса такую шнагу прописывать __DIR__.'/../ ?


Либо прописывать, либо сделать функцию например так:

$helper->getAbsolutePath('/config.json');
PathHelper::getAbsolutePath('/confog.json');

>>767581

Сомневаюсь что это хорошая идея. Никто на них не пишет. Либо Qt либо встроенный в приложение браузер (Electron) + HTML.

>>767522

Все для одного и того же - веб приложений.

>>767366

> $maxlength = mb_strlen($lines[0]);


Сложновато. Тут лучше использовать функции max и array_map например. Или array_reduce, если ты смел (она эффективнее из-за отсутствия промежуточного массива)

> $lines[$column] = mb_substr($lines[$column], 1);


Постоянно разрезать строки не очень эффективно и не очень читабельно. Лучше брать N-ю функцию, не меняя исходную строку.
#629 #770094
>>767728

> Я не очень понимаю как в таком случае переводить эти строки через gettext. Сейчас у меня вот эта строка


>>_("{0, plural, =0{No downloads} one{# download} other{# downloads}}")


> Получается через gettext и при разных языках она будет разная. А если делать такой объект, то функция форматирования будет выглядеть как-то так


gettext нужен только для получения перевода строки. В нем нет нормальной возможности склонять или менять слова.

Тут есть 2 варианта - либо ты вызываешь gettext вручную:

$tr->format(_('text', $args);

Либо это делает format()

$tr->format('text', $args);

От этого будет зависеть алгоритм работы сборщика строк для перевода, как их искать в коде.

я кстати еще вспомнил интересную штуку: фраза может меняться в зависимости от пола пользователя:

Ты получил подарок от Ивана
Ты получила подарок от Ивана

Вроде TextFormatter такое позволяет. Я кстати когда-то придумывал свой синтаксис и свой форматтер, то ли тогда не было Intl то ли я о нем не знал.

> Единственный вариант который могу придумать это такой:


>>{{ tr.format('{0, plural, =0{No downloads} one{# download} other{# downloads}}', { number: 2}) }}


> Он подойдет?


Подойдет.

>>767669

> Мне в начале каждого адреса такую шнагу прописывать __DIR__.'/../ ?


Либо прописывать, либо сделать функцию например так:

$helper->getAbsolutePath('/config.json');
PathHelper::getAbsolutePath('/confog.json');

>>767581

Сомневаюсь что это хорошая идея. Никто на них не пишет. Либо Qt либо встроенный в приложение браузер (Electron) + HTML.

>>767522

Все для одного и того же - веб приложений.

>>767366

> $maxlength = mb_strlen($lines[0]);


Сложновато. Тут лучше использовать функции max и array_map например. Или array_reduce, если ты смел (она эффективнее из-за отсутствия промежуточного массива)

> $lines[$column] = mb_substr($lines[$column], 1);


Постоянно разрезать строки не очень эффективно и не очень читабельно. Лучше брать N-ю функцию, не меняя исходную строку.
>>771843
#630 #770097
>>766531

ставишь обработчик в set_exception_hadnler (либо пишешь try/catch в фронт контроллере). В нем:

- логгируешь ошибку через error_log, тестируешь это
- выдаешь один из HTTP кодов 5xx
- выдаешь HTML страницу с сообщением для пользователя

Дополнительно можно написать обработчик котоый превратит обычные ошибки в исключения, смотри ErrorException в мануале, там есть код.

Это все работает если ошибка произошла до вывода текста. Если вывод уже начат, то ничего не поделать.

Ты можешь определить это например проверяя http://php.net/manual/en/function.headers-sent.php

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

>>766467

С фатальными ошибками ничего не поделать. можно их ловить через shutdown_handler, но по моему оно того не стоит. А в лог они пишутся, пхп это сам делает.
#631 #770098
>>766444

Должен ловить. Перепроверь, все ли верно? ЧТо будет если просто написать внизу throw new ErrorException(...) ?
#632 #770108
Анончики, почитайте, у Яндекса (как всегда) интересный пост про их колоночную СУБД. Она ориентирована на вставку и обработку огромных объемов данных: https://m.habrahabr.ru/company/yandex/blog/303282/

Заметьте, что используется SQL-подобный синтаксис. Знание SQL поможет вам не раз. ОП учит вас просто-таки жемчужинам из мира технологий.
#633 #770125
>>769992

>> $result; // ссылка на департамент или массив департаментов


> Что это за синтаксис такой? На мой взгляд, это обращение к несуществующей пока переменной $result.


Иногда вначале функций обозначаю переменные, стоит ли так делать? Вот так будет лучше $result = null ?

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


> Мне кажется, клонировать компании - это не задача антикризисного комитета, это не требуется для его работы, и этого кода в классе быть не должно.


Если я передаю компанию через конструктор, то затем нужно ее клонировать(внутри комитета?), чтобы применить 3 набора АМ. Если я клонирую компанию вне комитета, то мне нужно передать ее комитету три раза, как это сделать если не через аргумент? Вижу единственный выход, создать 3 комитета, каждый со своим набором АМ (клонирование снаружи и передачи в конструктор). Или есть еще варианты?

> Вот здесь у нас серьезная проблема. Что, если все работники содержат ссылку на один и тот же объект профессии? Тогда этот метод меняет зарплату всех этих работников. Я вижу, у тебя так и сделано.


Я так вижу, лол. Сделал это намеренно. Я понял условия так, что между аналитиками нет разницы. Поэтому зарплату поднял в профессии, которая общая для всех работников, а не у конкретных работников определенной должности. Имелось ввиду поднятие ставки у одного работника?

Остальное понятно, спасибо )
>>770133
#634 #770133
>>770125

"Это по идее должна быть ошибка. У тебя наверно не включен вывод ошибок и ты ее не видишь." - хотел я написать, но решил проверить, запустив код в командной строке:

$ php -r 'error_reporting(-1); $result;'
(ничего)

Действительно, ошибки нет. Но я первый раз вижу такую конструкцию. Что она значит? У тебя есть ссылка на мануал с объяснением?

Кстати, если добавить любую операцию, то ошибка будет:

$ php -r '$result + 1;'
PHP Notice: Undefined variable: result in Command line code on line 1

Не, если ты хочешь "обозначить" переменную, лучше присвоить ей какой-то значение. А такую конструкцию я вижу в первый раз.

> Вижу единственный выход, создать 3 комитета, каждый со своим набором АМ (клонирование снаружи и передачи в конструктор). Или есть еще варианты?


Да, либо 3 комитета, либо передавать через аргументы .

Такой подход, когда одна функция задает аругмент, другая делает какое-то действие, он в общем плох, так как всегда есть шансы:

- забыть задать аргумент
- не догадаться что нужно задать аргумент сначала
- забыть задать аргумент при обработке другой компании и получить результаты от старой компании

Я не вижу никаких преимуществ у твоего способа перед простой передачей компании в функцию явно:

$comittee->doSomething($company);

> Я понял условия так, что между аналитиками нет разницы. Поэтому зарплату поднял в профессии, которая общая для всех работников, а не у конкретных работников определенной должности. Имелось ввиду поднятие ставки у одного работника?


А, точно, поднять всем. Но тогда логичнее сделать по-другому: не в цикле увеличивать кждому зарплату, а взять объект профессии и увеличить на нем.
#634 #770133
>>770125

"Это по идее должна быть ошибка. У тебя наверно не включен вывод ошибок и ты ее не видишь." - хотел я написать, но решил проверить, запустив код в командной строке:

$ php -r 'error_reporting(-1); $result;'
(ничего)

Действительно, ошибки нет. Но я первый раз вижу такую конструкцию. Что она значит? У тебя есть ссылка на мануал с объяснением?

Кстати, если добавить любую операцию, то ошибка будет:

$ php -r '$result + 1;'
PHP Notice: Undefined variable: result in Command line code on line 1

Не, если ты хочешь "обозначить" переменную, лучше присвоить ей какой-то значение. А такую конструкцию я вижу в первый раз.

> Вижу единственный выход, создать 3 комитета, каждый со своим набором АМ (клонирование снаружи и передачи в конструктор). Или есть еще варианты?


Да, либо 3 комитета, либо передавать через аргументы .

Такой подход, когда одна функция задает аругмент, другая делает какое-то действие, он в общем плох, так как всегда есть шансы:

- забыть задать аргумент
- не догадаться что нужно задать аргумент сначала
- забыть задать аргумент при обработке другой компании и получить результаты от старой компании

Я не вижу никаких преимуществ у твоего способа перед простой передачей компании в функцию явно:

$comittee->doSomething($company);

> Я понял условия так, что между аналитиками нет разницы. Поэтому зарплату поднял в профессии, которая общая для всех работников, а не у конкретных работников определенной должности. Имелось ввиду поднятие ставки у одного работника?


А, точно, поднять всем. Но тогда логичнее сделать по-другому: не в цикле увеличивать кждому зарплату, а взять объект профессии и увеличить на нем.
#635 #770333
Обосрался на собеседовании. Не смог пояснить разницу между soap и rest. :(
>>770339
#636 #770339
>>770333
Посмотрел я этот SOAP, выглядит как говно мамонта. Алсо, что по SOAP, что по REST есть циклы статей на tutorialspoint.
Что ещё спрашивали?
>>771148
#637 #770360
Пипец. Скачал PHPStorm - грузится по полчаса, виснит. Скачал Sublime - выделяю текст, жду полсекунды реакции на экране. У кого нибудь такое было? Sublime же легчайший
>>770371
#638 #770371
>>770360
Шторм летает у меня.
64 винда, i7, amd radeon, ssd

Пользуясь случаем, спрошу. Кто обновлялся на Шторме? Не слетит ли сервер для авторизации?
>>770404
5 Кб, 439x202
#639 #770396

> $db=new DataBase($config['db']);


> Это раскидано в нескольких местах кода. Вообще-то идея была, чтобы в bootstrap создать нужные объекты один раз. Ты создаешь несколько соединений с базой данных например, несколько StudentDataGateway. Это не очень логично.



Идея нравится. Но вот не пойму, если я пропишу $db=new DataBase($config['db']); в bootstrap.php, как мне к ней обращаться в FrontController и в других классах?
>>770969
#640 #770404
>>770371
У меня не слетает.
>>770421
1336 Кб, 500x508
#641 #770421
>>771481
#642 #770821
>>769992

>> // Если сотрудник соответствует профессии


>> if ($employee->getProfession()->getName() == $profession) {


>Если у тебя профессия - это объект, может логично передавать для поиска не название, а этот объект?



Для того, чтобы передать объект как аргумент в функцию поиска, нужно создать этот объект? Я попробовал передать имя класса, которому принадлежит объект и получил ошибку "Argument 1 passed to Departament::findEmployees() must be an instance of Profession, string given". Получается, каждый раз когда используется функция, нужно будет создать объект определенного класса и передать его в качестве аргумента?
>>770828>>770954
#643 #770828
>>770821

Залез в мануал, действительно каждый раз создается объект класса foo(new Bar);
#644 #770914
>>753595 (OP)
ОП, а объясни условие в задаче про Антикризисные меры:

> В тех департаментах, где руководитель не является аналитиком,


> заменить его на аналитика самого высшего ранга из этого департамента


> (а бывшего руководителя вернуть к обычной работе)



А что делать в департаментах, где вообще нет аналитиков (по условию аналитики только в Департаменте продаж)? Нужно ли возвращать шефа к обычной работе? Или вообще ничего не делать с этими департаментами?
>>770954
#645 #770954
>>770914

Если более хорошего кандидаты в шефы нет, оставить старого.

>>770821

Вообще, по идее у тебя должен быть ровно 1 объект для каждой профессии и передавать надо именно тот же экземпляр. Другой экземпляр, пусть даже с таким же названием - это именно другой объект и не годится.

То есть у объекта есть "идентичность". Мы можем с помощью === сравнить, являются ли объекты одним и тем же. == сравнивает класс и поля объектов на равенство, а вот === проверяет именно идентичность. Благодаря этому нам не нужны какие-то дополнительные идентификаторы, чтобы понять тот же это объект или нет, объект это сам по себе уникальный идентификатор.

И в ООП у нас не должно несколько копий объекта-профессии без веской причины.

Правда, это все усложняет - надо как-то хранить эти объекты. Если это сложно, можно сделать константы для обозначения классов профессиий и проверять их. В качестве констант удобно использоваь имя класса. В PHP запись SomeClass::class возвращает строку с именем класса. То есть будет Manager::class и тд.

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


Ну так ты указал что нужен объект, а передаешь строку.
#646 #770969
>>770396

Тут есть разные варианты. Самый простой - забить на эту проблему и сказать что в контроллере можно создавать оьъекты, но это имеет недостатки. Например каждый новый объект PDO создает соединение с БД.

Второй вариант - сделать какое-то хранилище (контейнер) для объектов. Самый просто вариант - массив:

$services['pdo] = new PDO...

или объект:

$container->add('pdo', new PDO...);

А затем передать контейнер в контроллер через конструктор.

Третий вариант - передавать сервисы в конструктор контроллера по отдельности.

Урок по теме: https://github.com/codedokode/pasta/blob/master/arch/di.md

Я советую не делать слишком сложных решений. Для простой задачи наверно и массив сойдет.
879 Кб, 2560x1920
#647 #771037
>>766363
ОП, а как же RBAC...
>>771128
#648 #771128
>>766363
>>771037

Почитай оф. документацию, посмотри как это подходит к твоей задаче, если плохо то можно сделать что-то свое, какой-нибудь класс для проверки прав доступа.
#649 #771131
>>766363

Личный кабинет это обычный раздел, просто защищенный от доступа без логина.
#650 #771145
ОП, можешь проверять: https://github.com/TheSidSpears/Students
К тому моменту я многое успею исправить
#651 #771147
А кто-нибудь пытался подрабатывать на форумах, школьникам задачки делать? Есть маза быстро вкатиться или конкуренции не выдержу? А то мне 1-2к в месяц не помешают
#652 #771148
>>770339
Остальное как обычно - мвс, ооп, кем вы себя видите через 5 лет и тд.
>>774668
#653 #771481
>>770421
вроде и красивая девушка слева, а что-то в ней есть странное, тоьлко мне кажется? Какая-то она... не сформулирую.

Хрен с ним.
Я не оч пойму как генерировать схему таблицы для ОРМ.
>>771490>>772877
18 Кб, 604x340
#654 #771490
>>771481
Ну как вот эта
<-----
Неживое что-то есть.
#655 #771843
>>770094

> Yii, Symphony, Doctrine, Slim, Лар(в)ав(р)ель, апи вордпресса, не дохуища ли? Это все взаимозаменяемые фреймворки об одном и том же или они для разных задач?


> Все для одного и того же - веб приложений.


Я имел ввиду, их функционал пересекаются, дублируется или они для разного и их реально все-все надо знать? Я почти ничего не знаю о фреймворках кроме рельс для руби или кроме джанги для питона. Все остальные - либо хипстерские откровенно, либо узкоспециализированные. А для пхп нужно все-все это знать? Почему так?
>>772877
#656 #772493

>Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования


Читаю в маршрутке перед работой. Что еще посоветуете полезного?
>>772594>>772877
#657 #772594
>>772493
Ложиться спать пораньше и плотно завтракать.
>>772721
37 Кб, 447x335
#658 #772721
327 Кб, 639x359
#659 #772750

>Для установки MySQL на Debian войдите в систему под учетной записью root и наберите команду:


>apt-get install mysql-server


Почему это не работает? Помогите начинающему линуксоиду.
Не работает и с sudo.
Пишет:

>bash: sudo команда не найдена


Что делать, как дальше жить?
Debian 8 на VirtualBox.
#660 #772760
>>772750
sudo - команда которая позволяет запускать программы с правами другого пользователя, обычно это суперпользователь (root). Если ты уже залогинился под рутом писать sudo не нужно. Не копируй бездумно команды из интернета, старайся сам гуглить и понимать что они значат перед выполнением.

>>apt-get install mysql-server


>Почему это не работает?


Должно работать, какую именно ошибку пишет?
Т.к. у тебя все стоит на виртуалбоксе - поиграю в вангу и предположу что ты неправильно настроил сеть и у машины нет доступа в интернет.
>>773098
#661 #772812
Нормально из контроллера, например, главной страницы вызывать метод FrontController'а?

Получается FC вызывает MC, а в MC я вызываю $auth=FC->checkAuth(), на основании значения которой представление будет решать, что показать
>>772817>>772877
#662 #772817
>>772812
Хотя для этого нужно создавать новый экземпляр FC в MC, что плохо.
Такая дилема, некоторым контроллерам нужно получать значение переменной $auth из FrontController'a, а некоторым не нужно. Как это можно реализовать?
>>772853
#663 #772852
>>772750
ну сделай для начала apt-get install sudo из-под рута

Если ты сидишь под пользователем root, sudo ты можешь не писать
>>773098
#664 #772853
>>772817
а ты во фронт-котроллере не можешь почекать свой checkUath и уже вызывать тот контроллер, которые тебе нуджен?
>>772901
#665 #772877
>>771481

Зависит от того, какой у тебя ORM. Иногда они могут генерировать SQL код сами, иногда надо его самому писать, второй вариант почти всегда предпочтительнее, так как то, что по умолчанию генерируется, подходит только для простых случаев.

>>771843

Вообще, это не совсем одинаковые вещи. Доктрина например это ORM, а не фреймворк. Ты бы мог погуглить и хотя бы в википедии или на хабре про них прочитать.

Различаются они масштабом - Слим очень маленький и годится для простых приложений, Симфони для больших и сложных.

Что надо знать - смотри описание вакансий.

>>772493

"Совершенный код" например.

>>772750

Надо sudo сначала установить

Также, не копируй команды, найди где-нибудь и изучи синтаксис команд apt-cache и apt-get, научись устанавливать любые пакеты.

>>772812

Вообще, нет. Для авторизации логичнее сделать отдельный класс-сервис, а не пихать все в фронт контроллер. В соответствии с приницпом единой обязанности каждый класс должен заниматься своим делом.
#665 #772877
>>771481

Зависит от того, какой у тебя ORM. Иногда они могут генерировать SQL код сами, иногда надо его самому писать, второй вариант почти всегда предпочтительнее, так как то, что по умолчанию генерируется, подходит только для простых случаев.

>>771843

Вообще, это не совсем одинаковые вещи. Доктрина например это ORM, а не фреймворк. Ты бы мог погуглить и хотя бы в википедии или на хабре про них прочитать.

Различаются они масштабом - Слим очень маленький и годится для простых приложений, Симфони для больших и сложных.

Что надо знать - смотри описание вакансий.

>>772493

"Совершенный код" например.

>>772750

Надо sudo сначала установить

Также, не копируй команды, найди где-нибудь и изучи синтаксис команд apt-cache и apt-get, научись устанавливать любые пакеты.

>>772812

Вообще, нет. Для авторизации логичнее сделать отдельный класс-сервис, а не пихать все в фронт контроллер. В соответствии с приницпом единой обязанности каждый класс должен заниматься своим делом.
>>772926>>773098
#666 #772901
>>772853
запихнул checkAuth в abstract class Controller, который наследуется остальными контроллерами
>>772954
#667 #772926
>>772877

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


Нафиг она тогда нужна-то? Ну я понимаю, сложные мени-ту-мени отношения можно и переписать, но если у тебя в базе данных пицот таблиц, каждую описывать вручную можно же умом поехать, мне казалось ОРМ и должна освобождать от рутинного sql дрочения
>>772954
#668 #772954
>>772901

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

>>772926

Индексы например, как ставить? Добавлять всякие ограничения. Использовать text вместо varchar, и тд. Комментарии к полям добавлять. Все это ORM не сделает.

И почему ты так недоволен? Ты плохо знаешь SQL и тебе тяжело написать CREATE TABLE? Тогда стоит лучше его изучить, ORM это помощник в работе с базой данных, но он не отменяет необходимость знать SQL.
>>772970
#669 #772970
>>772954
Я, конечно, может чего не понимаю, но, тупо из википедии берём цитату:

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


[далее код доктрины]

Я могу описать некую таблицу, без вопросов, но неужели суть ОРМ не в том, чтобы избавить меня хотя бы от написания банального КРУДа?
>>773544
#670 #773031
Господа, как мне поставить модуль на пхп, запущенный как cgi?
>>773036>>773544
#671 #773036
>>773031
Тоесть я этот пхп скомпилировал, и как мне теперь добавлять в него модули?
>>773068
#672 #773065
ОПчик, а поясни по хардкору, верен ли подход и овтеть плз на пару вопросов:
сначала пример кода (он не рабочий, прост пример)

Есть класс для работы с таблицей
class News {
public $date;
public $news;

public function __construct($date, $news) {
$this->date = $date;
$this->news = $news;
}

//новая новость
public function save() {
// some mysqli shit
$query = "INSERT INTO news (date, news) VALUES (?,?)";
$sth = $dbh->prepare($query);
$sth->bind_param("is", $this->date, $this->news);
$sth->execute;
}

Вопрос
Как передовать хендлер базы данных в метод? В каждлом методе делать новый хендлер, по-новой соедниясь с БД?
>>773553
#673 #773068
>>773036
В пхп ини прописал extension=mcrypt.so, заработало
67 Кб, 802x480
#674 #773098
>>772760
Нет, доступ в Интернет есть, браузер был открыт, там как раз мануал по установке LAMP.
Просто я не как суперюзер вошёл и sudo не установил.
Вот сейчас пытаюсь установить, получаю прямо по лбу вот этим
<-----
Какой диск, какая Джесси, куда вставить - сие не понять.

>>772852
Вроде сидел под root, пока в этом просто ещё не разобрался.
А sudo пытаюсь вот только установить.

>>772877

>найди где-нибудь и изучи синтаксис команд apt-cache и apt-get, научись устанавливать любые пакеты.


Придётся, конечно.
Я просто думал, что это будет работать всё. Я когда Дебиан на ВиртуалБокс стааааавил...
#675 #773105
>>773098
тяжело тебе будет без знаения хотя бы основ unix-like систем

вот ты говоришь ты под рутом сидел. А зачем тогда sudo вызывал? Судо в данном нужно только для того, чтобы запустить команду от имени рута. Потому что пакет, в данном случае = сервер бд, может установить только рут.
>>773112
#676 #773112
>>773105

>тяжело тебе будет без знаения хотя бы основ unix-like систем


Надеюсь, что не тяжелее, чем без знания основ программирования полгода назад...
Спасибо, немного прояснело.
А с установкой вот что: надо было в ВиртуалБоксе просто снова направить на дистрибутив Дебиан путь в "Носителях".
Я думал, что не нужно это повторять, если один раз уже прописал путь, но вот так.
Дальше пытаюсь.
Отпишусь по результатам, постараюсь держать в курсе!
>>773121
#677 #773121
>>773112
чо? каких носителях?
отредактируй /etc/apt/sources.list и удали
оттуда всё к ебеням, оставь только

deb http://mirror.mephi.ru/debian/ jessie main
deb-src http://mirror.mephi.ru/debian/ jessie main

deb http://security.debian.org/ jessie/updates main
deb-src http://security.debian.org/ jessie/updates main

# jessie-updates, previously known as 'volatile'
deb http://mirror.mephi.ru/debian/ jessie-updates main
deb-src http://mirror.mephi.ru/debian/ jessie-updates main
#678 #773139
>>773098

>Какой диск, какая Джесси, куда вставить - сие не понять.


Это происходит потому что в списке репозиториев у тебя находится установочный диск, и так как он не смонтирован то установщик пакетов тебя просит его смонтировать. Вообще установщик дебиана, насколько я помню после установки советует убрать образ из списка репозиториев, может ты просто это пропустил. Как его убрать, тебе уже написали тут >>773121
>>774671
#679 #773222
https://github.com/someApprentice/Students/

>>770003

>редактирование и регистрацию надо бы объединить в один метод


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

Старая копипаста
https://github.com/someApprentice/Students/blob/1b6864801a038c4619701ccb96c43144ea91c5b3/app/Controller/RegisterAction.php

Новая копипаста
https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php#L33
https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php#L43
https://github.com/someApprentice/Students/blob/master/app/Controller/RegisterAction.php#L50

К тому же, из-за того что я сократил проверку токена, если не будет параметра $_GET['token'] в адресной строке, то залогиненый пользователь увидит форму регистрации. Логично что для такого случая нужно делать проверку и вбрасывать исключения или делать ридерект, но это приведет к еще большей копипасте.

Вконтакте, Фейсбуке и Твиттере почти для каждого поля своя форма редактирования. У них, наверно, для этого отдельный от регистрации контроллер и отдельный валидатор?
>>773648
#680 #773236
Ставлю prestashop, требует включенной опции allow_url_fopen.
Естественно не только проверил, включена ли она (включена по-умолчанию), но и хочу разобраться, за что собственно отвечает.

>Данная директива включает поддержку оберток URL (URL wrappers), которые позволяют работать с объектами URL как с обычными файлами. Обертки, доступные по умолчанию, служат для работы с удаленными файлами с использованием ftp или http протокола. Некоторые расширения, например, zlib, могут регистрировать собственные обертки.


Что такое "обертки URL", и как их активация/отключение изменит работу приложения?
Разве php и так не работает с url как с обычными файлами, зачем нужны эти "обертки"?

На форумах суппорта не найдешь, одни мудаки или тролли (поэтому спрашиваю на дваче, да).
Вот чел приводит пример, когда подключается внешний скрипт из гет-переменной(!).
http://phpclub.ru/talk/threads/Опция-allow_url_fopen-вопрос-по-безопасности.51669/#post-444000
Резонный вопрос, а есть ли уязвимость, если не использовать непроверенные данные от пользователя?
Тем более что за инклюды с 5.2 теперь отвечает отдельная настройка allow_url_include

В оф.документации непонятная лабуда, на форумах мудаки. Куда гуглить? Хочу научиться самостоятельно разбираться в подобных вопросах.
Подозреваю, что у меня пробел в понимании, как php работает с файлами и прочими ресурсами, как составить правильный поисковый запрос?
Запрос "как php работает с ресурсами" не выдал удовлетворительных ссылок.
>>773522>>773560
#681 #773247
Удивительно, как люди умудряются генерировать огромное количество бессмысленных постов, вместо того чтобы ответить на простой вопрос (скорее всего ответа не знают, но что-то написать хочется).
https://habrahabr.ru/post/61429/

>А какаие противоречия у них есть? У одного потенциальная дыра открыта, у другого прикрыта. Выбирайте что вам нужнее :)


Безграмотный смайлофаг. Вопрос был, в чем состоит уязвимость.

>может, один эту дыру за дыру не считает? или другой, наоборот, видит дыру там, где её нету?


Агностик.

>Потенциально (!) это однозначно дыра, зависит исключительно от скриптов, которые реализуют некий функционал.


Не приводит пример скрипта, реализующего некий потенциал, и в котором включение настройки становится "дырой".

>Давненько я не встречал платный виртуальный хостинг с отключенным allow_url_fopen.


Напиши еще что-нибудь из своей биографии.

>Не понимаю сути вопроса.


Тупой.

>У вас есть задача и вам нужно ее решить, значит используйте allow_url_fopen.


Мне для этого нужно понять, что делает эта опция, и какие могут быть подводные камни.

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


Сука, напиши как использовать, и опиши как защитить приложение.

>если скрипты безопасны (возмем идеальный вариант) 100%, то это не дыра.


Как сделать "скрипты" (процедурщики?) безопасными?

Поэтому не люблю хабрахабр, это же обычная соцсеть, или в крайнем случае тухлый блог, куда репостят несвежие переводы.
>>773560
#682 #773522
>>773236
http://phpclub.ru/detail/article/2003-09-23

>Для увеличения функциональности и упрощения кодирования, разработчики php сделали такую особенность в функциях fopen, file, include и прочих. >Если имя файла начинается с "http://", сервер выполнит HTTP-запрос, скачает страницу, и запишет в переменную как из обычного файла. Аналогично работают префиксы "ftp://", "php://" (последний предназначен для чтения и записи в stdin, stdout и stderr).

#683 #773544
>>772970

Чтобы создать пользователя, тебе не надо писать рутинный однотипный SQL код. А вот чтобы создать таблицу - надо, так как там часто требуется что-то нестандартное или то, что ORM не сгенерирует.

Использование ORM вообще не значит, что SQL можно не изучать. Он избавляет от рутинных запросов, а не от необходимости знать SQL.

>>773031

во-первых, CGI это несерьезно. Он делался скорее для каких-то любительских вещей. Сейчас используют либо php как модуль Апача, либо php-fpm, взаимодействующий с сервером через FCGI.

Модули php это просто динамические библиотеки. Ты их компилируешь (или устанавливаешь пакетным менеджером, или качаешь готовые) и подключаешь в php.ini. Часть модулей уже встроена в пхп и подключается в php.ini.

конкретные инструкции зависят от модуля и версии ОС, смотри в мануале. Например для модуля gd: http://php.net/manual/ru/image.installation.php

Для расширений pecl: http://php.net/manual/ru/install.pecl.php
>>773785
#684 #773553
>>773065

> Как передовать хендлер базы данных в метод?


Читай урок по DI https://github.com/codedokode/pasta/blob/master/arch/di.md

Если кратко - через конструктор.

>>773098

Странно. Тебе надо проверить конфиг в файле /etc/apt/sources.list (редактировать его можно редактором nano, набрав nano /etc/apt/s.... )

В нем указывается, откуда брать пакеты. У тебя почему-то указан только cdrom (почему? ты наверно при установке что-то не то указал). Надо раскомментировать или добавить туда официальный репозитоий дебиана. Адреса можно взять в генераторе sources.list: https://debgen.simplylinux.ch/

Выбираешь страну, версию ОС, ставишь все 10 галочек, при желании дополнительные галочки в 3rdparties, но это необязательно и всегда можно добавить потом. Получаешь конфги, копипастишь его в sources.list

Обновляешь список командой apt-get update

После этого должно ставить пакеты из интернета.

Также почитай статью https://wiki.debian.org/ru/SourcesList
>>773727>>774671
#685 #773560
>>773121

Лучше не давать готовый список, а ссылку на генератор soures.list и мануалы. А то человек ничему не научится.

>>773236

Эта опция позволяет писать такое

$content = file_get_contents('http://example.com/file.txt');

Во многих местах в пхп функции могут работать не только с файлами на диске, но и с удаленными файлами по сети, и много еще с чем. Мануал:

http://php.net/manual/ru/wrappers.php
http://php.net/manual/ru/book.stream.php

> Разве php и так не работает с url как с обычными файлами, зачем нужны эти "обертки"?


Это отключается/включается в конфиге.

> Резонный вопрос, а есть ли уязвимость, если не использовать непроверенные данные от пользователя?


Есть ли уязвимость зависит от кода. Если в коде делается например fopen() с данными от пользователя то конечно поддержка врапперов расширяет возможности для атаки. Если код написан грамотно и ответственно (что случается редко) то проблем нет.

>>773247

Да, статьи разные по качеству. Но например у Яндекса обычно качественные статьи. А вот по пхп - скажем так, ... разные.
#685 #773560
>>773121

Лучше не давать готовый список, а ссылку на генератор soures.list и мануалы. А то человек ничему не научится.

>>773236

Эта опция позволяет писать такое

$content = file_get_contents('http://example.com/file.txt');

Во многих местах в пхп функции могут работать не только с файлами на диске, но и с удаленными файлами по сети, и много еще с чем. Мануал:

http://php.net/manual/ru/wrappers.php
http://php.net/manual/ru/book.stream.php

> Разве php и так не работает с url как с обычными файлами, зачем нужны эти "обертки"?


Это отключается/включается в конфиге.

> Резонный вопрос, а есть ли уязвимость, если не использовать непроверенные данные от пользователя?


Есть ли уязвимость зависит от кода. Если в коде делается например fopen() с данными от пользователя то конечно поддержка врапперов расширяет возможности для атаки. Если код написан грамотно и ответственно (что случается редко) то проблем нет.

>>773247

Да, статьи разные по качеству. Но например у Яндекса обычно качественные статьи. А вот по пхп - скажем так, ... разные.
>>773736>>773800
https://github.com/someApprentice/Students #686 #773648
>>773222

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


Не вижу тут особой сложности.

> К тому же, из-за того что я сократил проверку токена, если не будет параметра $_GET['token'] в адресной строке, то залогиненый пользователь увидит форму регистрации. Логично что для такого случая нужно делать проверку и вбрасывать исключения или делать ридерект, но это приведет к еще большей копипасте.


Думаю, можно как-то решить эту проблему. Я посмотрел контроллер регистрации и там можно полностью избавиться от копипасты строк кода.

> Вконтакте, Фейсбуке и Твиттере почти для каждого поля своя форма редактирования. У них, наверно, для этого отдельный от регистрации контроллер и отдельный валидатор?


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

-----------

Вместо того, чтобы копипастить условие в if:

> if (Helper::validCSRFtoken($_GET['token']) and $this->loginAction->isLoggedIn()) {


Можно завести булеву переменную $isEdit:

$isEdit = $this->loginAction->isLoggedIn();

И передавать ее куда надо, например:

$errors = $this->validations->validRegisterStudentForm($registerStudentForm, $isEdit);

> if ($registerStudentForm->getPassword() != "") {


> $registerStudentForm->setStudentPassword();


Вообще, это можно было бы делать в классе формы в методе fillDataFromArray

>if (Helper::validCSRFtoken($_GET['token']) and $this->loginAction->isLoggedIn()) {


> $student = $this->studentGateway->getStudentByСolumn('id', $_COOKIE['id']);


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

Насчет XSRF, у тебя при несовпадении токена делается регистрация. Но правильнее вообще не обрабатывать форму. А то злоумышленник может от имени пользователя регистрировать аккаунты.

А, еще, я думал, loginAction это сервис, а это контроллер. Тогда это странный код:

> $this->loginAction->isLoggedIn()


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

Более того, проверяешь авторизацию ты контроллером, а залогинаваешь пользователя в классе со странным названием StudentCookies.

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

- залогинивать пользователя (ставить нужные куки)
- разлогинивать
- проверять залогинен ли пользователь

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

Проверка CSRF сделана неправильно.

https://github.com/someApprentice/Students/blob/master/app/Model/Helper/Helper.php#L15

> if ($token == $_COOKIE['token']) {


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

Далее, нет логики в наследовании хелперов. Вот у тебя есть Helper и есть LoginHelper, который его наследует. Непонятно, а зачем? Там все равно почти все методы статические. Точнее, часть статическая, а часть нет, и почему, непонятно.

Непонятно, зачем нужен этот пустой класс: https://github.com/someApprentice/Students/blob/master/app/Model/Helper/RegistrationHelper.php

Ты вызываешь статически не-статический метод Helper::validCSRFtoken

https://github.com/someApprentice/Students/blob/master/app/init.php#L21

> $config = parse_ini_file('config.ini');


Тут используется относительное имя файла. Это ненадежно, так как правильно ли сработает код, зависит от того, какая директория текущая (прочти-ка про текущую директорию https://ru.wikipedia.org/wiki/Рабочий_каталог )

https://github.com/someApprentice/Students/blob/master/app/Model/Cookies/StudentCookies.php
Тут по моему ты радикально все переусложнил. По моему, установку кук можно было просто сделать 2 строчками setcookie и незачем ради этого было городить интерфейсы. Также, ты указал для кук в качестве домена 'localhost' и получается что на другом домене твое приложение не будет работать (не будет ставить куки).

https://github.com/someApprentice/Students/blob/master/app/Model/Entity/Search.php#L11

> if (is_scalar($query)) {


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

https://github.com/someApprentice/Students/tree/master/app/Model/Entity
Я думаю, формы лучше было бы конечно вынести в отдельную папку.

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

https://github.com/someApprentice/Students/blob/master/app/Model/Gateway/TableDataGateway.php#L15
Непонятно что в базовом классе делается функция adduser. Разве она не в StudentTDG должна быть?

В классах валидации наследование реализовано неправильно. Вот, как я понимаю:

- есть базовый класс валидации с общими методами вроде "провеhить длину", не привязанный ни к студенту, ни к формам
- есть его наследники: класс для валидации стдента, класс для валидации формы регистрации

Но у тебя это нарушается. В базовом классе зачем-то есть константы (которые относятся к модели студента, а не к валидации), базовый класс через конструктор получает StudentGateway, там есть метод isGenderInvalid($gender), который предназначен только для студента, там же есть метод validateLoginStudentForm.

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

И наконец, в некоторых местах, ты обращаешься к массивам вроде $_GET или $_COOKIE, не проверяя перед этим, есть ли в них такой элемент:

Helper::redirect($_GET['go']);

Но ведь он может и отсутствовать. Лучше использовать функцию, вроде $this->getQuery('go'), которая делает нужную проверку. Редирект, кстати, я подумал, логичнее было бы поместить в базовый класс контроллера. Тогда редиректить можно будет только из контроллеров.

Вместо include __DIR__ . '/../../templates/registration.phtml'; лучше было бы сделать метод $this->render('templates/registration.phtml')

В общем, как всегда, я тут написал много замечаний, может даже немного запутанно, так что, если что, задавай уточняющие вопросы.
https://github.com/someApprentice/Students #686 #773648
>>773222

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


Не вижу тут особой сложности.

> К тому же, из-за того что я сократил проверку токена, если не будет параметра $_GET['token'] в адресной строке, то залогиненый пользователь увидит форму регистрации. Логично что для такого случая нужно делать проверку и вбрасывать исключения или делать ридерект, но это приведет к еще большей копипасте.


Думаю, можно как-то решить эту проблему. Я посмотрел контроллер регистрации и там можно полностью избавиться от копипасты строк кода.

> Вконтакте, Фейсбуке и Твиттере почти для каждого поля своя форма редактирования. У них, наверно, для этого отдельный от регистрации контроллер и отдельный валидатор?


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

-----------

Вместо того, чтобы копипастить условие в if:

> if (Helper::validCSRFtoken($_GET['token']) and $this->loginAction->isLoggedIn()) {


Можно завести булеву переменную $isEdit:

$isEdit = $this->loginAction->isLoggedIn();

И передавать ее куда надо, например:

$errors = $this->validations->validRegisterStudentForm($registerStudentForm, $isEdit);

> if ($registerStudentForm->getPassword() != "") {


> $registerStudentForm->setStudentPassword();


Вообще, это можно было бы делать в классе формы в методе fillDataFromArray

>if (Helper::validCSRFtoken($_GET['token']) and $this->loginAction->isLoggedIn()) {


> $student = $this->studentGateway->getStudentByСolumn('id', $_COOKIE['id']);


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

Насчет XSRF, у тебя при несовпадении токена делается регистрация. Но правильнее вообще не обрабатывать форму. А то злоумышленник может от имени пользователя регистрировать аккаунты.

А, еще, я думал, loginAction это сервис, а это контроллер. Тогда это странный код:

> $this->loginAction->isLoggedIn()


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

Более того, проверяешь авторизацию ты контроллером, а залогинаваешь пользователя в классе со странным названием StudentCookies.

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

- залогинивать пользователя (ставить нужные куки)
- разлогинивать
- проверять залогинен ли пользователь

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

Проверка CSRF сделана неправильно.

https://github.com/someApprentice/Students/blob/master/app/Model/Helper/Helper.php#L15

> if ($token == $_COOKIE['token']) {


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

Далее, нет логики в наследовании хелперов. Вот у тебя есть Helper и есть LoginHelper, который его наследует. Непонятно, а зачем? Там все равно почти все методы статические. Точнее, часть статическая, а часть нет, и почему, непонятно.

Непонятно, зачем нужен этот пустой класс: https://github.com/someApprentice/Students/blob/master/app/Model/Helper/RegistrationHelper.php

Ты вызываешь статически не-статический метод Helper::validCSRFtoken

https://github.com/someApprentice/Students/blob/master/app/init.php#L21

> $config = parse_ini_file('config.ini');


Тут используется относительное имя файла. Это ненадежно, так как правильно ли сработает код, зависит от того, какая директория текущая (прочти-ка про текущую директорию https://ru.wikipedia.org/wiki/Рабочий_каталог )

https://github.com/someApprentice/Students/blob/master/app/Model/Cookies/StudentCookies.php
Тут по моему ты радикально все переусложнил. По моему, установку кук можно было просто сделать 2 строчками setcookie и незачем ради этого было городить интерфейсы. Также, ты указал для кук в качестве домена 'localhost' и получается что на другом домене твое приложение не будет работать (не будет ставить куки).

https://github.com/someApprentice/Students/blob/master/app/Model/Entity/Search.php#L11

> if (is_scalar($query)) {


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

https://github.com/someApprentice/Students/tree/master/app/Model/Entity
Я думаю, формы лучше было бы конечно вынести в отдельную папку.

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

https://github.com/someApprentice/Students/blob/master/app/Model/Gateway/TableDataGateway.php#L15
Непонятно что в базовом классе делается функция adduser. Разве она не в StudentTDG должна быть?

В классах валидации наследование реализовано неправильно. Вот, как я понимаю:

- есть базовый класс валидации с общими методами вроде "провеhить длину", не привязанный ни к студенту, ни к формам
- есть его наследники: класс для валидации стдента, класс для валидации формы регистрации

Но у тебя это нарушается. В базовом классе зачем-то есть константы (которые относятся к модели студента, а не к валидации), базовый класс через конструктор получает StudentGateway, там есть метод isGenderInvalid($gender), который предназначен только для студента, там же есть метод validateLoginStudentForm.

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

И наконец, в некоторых местах, ты обращаешься к массивам вроде $_GET или $_COOKIE, не проверяя перед этим, есть ли в них такой элемент:

Helper::redirect($_GET['go']);

Но ведь он может и отсутствовать. Лучше использовать функцию, вроде $this->getQuery('go'), которая делает нужную проверку. Редирект, кстати, я подумал, логичнее было бы поместить в базовый класс контроллера. Тогда редиректить можно будет только из контроллеров.

Вместо include __DIR__ . '/../../templates/registration.phtml'; лучше было бы сделать метод $this->render('templates/registration.phtml')

В общем, как всегда, я тут написал много замечаний, может даже немного запутанно, так что, если что, задавай уточняющие вопросы.
>>774640
https://github.com/applejacky/students #687 #773656
1. Вопрос по поводу HTML5 атрибута pattern.

>а бекслеш пишется один раз (например: \d). Писать ^ и $ для привязки выражения к краям не требуется.


Это все различия с PCRE? Я не нагуглил больше. Для получения регулярок из валидатора в шаблон сделал так:
https://github.com/applejacky/students/blob/master/app/Lib/StudentValidator.php#L87

2. Подсветка найденного реализована вот так:
https://github.com/applejacky/students/blob/master/app/functions.php#L11
В шаблонах вызывается так: https://github.com/applejacky/students/blob/master/app/View/student/index.phtml#L44
Так пойдёт или я схалтурил и нужно писать какой-то сложный парсер массива объектов Student, проверяя свойства объекта (только определённые) на соответствие поиску?

3. Нагуглил ещё Laravel Auth Scaffold. Там роуты, связанные с аутентификацией, выглядят так:
$this->get('login', 'Auth\AuthController@showLoginForm');
$this->post('login', 'Auth\AuthController@login');
$this->get('logout', 'Auth\AuthController@logout');
$this->get('register', 'Auth\AuthController@showRegistrationForm');
$this->post('register', 'Auth\AuthController@register');
И всё-таки я склонился именно к такому варианту и у себя:
https://github.com/applejacky/students/blob/master/app/routes.php
Это только в Laravel так или в некоторых других фреймворках тоже?

4. Насколько хорошо нужно знать Bash джуну?
Здесь вбрасывали ссылку на задание по SF2, там в конце было указано написать скрипт развёртывания проекта на локалхосте. Попытался сделать для студентов такой:
https://github.com/applejacky/students/blob/master/util/deploy_to_localhost.sh
И сложилось впечатление, что Bash это язык вообще не для людей. Хочется верить, что это всё-таки я плохо Bash изучил и на нём можно писать по-человечески. Пока вот что обнаружил:
- Функции могут возвращать только код операции. Всё остальное нужно выплёвать в stdout с помощью echo.
- Все переменные по умолчанию глобальные, поэтому передавая переменную в функцию, я, по сути, передаю туда глобальную переменную, которая и так была бы доступна для функции. Думаю, что для читаемости, всё-таки стоит явно передавать параметры?
- В определении функции не указываются названия параметров. Для того, чтобы разобраться в каше из $1, $2, $3 нужно искать вызов этой функции или костылями присваивать значения параметров новым переменным: https://github.com/applejacky/students/blob/master/util/deploy_to_localhost.sh#L49
- В функции нельзя полностью выйти из сценария, так как функция это сабшелл и выход из неё возвращает в родительский. Нужно делать костыль с убийством процесса для скрипта:
https://github.com/applejacky/students/blob/master/util/deploy_to_localhost.sh#L18
Молчу про исключения и наркоманские диалекты регулярок в sed и grep.

5. Платина: куда это халявно задеплоить? На heroku используется postgresql; разбираюсь с openshift, но там сейчас какие-то глюки с регистрацией.

6. Что должен уметь файлообменник, чтобы его можно было отдавать тебе на ревью? Стоит ли ради древовидных комментариев брать ORM или хватит мапперов и паттернов для работы с древовидными структурами, описанными в твоей пасте?
https://github.com/applejacky/students #687 #773656
1. Вопрос по поводу HTML5 атрибута pattern.

>а бекслеш пишется один раз (например: \d). Писать ^ и $ для привязки выражения к краям не требуется.


Это все различия с PCRE? Я не нагуглил больше. Для получения регулярок из валидатора в шаблон сделал так:
https://github.com/applejacky/students/blob/master/app/Lib/StudentValidator.php#L87

2. Подсветка найденного реализована вот так:
https://github.com/applejacky/students/blob/master/app/functions.php#L11
В шаблонах вызывается так: https://github.com/applejacky/students/blob/master/app/View/student/index.phtml#L44
Так пойдёт или я схалтурил и нужно писать какой-то сложный парсер массива объектов Student, проверяя свойства объекта (только определённые) на соответствие поиску?

3. Нагуглил ещё Laravel Auth Scaffold. Там роуты, связанные с аутентификацией, выглядят так:
$this->get('login', 'Auth\AuthController@showLoginForm');
$this->post('login', 'Auth\AuthController@login');
$this->get('logout', 'Auth\AuthController@logout');
$this->get('register', 'Auth\AuthController@showRegistrationForm');
$this->post('register', 'Auth\AuthController@register');
И всё-таки я склонился именно к такому варианту и у себя:
https://github.com/applejacky/students/blob/master/app/routes.php
Это только в Laravel так или в некоторых других фреймворках тоже?

4. Насколько хорошо нужно знать Bash джуну?
Здесь вбрасывали ссылку на задание по SF2, там в конце было указано написать скрипт развёртывания проекта на локалхосте. Попытался сделать для студентов такой:
https://github.com/applejacky/students/blob/master/util/deploy_to_localhost.sh
И сложилось впечатление, что Bash это язык вообще не для людей. Хочется верить, что это всё-таки я плохо Bash изучил и на нём можно писать по-человечески. Пока вот что обнаружил:
- Функции могут возвращать только код операции. Всё остальное нужно выплёвать в stdout с помощью echo.
- Все переменные по умолчанию глобальные, поэтому передавая переменную в функцию, я, по сути, передаю туда глобальную переменную, которая и так была бы доступна для функции. Думаю, что для читаемости, всё-таки стоит явно передавать параметры?
- В определении функции не указываются названия параметров. Для того, чтобы разобраться в каше из $1, $2, $3 нужно искать вызов этой функции или костылями присваивать значения параметров новым переменным: https://github.com/applejacky/students/blob/master/util/deploy_to_localhost.sh#L49
- В функции нельзя полностью выйти из сценария, так как функция это сабшелл и выход из неё возвращает в родительский. Нужно делать костыль с убийством процесса для скрипта:
https://github.com/applejacky/students/blob/master/util/deploy_to_localhost.sh#L18
Молчу про исключения и наркоманские диалекты регулярок в sed и grep.

5. Платина: куда это халявно задеплоить? На heroku используется postgresql; разбираюсь с openshift, но там сейчас какие-то глюки с регистрацией.

6. Что должен уметь файлообменник, чтобы его можно было отдавать тебе на ревью? Стоит ли ради древовидных комментариев брать ORM или хватит мапперов и паттернов для работы с древовидными структурами, описанными в твоей пасте?
>>773682>>773741
#688 #773682
>>773656

> Это все различия с PCRE? Я не нагуглил больше.


не знаю, есть ли где список различий, но я знаю, где есть описание синтаксиса.

В спецификации (https://www.w3.org/TR/html5/forms.html#the-pattern-attribute) написано:

> the attribute's value must match the JavaScript Pattern production. [ECMA262]



Используются рег. выражения из яваскрипта. Их описание лучше всего конечно прочитать в стандарте ECMA, но в более понятном виде его можно например найти тут:

- https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Regular_Expressions
- https://learn.javascript.ru/regular-expressions-javascript

Также, в стандарте написано:

> This implies that the regular expression language used for this attribute is the same as that used in JavaScript, except that the pattern attribute is matched against the entire value, not just any subset (somewhat as if it implied a ^(?: at the start of the pattern and a )$ at the end).



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

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

> convertPcreRegexToHtml5($pcreRegex)

#688 #773682
>>773656

> Это все различия с PCRE? Я не нагуглил больше.


не знаю, есть ли где список различий, но я знаю, где есть описание синтаксиса.

В спецификации (https://www.w3.org/TR/html5/forms.html#the-pattern-attribute) написано:

> the attribute's value must match the JavaScript Pattern production. [ECMA262]



Используются рег. выражения из яваскрипта. Их описание лучше всего конечно прочитать в стандарте ECMA, но в более понятном виде его можно например найти тут:

- https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Regular_Expressions
- https://learn.javascript.ru/regular-expressions-javascript

Также, в стандарте написано:

> This implies that the regular expression language used for this attribute is the same as that used in JavaScript, except that the pattern attribute is matched against the entire value, not just any subset (somewhat as if it implied a ^(?: at the start of the pattern and a )$ at the end).



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

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

> convertPcreRegexToHtml5($pcreRegex)

#689 #773727
>>773553

>>> Как передовать хендлер базы данных в метод?


Читай урок по DI https://github.com/codedokode/pasta/blob/master/arch/di.md

>>Если кратко - через конструктор.


Бро, а ты можешь привести простой пример?
То есть как я понимаю слежуеь созать класс о статиечскеим методом получения хендлера и вызывать этот метод в других методах?
>>773747
#690 #773736
>>773560
а то он с генератором научится
>>773747
#691 #773741
>>773656

> convertPcreRegexToHtml5($pcreRegex)


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

> Подсветка найденного


такой вариант подходит

> Так пойдёт или я схалтурил и нужно писать какой-то сложный парсер массива объектов Student, проверяя свойства объекта (только определённые) на соответствие поиску?


это переусложнение

> Нагуглил ещё Laravel Auth Scaffold.


Имей в виду что scaffold это процесс генерации файлов с кодом по шаблону.

> Это только в Laravel так или в некоторых других фреймворках тоже?


Это их особенности. Вот как выглядят роуты в Симфони:

http://symfony.com/doc/current/components/routing/introduction.html

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

> 4. Насколько хорошо нужно знать Bash джуну?


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

> там в конце было указано написать скрипт развёртывания проекта на локалхосте. Попытался сделать для студентов такой:


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

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

Плюс, он почему-то работает из-под рута, что опасно, чуть что не так и легко разломать систему.

Вместо проверки наличия гита можно было наверно просто написать apt-get install git mysql compser

Зачем-то прописывает записи в hosts. А на продакшене ты тоже будешь адрес домена на 127.0.0.1 направлять?

> function die {


> kill $$


Ой, как все сложно и запутанно.

> echo "Type dbname: "


> read dbname;


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

Проще сказать пользователю отредактировать конфиг или предоставить файл локального конфига.

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

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

> https://github.com/applejacky/students/blob/master/app/Model/Student.php#L21


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

> Здесь вбрасывали ссылку на задание по SF2, там в конце было указано написать скрипт развёртывания проекта на локалхосте.


Думаю, имелось в виду что-то проще.

> Функции могут возвращать только код операции. Всё остальное нужно выплёвать в stdout с помощью echo.


А они не имеют доступа к каким-нибудь глобальным переменным? Можно через них вернуть. Вообще, баш скрипты - это просто способ записать последовательность команд, что-то сложное там писать не стоит.

> Платина: куда это халявно задеплоить? На heroku используется postgresql; разбираюсь с openshift, но там сейчас какие-то глюки с регистрацией.


Есть c9.io, на нем дают рутовый доступ, но сайт доступен только пока IDE открыта в браузере. Были когда-то free vps на каком-то западном freewebhost или как-то так, попробуй погуглить. Есть бесплатные хостинги, западные даже без рекламы, но там не дают рута, ssh, и менять настройки Апача.

> 6. Что должен уметь файлообменник, чтобы его можно было отдавать тебе на ревью? Стоит ли ради древовидных комментариев брать ORM или хватит мапперов и паттернов для работы с древовидными структурами, описанными в твоей пасте?


Не знаю, что хочешь то и делай, я наверно в любом случае проверю. Чем больше, тем лучше. Насчет ОРМ - сам решай, можно сделать и на мапперах + materialized path. Комментарии хорошо бы сделать с поддержкой аякса и вообще как-то продуманно сделать.
#691 #773741
>>773656

> convertPcreRegexToHtml5($pcreRegex)


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

> Подсветка найденного


такой вариант подходит

> Так пойдёт или я схалтурил и нужно писать какой-то сложный парсер массива объектов Student, проверяя свойства объекта (только определённые) на соответствие поиску?


это переусложнение

> Нагуглил ещё Laravel Auth Scaffold.


Имей в виду что scaffold это процесс генерации файлов с кодом по шаблону.

> Это только в Laravel так или в некоторых других фреймворках тоже?


Это их особенности. Вот как выглядят роуты в Симфони:

http://symfony.com/doc/current/components/routing/introduction.html

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

> 4. Насколько хорошо нужно знать Bash джуну?


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

> там в конце было указано написать скрипт развёртывания проекта на локалхосте. Попытался сделать для студентов такой:


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

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

Плюс, он почему-то работает из-под рута, что опасно, чуть что не так и легко разломать систему.

Вместо проверки наличия гита можно было наверно просто написать apt-get install git mysql compser

Зачем-то прописывает записи в hosts. А на продакшене ты тоже будешь адрес домена на 127.0.0.1 направлять?

> function die {


> kill $$


Ой, как все сложно и запутанно.

> echo "Type dbname: "


> read dbname;


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

Проще сказать пользователю отредактировать конфиг или предоставить файл локального конфига.

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

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

> https://github.com/applejacky/students/blob/master/app/Model/Student.php#L21


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

> Здесь вбрасывали ссылку на задание по SF2, там в конце было указано написать скрипт развёртывания проекта на локалхосте.


Думаю, имелось в виду что-то проще.

> Функции могут возвращать только код операции. Всё остальное нужно выплёвать в stdout с помощью echo.


А они не имеют доступа к каким-нибудь глобальным переменным? Можно через них вернуть. Вообще, баш скрипты - это просто способ записать последовательность команд, что-то сложное там писать не стоит.

> Платина: куда это халявно задеплоить? На heroku используется postgresql; разбираюсь с openshift, но там сейчас какие-то глюки с регистрацией.


Есть c9.io, на нем дают рутовый доступ, но сайт доступен только пока IDE открыта в браузере. Были когда-то free vps на каком-то западном freewebhost или как-то так, попробуй погуглить. Есть бесплатные хостинги, западные даже без рекламы, но там не дают рута, ssh, и менять настройки Апача.

> 6. Что должен уметь файлообменник, чтобы его можно было отдавать тебе на ревью? Стоит ли ради древовидных комментариев брать ORM или хватит мапперов и паттернов для работы с древовидными структурами, описанными в твоей пасте?


Не знаю, что хочешь то и делай, я наверно в любом случае проверю. Чем больше, тем лучше. Насчет ОРМ - сам решай, можно сделать и на мапперах + materialized path. Комментарии хорошо бы сделать с поддержкой аякса и вообще как-то продуманно сделать.
>>774967
#692 #773747
>>773727

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

> То есть как я понимаю слежуеь созать класс о статиечскеим методом получения хендлера и вызывать этот метод в других методах?


То есть ты не прочел урок, потому что там написано что статические методы это плохо.

Если у тебя ActveRecord то он плохо работает c DI. Разве что только так (тогда DI можно использовать с $newsTable):

$news = $newsTable->create();

А если ты пишешь

$news = new News();

То разумеется DI тут нет и придется какими-то плохими методами вроде статических методов получать нужные зависимости.

>>773736

Ну я надеюсь что он прочитает где-нибудь про apt
>>773796
#693 #773785
>>773544

>во-первых, CGI это несерьезно. Он делался скорее для каких-то любительских вещей. Сейчас используют либо php как модуль Апача, либо php-fpm, взаимодействующий с сервером через FCGI.


Мне помимо 7.0, который как модуль апача стоит, нужны 5.2 и 5.3, для запуска мамонтов. Вот таким способом и запускаю, лучше вариантов не нашел.

>Ты их компилируешь (или устанавливаешь пакетным менеджером, или качаешь готовые) и подключаешь в php.ini.


А вот как мне например pecl'ом получить gd.so с поддержкой freetype? Как-то это все сложно и в гугле очень скупо на эту тему.
>>773789>>773790
#694 #773789
>>773785

CGI очень неэффективен. В твоем случае гораздо логичнее либо использовать php-fpm либо несколько Апачей с разными версиями пхп. И по моему даже есть какая-то штука, чтобы один Апач мог работать с разными версиями.

> А вот как мне например pecl'ом получить gd.so с поддержкой freetype? Как-то это все сложно и в гугле очень скупо на эту тему.


В мануале написано что gd входит в состав php. Следовательно, нужная поддержка включается флагами (наверно в ./configure) при сборке php.
>>773821
#695 #773790
>>773785

Более того, ты не прочел даже мануал который я дал.

http://php.net/manual/ru/image.installation.php

Тут написано про freetype. Ну и никто тебе не мешает сделать ./configure --help
>>773821
#696 #773796
>>773747

>> придется какими-то плохими методами вроде статических методов получать нужные зависимости.


так а как следует поступать? и что делает методы, о которых ты пишешь _плохими_? Это объективные данные?
>>773814
#697 #773800
>>773560
да тут не с апта надо начинаит, а надо с... а бог знает, с чего.
Вот там выше советовали хендбук генту. Как бы жутко это ни звучало, но это, наверное, неплохое решение.
Ну, и практика, посоны. Без практики...
>>773814
#698 #773814
>>773796

В уроке по DI написаны недостатки статических методов.

>>773800

Если у него дебиан то лучше наверно дебиановское руководство.
#699 #773821
>>773789
Что-то слишком круто. Я модуль то для cgi накатить не могу.
>>773790
Прочел, я десяток раз пост перписал, лол. Переконфигурирую, спасибо. Надеялся что не придется это делать.
Ответы #700 #773828
>>753774

Сойдет, хотя я бы написал как "[^"]*?" - так надежнее по моему

>>753870

увы, не знаю, надо смотреть документацию

>>755563

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

>>755864

Не знаю, документацию может быть, но не знаю, есть ли там то, что нужно.

>>756017

композер ставит все в vendor в текущую папку + держит кеш домашней директории пользователя

>>756490

Объекты животных, например:

$animal = new Cat;
$animals[] = $animal;

>>756755

Поищи.

>>757866

не понял вопрос. Что значит "забивалось в html-овский insert"?
Ответы #700 #773828
>>753774

Сойдет, хотя я бы написал как "[^"]*?" - так надежнее по моему

>>753870

увы, не знаю, надо смотреть документацию

>>755563

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

>>755864

Не знаю, документацию может быть, но не знаю, есть ли там то, что нужно.

>>756017

композер ставит все в vendor в текущую папку + держит кеш домашней директории пользователя

>>756490

Объекты животных, например:

$animal = new Cat;
$animals[] = $animal;

>>756755

Поищи.

>>757866

не понял вопрос. Что значит "забивалось в html-овский insert"?
Ответы - вектор #701 #773829
>>757886

> public function addEmployee($employee)


> {


> if(class_exists($employee[0]))


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

>public function fireEmployee($employee)


> $employeeKey = array_search($employee, $this->employees);


почитай мануал по array-search. У тебя он может уволить не того работника, что передан. Там есть дополнительный параметр.

> public function countEmployees($position)


Вообще эта функция смотрится очень специализированно (заточена под антикризисную задачу), а не универсальной и что-то мне кажется, что она должна быть не в департаменте. Также, она смотрится переусложненной. Чтобы отобрать N% работников определенной професссии, проще взять всех работников, соответствующих условиям, отсорттировать по рангу и взять первые N% из списка.

> public function findEmployee($position, $boss, $rank)


Для поиска по произвольному критерию удобнее использовать анонимные функции:

find(function ($e) { return $e->rank > 1; });

Для департамента не определен __clone, потому он при клонировании не создает клоны работников, а сохраняет ссылки на старые объекты.

> $employee->boss = true;


> $i+=1;


> }


> if(max(array_flip($analystQuantity)) > $employee->rank && $employee->boss == true)


> $employee->boss = false;


Смена босса должна делаться методом в департаменте, а не вот такими вот костылями. Ты вместо выделения отдельных операций в методы пишешь код сплошной стеной из отдельных команд.

Код лучше было бы написать так:

- найти босса
- если он не аналитик, то найти аналитика высшего ранга
- назначить его боссом

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

> Опять возникла проблема с клонированием: клоны перезаписывают оригинал с каждым использованием. И почему-то количество работников в норме, а вот зарплата, кофе, страницы меняются.


Потому что ты не клонируешь работников вместе с департаментом
Ответы - вектор #701 #773829
>>757886

> public function addEmployee($employee)


> {


> if(class_exists($employee[0]))


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

>public function fireEmployee($employee)


> $employeeKey = array_search($employee, $this->employees);


почитай мануал по array-search. У тебя он может уволить не того работника, что передан. Там есть дополнительный параметр.

> public function countEmployees($position)


Вообще эта функция смотрится очень специализированно (заточена под антикризисную задачу), а не универсальной и что-то мне кажется, что она должна быть не в департаменте. Также, она смотрится переусложненной. Чтобы отобрать N% работников определенной професссии, проще взять всех работников, соответствующих условиям, отсорттировать по рангу и взять первые N% из списка.

> public function findEmployee($position, $boss, $rank)


Для поиска по произвольному критерию удобнее использовать анонимные функции:

find(function ($e) { return $e->rank > 1; });

Для департамента не определен __clone, потому он при клонировании не создает клоны работников, а сохраняет ссылки на старые объекты.

> $employee->boss = true;


> $i+=1;


> }


> if(max(array_flip($analystQuantity)) > $employee->rank && $employee->boss == true)


> $employee->boss = false;


Смена босса должна делаться методом в департаменте, а не вот такими вот костылями. Ты вместо выделения отдельных операций в методы пишешь код сплошной стеной из отдельных команд.

Код лучше было бы написать так:

- найти босса
- если он не аналитик, то найти аналитика высшего ранга
- назначить его боссом

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

> Опять возникла проблема с клонированием: клоны перезаписывают оригинал с каждым использованием. И почему-то количество работников в норме, а вот зарплата, кофе, страницы меняются.


Потому что ты не клонируешь работников вместе с департаментом
>>774244
Ответы #702 #773830
>>761025

Можно в конфиге в файле, если он один раз туда впишется и больше не используется. Также, доступ можно закрыть через http-авторизацию.

>>762026

Надо читать мануалы. learn.javascript.ru, MDN, caniuse и так далее.

Ну и ты сам ведь написал, в чем различия:

> Да, понятно, что нужны фолбеки для определения события для разных браузеров, поддержка скролла с клавы и на мобилах, заворачивание в плагин и т. д.



Попробуй все это реализовать, при этом соблюдая приницпы вроде:

- не должно быть копипасты
- не должно быть длинных полотен кода в одной функции
- разные опции должны настраиваться
- поддержка разных версий браузеров

И может у тебя выйдет примерно то же.

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

Или например у тебя есть такая штука:

> [id^="page"]


получается если на странице есть такие id то твой код на них повлияет.

Вообще, его код выглядит каким-то переусложненным. Мне он не особо нравится. А твой выглядит вообще непригодным для реального использования.

>>762131

Если нет АПИ то значит нельзя. Если это программа для управления множеством аккаунтов то такое у нас не обсуждается.
Ответы #702 #773830
>>761025

Можно в конфиге в файле, если он один раз туда впишется и больше не используется. Также, доступ можно закрыть через http-авторизацию.

>>762026

Надо читать мануалы. learn.javascript.ru, MDN, caniuse и так далее.

Ну и ты сам ведь написал, в чем различия:

> Да, понятно, что нужны фолбеки для определения события для разных браузеров, поддержка скролла с клавы и на мобилах, заворачивание в плагин и т. д.



Попробуй все это реализовать, при этом соблюдая приницпы вроде:

- не должно быть копипасты
- не должно быть длинных полотен кода в одной функции
- разные опции должны настраиваться
- поддержка разных версий браузеров

И может у тебя выйдет примерно то же.

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

Или например у тебя есть такая штука:

> [id^="page"]


получается если на странице есть такие id то твой код на них повлияет.

Вообще, его код выглядит каким-то переусложненным. Мне он не особо нравится. А твой выглядит вообще непригодным для реального использования.

>>762131

Если нет АПИ то значит нельзя. Если это программа для управления множеством аккаунтов то такое у нас не обсуждается.
#703 #773860
>>762026
Оставь в покое скролл. Сколько не видел решений с изменением скролла - все жутко неудобные и меняют функциональность в худшую сторону, причем взамен ничего не дают. Браузеры-операционки-разрешения-драйверы мыши не у всех одинаковые, и то, что у тебя нормально выглядит, на другом компе будет крайне уебищно смотреться и мешать навигации по сайту. С этим то же самое. Руки бы отрывал, кто в продакшн менялку скролла ставит. Что касается JS, то он там довольно стандартный, любая книга по JS тебя такому научит. Причем автор явно тоже не заморачивался чтением книг по JS, у него куски кода там просто тупо скопипасчены из stackoverflow c указанием откуда вставлял. Размер большой из-за обратной совместимости с разными браузерами, которой в твоем коде нет, плюс всяческие настройки и хаки.

>не пойму как писать такой профессионально выглядящий нихера непонятный код вместо


Это как раз признак плохого кода. Функции и переменные названы как попало, кругом навставлены куски всего подряд, связи проследить сразу трудно, jsdoc или внятных комментов нет, про solid автор судя по всему вообще не слышал, зачем-то написано, что pure javascript, хотя используется jquery. Писать такой код научиться не очень сложно, открой руководства по Javascript, раздел ООП и колбэки, и доку по Jquery/плагинам к нему, остальное догугли по именам функций.
15 Кб, 552x457
11 Кб, 879x129
#704 #773937
Возможно сделать перехватчик необъявленных статических методов и свойств?

Сейчас у меня Uncaught Error: Access to undeclared static property: Container::$config
>>774493
2550 Кб, Webm
#705 #774244
>>773829

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


Сделал отдел кадров и унаследовал от него департамент

>>почитай мануал по array-search. У тебя он может уволить не того работника, что передан. Там есть дополнительный параметр.


Ты хочешь сказать, что array_search выдает ключ первого попавшегося подходящего значения? Если так, то я передаю ему объект и он ищет его в массиве и все норм вроде.

>>Для поиска по произвольному критерию удобнее использовать анонимные функции


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

>>Для департамента не определен __clone


исправил

>>Смена босса должна делаться методом в департаменте, а не вот такими вот костылями.


исправил

Есть вопрос по Кошкам-Мышкам:
Как найти самую ближнюю кошку? Нужно как-то сравнить высоту и ширину на поле, но я пока не понял как. Попробовал воспользоваться сложением высоты и ширины и сравнением этой суммы мышки и кошки, но в некоторых случаях этот способ дает неверный результат.

Вектор http://ideone.com/H5DCfT
Набросок Кошек-Мышек http://ideone.com/f1aQaw
>>774493
#706 #774493
>>773937

Там по моему есть __callStatic, но я хочу предупредить что ты занимаешься плохими вещами:

- 2 контейнера это плохо
- статические методы это плохо в данном случае
- писать код внутри строки это очень плохо

>>774244

> Сделал отдел кадров и унаследовал от него департамент



Нельзя наследовать что угодно от чего угодно. Наследование - это отношение "A является B" (is-a relation). Например: "Кошка является Животным" или "Танк является СредствомПередвижения".

Департамент - это не улучшенная версия отдела кадров.

> Ты хочешь сказать, что array_search выдает ключ первого попавшегося подходящего значения? Если так, то я передаю ему объект и он ищет его в массиве и все норм вроде.


Ты читал мануал? Есть 2 способа сравнения объектов: по содержимому полей и по идентичности и почти всегда нужно последнее.

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


А ты попробуй - скорее будет проще

> Как найти самую ближнюю кошку?


Взять список кошек, найти в цикле расстояния до каждой и взять ту, до которой расстояние меньшее.

Там правда есть два разных расстояни:

- декартово - вычисляется через корень - реальное расстояние между точками на плоскости
- "игровое" - минимальное число ходов, нужное чтобы дойти из точки A в B.

Например, если кошка и мышка стоят по диагонали друг от друга, то декартово расстояние = корень из 2 ~ 1.41, а игровое - 1, так как кошка может за 1 ход дойти до клеточки с мышкой.
#706 #774493
>>773937

Там по моему есть __callStatic, но я хочу предупредить что ты занимаешься плохими вещами:

- 2 контейнера это плохо
- статические методы это плохо в данном случае
- писать код внутри строки это очень плохо

>>774244

> Сделал отдел кадров и унаследовал от него департамент



Нельзя наследовать что угодно от чего угодно. Наследование - это отношение "A является B" (is-a relation). Например: "Кошка является Животным" или "Танк является СредствомПередвижения".

Департамент - это не улучшенная версия отдела кадров.

> Ты хочешь сказать, что array_search выдает ключ первого попавшегося подходящего значения? Если так, то я передаю ему объект и он ищет его в массиве и все норм вроде.


Ты читал мануал? Есть 2 способа сравнения объектов: по содержимому полей и по идентичности и почти всегда нужно последнее.

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


А ты попробуй - скорее будет проще

> Как найти самую ближнюю кошку?


Взять список кошек, найти в цикле расстояния до каждой и взять ту, до которой расстояние меньшее.

Там правда есть два разных расстояни:

- декартово - вычисляется через корень - реальное расстояние между точками на плоскости
- "игровое" - минимальное число ходов, нужное чтобы дойти из точки A в B.

Например, если кошка и мышка стоят по диагонали друг от друга, то декартово расстояние = корень из 2 ~ 1.41, а игровое - 1, так как кошка может за 1 ход дойти до клеточки с мышкой.
#707 #774640
>>773648

>> if ($registerStudentForm->getPassword() != "") {


>> $registerStudentForm->setStudentPassword();


>Вообще, это можно было бы делать в классе формы в методе fillDataFromArray


Прежде чем задавать студенту хэш нужно проверить пароль на валидность. Из названии функции наверно кажется что я меня именно пароль, а не создаю хеши?

>>773648

>>if (Helper::validCSRFtoken($_GET['token']) and $this->loginAction->isLoggedIn()) {


>> $student = $this->studentGateway->getStudentByСolumn('id', $_COOKIE['id']);


>Вот здесь странно. Если у тебя есть сервис авторизации и ты через него проверяешь залогиненность, то разве не логично через него же и получать текущего пользователя? Почему у тебя проверка залогиненности в одном месте, а получение пользователя - в другом?


Не знаю, мне казалось что если есть какая-то проверка на что-то, то результат должен быть true\false и не более.
Вообще это очевидно что результат должен быть в зависимости от требований задачи, но я и представить не мог что такое где-нибудь понадобиться. То есть я думал что этот метод будет использоваться только в проверках, и в моем случае изначально после проверки на залогиненность была проверка на токен а потом уже получение пользователя.

>Можно завести булеву переменную $isEdit:


>$isEdit = $this->loginAction->isLoggedIn();


Если результат этого метода будет сущность студента, то ничего страшного если переменная $isEdit будет содержать не булевое значение? Ведь на практике это можно применить точно так же.

>>773648

>Более того, проверяешь авторизацию ты контроллером, а залогинаваешь пользователя в классе со странным названием StudentCookies.


В каком именно месте это не правильно? В месте где я перезалогиниваю пользователя после редактирования?
Вообще я залогиниваю пользователя с помощью контроллера https://github.com/someApprentice/Students/blob/master/app/Controller/LoginAction.php#L41

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

>>773648

>По моему это нелогично, что код, отвечающий за авторизацию разбросан по всему приложению. Мне кажется, логичнее сделать единый сервис авторизации, который умеет:


>


>- залогинивать пользователя (ставить нужные куки)


>- разлогинивать


>- проверять залогинен ли пользователь


>


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


Но ведь уже есть контроллер который занимается этим. Или ты имеешь ввиду переделать так чтобы контроллер пользовался вышеперечисленными методами сервиса?

>>773648

>Далее, нет логики в наследовании хелперов. Вот у тебя есть Helper и есть LoginHelper, который его наследует. Непонятно, а зачем? Там все равно почти все методы статические. Точнее, часть статическая, а часть нет, и почему, непонятно.


Раньше LoginHelper наследовался чтобы избавиться от копипасты метода перенаправления.

А разве в одном классе все методы должны быть либо статические либо не статические? Почему?

>>773648

>Также, ты указал для кук в качестве домена 'localhost' и получается что на другом домене твое приложение не будет работать (не будет ставить куки).


У меня без этого куки не работали почему-то - при разлогинивании не удалялись и при повторном залогинивании создавалась еще одна копия. Сейчас снова поставил этот параметр на null и все работает. Странно.

>>773648

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


Так токен нужен же для защиты от CSRF. Его удобно держать в студенте, потому что мы создаем куки на его основе.
#707 #774640
>>773648

>> if ($registerStudentForm->getPassword() != "") {


>> $registerStudentForm->setStudentPassword();


>Вообще, это можно было бы делать в классе формы в методе fillDataFromArray


Прежде чем задавать студенту хэш нужно проверить пароль на валидность. Из названии функции наверно кажется что я меня именно пароль, а не создаю хеши?

>>773648

>>if (Helper::validCSRFtoken($_GET['token']) and $this->loginAction->isLoggedIn()) {


>> $student = $this->studentGateway->getStudentByСolumn('id', $_COOKIE['id']);


>Вот здесь странно. Если у тебя есть сервис авторизации и ты через него проверяешь залогиненность, то разве не логично через него же и получать текущего пользователя? Почему у тебя проверка залогиненности в одном месте, а получение пользователя - в другом?


Не знаю, мне казалось что если есть какая-то проверка на что-то, то результат должен быть true\false и не более.
Вообще это очевидно что результат должен быть в зависимости от требований задачи, но я и представить не мог что такое где-нибудь понадобиться. То есть я думал что этот метод будет использоваться только в проверках, и в моем случае изначально после проверки на залогиненность была проверка на токен а потом уже получение пользователя.

>Можно завести булеву переменную $isEdit:


>$isEdit = $this->loginAction->isLoggedIn();


Если результат этого метода будет сущность студента, то ничего страшного если переменная $isEdit будет содержать не булевое значение? Ведь на практике это можно применить точно так же.

>>773648

>Более того, проверяешь авторизацию ты контроллером, а залогинаваешь пользователя в классе со странным названием StudentCookies.


В каком именно месте это не правильно? В месте где я перезалогиниваю пользователя после редактирования?
Вообще я залогиниваю пользователя с помощью контроллера https://github.com/someApprentice/Students/blob/master/app/Controller/LoginAction.php#L41

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

>>773648

>По моему это нелогично, что код, отвечающий за авторизацию разбросан по всему приложению. Мне кажется, логичнее сделать единый сервис авторизации, который умеет:


>


>- залогинивать пользователя (ставить нужные куки)


>- разлогинивать


>- проверять залогинен ли пользователь


>


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


Но ведь уже есть контроллер который занимается этим. Или ты имеешь ввиду переделать так чтобы контроллер пользовался вышеперечисленными методами сервиса?

>>773648

>Далее, нет логики в наследовании хелперов. Вот у тебя есть Helper и есть LoginHelper, который его наследует. Непонятно, а зачем? Там все равно почти все методы статические. Точнее, часть статическая, а часть нет, и почему, непонятно.


Раньше LoginHelper наследовался чтобы избавиться от копипасты метода перенаправления.

А разве в одном классе все методы должны быть либо статические либо не статические? Почему?

>>773648

>Также, ты указал для кук в качестве домена 'localhost' и получается что на другом домене твое приложение не будет работать (не будет ставить куки).


У меня без этого куки не работали почему-то - при разлогинивании не удалялись и при повторном залогинивании создавалась еще одна копия. Сейчас снова поставил этот параметр на null и все работает. Странно.

>>773648

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


Так токен нужен же для защиты от CSRF. Его удобно держать в студенте, потому что мы создаем куки на его основе.
>>779253
27 Кб, 493x386
#708 #774668
>>771148

>кем вы себя видите через 5 лет


Каждый раз.
36 Кб, 1009x214
#709 #774671
Я снова выхожу на связь.
Установил MySQL и Apache.
Не получается установить РНР.
Вот что выдаёт
<----
Делают вот по тому, что пацанчик описал вот тут: https://codebeer.ru/ustanovka-php-7-v-debian-8/

Скачиваем и распаковываем исходники PHP 7.0.4:

>wget http://de1.php.net/get/php-7.0.4.tar.bz2/from/this/mirror -O php-7.0.4.tar.bz2


>tar -xvjf php-7.0.4.tar.bz2



Переходим в каталог с исходниками PHP 7:

>cd php-7.0.4



Для того чтобы установить PHP 7, нам необходимо выполнить компиляцию из исходников.
./buildconf --force

CONFIGURE_STRING="--prefix=/usr/local/php-fpm
--enable-fpm
--enable-mysqlnd
--enable-mbstring
--disable-pdo
--disable-phar
--with-config-file-scan-dir=/usr/local/php-fpm/etc/conf.d
--with-curl
--with-gd
--with-fpm-user=www-data
--with-fpm-group=www-data
--with-mysql-sock=/var/run/mysqld/mysqld.sock
--with-mysqli=mysqlnd
--with-zlib
--without-sqlite3
--without-pdo-sqlite"

Далее делаю
./configure $CONFIGURE_STRING
make && make install
и получаю вот то, что на скриншоте.
Какой permission denied, о чём ты несёшь?..

Спасибо, попробую это сделать тоже.
>>773121
>>773139
>>773553
Обновлю sourcelist. Но вроде проблем же не возникло с установкой Мускула и Апача, что теперь надо где указать - может, подскажете? Заранее благодарен.
36 Кб, 1009x214
#709 #774671
Я снова выхожу на связь.
Установил MySQL и Apache.
Не получается установить РНР.
Вот что выдаёт
<----
Делают вот по тому, что пацанчик описал вот тут: https://codebeer.ru/ustanovka-php-7-v-debian-8/

Скачиваем и распаковываем исходники PHP 7.0.4:

>wget http://de1.php.net/get/php-7.0.4.tar.bz2/from/this/mirror -O php-7.0.4.tar.bz2


>tar -xvjf php-7.0.4.tar.bz2



Переходим в каталог с исходниками PHP 7:

>cd php-7.0.4



Для того чтобы установить PHP 7, нам необходимо выполнить компиляцию из исходников.
./buildconf --force

CONFIGURE_STRING="--prefix=/usr/local/php-fpm
--enable-fpm
--enable-mysqlnd
--enable-mbstring
--disable-pdo
--disable-phar
--with-config-file-scan-dir=/usr/local/php-fpm/etc/conf.d
--with-curl
--with-gd
--with-fpm-user=www-data
--with-fpm-group=www-data
--with-mysql-sock=/var/run/mysqld/mysqld.sock
--with-mysqli=mysqlnd
--with-zlib
--without-sqlite3
--without-pdo-sqlite"

Далее делаю
./configure $CONFIGURE_STRING
make && make install
и получаю вот то, что на скриншоте.
Какой permission denied, о чём ты несёшь?..

Спасибо, попробую это сделать тоже.
>>773121
>>773139
>>773553
Обновлю sourcelist. Но вроде проблем же не возникло с установкой Мускула и Апача, что теперь надо где указать - может, подскажете? Заранее благодарен.
>>774776
#710 #774700
Устанавливаю PHP5, вот до чего доводит желание разобраться в Yii2 по вот этому руководству: >>764665
Так и не нашёл нормальной информации для установки РНР7.
Придётся окунаться в эти экскременты доисторических животных.
Честно говоря, жалею, что вообще затеял установку Дебиан и так далее. Надо было просто искать аналоги для cmd.exe, хотя бы попробовать.
>>774776
#711 #774723
public function __construct(UserTableGateway $userTableGateway) { ... }

Кто-то может пояснить такой синтаксис? Почему перед аргументом конструктора какой-то непнятный bareword?
>>774730
#713 #774736
>>774730
мерси
#714 #774776
>>774671

make install надо делать от рута (а вот остальное не стоит, чтобы при ошибке не разломать себе систему)

Ну подумай сам, install копирует собранные бинарники в системные директории.

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

>>774700

Плохо искал. В дебиане софт всегда в стабильной ветке не новый. для новых версий надо подключать сторонний репозиторий вроде dotdeb.
>>775033
#715 #774876
Мне кажется, я правильно понял (наконец-то) суть TDG
(обработку ошибок для краткости опустил)

# Класс объекта для работы с БД
class Handler {
public $hostname;
public $username;
public $password;
public $databaseName;
public function __construct($hostname, $username, $password, $databaseName ) {
$this->hostname = $hostname;
$this->username = $username;
$this->password = $password;
$this->databaseName = $databaseName;
}

public function dbConnect() {
$dbh = mysqli_connect($this->hostname, $this->username, $this->password, $this->databaseName);
return $dbh;
}

#касс, описывающий таблицу users
class Users {
public $uid;
public $ulogin;
public $upass;
public $handler;

## handler передаём в конструкторе
public function __construct(Mysqli $handler) {
$this->handler = $handler;
}

# простая выборка логина по ID
public function getUserNameById($uid) {
$dbh = $this->handler;
$stmt = $dbh->prepare("SELECT ulogin, upass FROM authorise WHERE uid=?");
$stmt->bind_param("i", $uid);
$stmt->execute();
$result = $stmt->get_result();
return $result;
}
}

# код теста всего хозяйства
$dbh = new Handler("localhost", "user", "password", "db_name"); ## конечно они будут передаваться не так, а в переменных. Это для краткости
$users = new Users($dbh->dbConnect());
$user = $users->getUserNameById(2);
$user1 = $user->fetch_assoc();
echo $user1["ulogin"];

данный код работает корректно, но кошерен ли он с точки зрения правиьного программирования?
#715 #774876
Мне кажется, я правильно понял (наконец-то) суть TDG
(обработку ошибок для краткости опустил)

# Класс объекта для работы с БД
class Handler {
public $hostname;
public $username;
public $password;
public $databaseName;
public function __construct($hostname, $username, $password, $databaseName ) {
$this->hostname = $hostname;
$this->username = $username;
$this->password = $password;
$this->databaseName = $databaseName;
}

public function dbConnect() {
$dbh = mysqli_connect($this->hostname, $this->username, $this->password, $this->databaseName);
return $dbh;
}

#касс, описывающий таблицу users
class Users {
public $uid;
public $ulogin;
public $upass;
public $handler;

## handler передаём в конструкторе
public function __construct(Mysqli $handler) {
$this->handler = $handler;
}

# простая выборка логина по ID
public function getUserNameById($uid) {
$dbh = $this->handler;
$stmt = $dbh->prepare("SELECT ulogin, upass FROM authorise WHERE uid=?");
$stmt->bind_param("i", $uid);
$stmt->execute();
$result = $stmt->get_result();
return $result;
}
}

# код теста всего хозяйства
$dbh = new Handler("localhost", "user", "password", "db_name"); ## конечно они будут передаваться не так, а в переменных. Это для краткости
$users = new Users($dbh->dbConnect());
$user = $users->getUserNameById(2);
$user1 = $user->fetch_assoc();
echo $user1["ulogin"];

данный код работает корректно, но кошерен ли он с точки зрения правиьного программирования?
>>774905>>774909
#716 #774905
>>774876

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

Если ты хочешь использовать mysqli то (тебе лично) надо прочитать как минимум введение целиком и просмотреть мануал по всем ее функциям сначала.

Класс Handler непонятно зачем нужен и вообще выглядит бесполезно.

Почему mysqli_connect, а не new mysqli?

Названия классов неудачные.

Users -> USersTable, UsersTableGateway

> $user = $users->getUserNameById(2);


> $user1 = $user->fetch_assoc();


Это неправильнро. Судя по названию, функция getUserNameById должна вернуть строку с именем. А у тебя возвращается непонятно что. Вся работа с базой данных должна быть внутри TDG а если ты возвращаешь объект mysqli то это значит что это правило не соблюдается.

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

Так, отдаленно напоминает TDG.
>>775013
#717 #774909
>>774876

А, еще непонятно что в классе USers делают поля $ulogin, $upass. Для чего у тебя этот класс? Что представляет его объект? Пользователя? Тогда в методе getUserNameById не должно быть аргумента $uid.

По моему ты плоховато понял суть паттерна. Объект TDG это объект, представляющий интерфейс (шлюз) к базе данных. Он не хранит внутри информацию о пользователях.

Ты же просто намешал в классе все, что придет в голову. У меня ощущение что ты слабовато понимаешь ООП. В ООП нельзя просто так сваливать в класс любые поля и методы, там есть определенная логика. Каждый класс выполняет какую-то свою задачу.
>>775011
28 Кб, 493x97
#718 #774911
ОП, это как-то можно упростить? Пик 1. Просто намёка или названия функции мне должно хватить.
Такой if/else делать нужно, так как $search может быть пустым и тогда матчится пустая строка, на выходе каждый символ становится разделённым тегом b.
Я ковырял preg_replace_callback, но получилось ещё запутаннее.
>>774912>>774945
#719 #774912
>>774911
return $string ? "<b>$string</b>" : $string;
>>774913>>774914
97 Кб, 543x769
#720 #774913
>>774912
Тупанул
20 Кб, 725x50
#721 #774914
>>774912
Та норм всё, я тебя понял. А флагов там нет каких-то, по типу PREG_SPLIT_NO_EMPTY?
>>774915
#722 #774915
>>774914
Не знаю. А первый вариант лучше был, читабельней.
#723 #774945
>>774911

Тут не надо ничего упрощать.
31 Кб, 599x244
11 Кб, 619x63
https://github.com/applejacky/students #724 #774967
>>773741
Первый блин деплоя стал комом: https://secondtryphp-veryfirtsapp.rhcloud.com/
Если у кого есть желание потестить и сообщить о неисправностях - то буду вам очень благодарен.
SSH-сессия очень кастрированная (на 1-м пике список всех доступных команд), но зато бесплатно 3 постоянно доступных сайта.

>> convertPcreRegexToHtml5($pcreRegex)


> Ты серьезно? Одной маленькой регуляркой ты преобразуешь один синтаксис в другой? Не, это не будет работать.


Максимум, что я могу сделать - изменить название функции с пафосного на более приземлённое - deleteStartEndAnchors. Я почитал про регулярки в JS и так и не понял, что мне нужно менять в этих: https://github.com/applejacky/students/blob/6d2bea191317e4195c9e5f8aa61a1088b298bce6/app/Lib/StudentValidator.pбылhp#L11
Исключая привязку по краям, разумеется. На пике 2 - то, что выводится на страницу, хотя ты и так можешь по верхней ссылке глянуть.

>Плюс, он почему-то работает из-под рута, что опасно, чуть что не так и легко разломать систему.


Мне самому эту штуку сразу было страшно запускать. Но я всё протестировал на голой убунте. Ну и не знаю как по-другому. Без прав суперпользователя в изкоробочной убунте нельзя добавлять виртуальные хосты. Разумеется, ещё ограничен доступ к менеджеру пакетов и /etc/hosts

>Зачем-то прописывает записи в hosts. А на продакшене ты тоже будешь адрес домена на 127.0.0.1 направлять?


Вынес в переменную ip_addr. Скрипт только для использования на локалхосте. Я не знаю как на продакшене должно быть.

>> function die {


>> kill $$


> Ой, как все сложно и запутанно.


Я объяснил в предыдущем посте, почему так сделал.

>Проще сказать пользователю отредактировать конфиг или предоставить файл локального конфига.


Не понимаю. То есть ты предлагаешь такую последовательность действий для развёртывания на локалхосте:
1. Склонировать репозиторий;
2. Найти конфиг и поправить его;
3. Запустить скрипт, который будет создавать виртуальный хост, включать апач и прочее.

Я же предлагаю сделать так:
1. Скачать скрипт и запустить его. В процессе установки cкрипт склонирует репозиторий и предложит ввести данные для подлючения к бд, которые запишутся в config.ini
Всё в одном месте, неужели так хуже?

>В разных дистрибутивах линукса конфиги Апача могут быть организованы по-разному и храниться в разных папках.


Насколько я помню, то для Arch (и, скорее всего для Red Hat based) нужно поменять apache_root с '/var/www' на '/srv/http', а виртуальные хосты класть в /etc/httpd/conf/extra, что в общем-то неважно, так как путь можно любой указывать. Другое дело, что там нет a2ensite/a2enmode, то есть мне придётся шаманить sed'ом подключение виртульных хостов в httpd.conf
Хорошо, я займусь этим, но попозже.
31 Кб, 599x244
11 Кб, 619x63
https://github.com/applejacky/students #724 #774967
>>773741
Первый блин деплоя стал комом: https://secondtryphp-veryfirtsapp.rhcloud.com/
Если у кого есть желание потестить и сообщить о неисправностях - то буду вам очень благодарен.
SSH-сессия очень кастрированная (на 1-м пике список всех доступных команд), но зато бесплатно 3 постоянно доступных сайта.

>> convertPcreRegexToHtml5($pcreRegex)


> Ты серьезно? Одной маленькой регуляркой ты преобразуешь один синтаксис в другой? Не, это не будет работать.


Максимум, что я могу сделать - изменить название функции с пафосного на более приземлённое - deleteStartEndAnchors. Я почитал про регулярки в JS и так и не понял, что мне нужно менять в этих: https://github.com/applejacky/students/blob/6d2bea191317e4195c9e5f8aa61a1088b298bce6/app/Lib/StudentValidator.pбылhp#L11
Исключая привязку по краям, разумеется. На пике 2 - то, что выводится на страницу, хотя ты и так можешь по верхней ссылке глянуть.

>Плюс, он почему-то работает из-под рута, что опасно, чуть что не так и легко разломать систему.


Мне самому эту штуку сразу было страшно запускать. Но я всё протестировал на голой убунте. Ну и не знаю как по-другому. Без прав суперпользователя в изкоробочной убунте нельзя добавлять виртуальные хосты. Разумеется, ещё ограничен доступ к менеджеру пакетов и /etc/hosts

>Зачем-то прописывает записи в hosts. А на продакшене ты тоже будешь адрес домена на 127.0.0.1 направлять?


Вынес в переменную ip_addr. Скрипт только для использования на локалхосте. Я не знаю как на продакшене должно быть.

>> function die {


>> kill $$


> Ой, как все сложно и запутанно.


Я объяснил в предыдущем посте, почему так сделал.

>Проще сказать пользователю отредактировать конфиг или предоставить файл локального конфига.


Не понимаю. То есть ты предлагаешь такую последовательность действий для развёртывания на локалхосте:
1. Склонировать репозиторий;
2. Найти конфиг и поправить его;
3. Запустить скрипт, который будет создавать виртуальный хост, включать апач и прочее.

Я же предлагаю сделать так:
1. Скачать скрипт и запустить его. В процессе установки cкрипт склонирует репозиторий и предложит ввести данные для подлючения к бд, которые запишутся в config.ini
Всё в одном месте, неужели так хуже?

>В разных дистрибутивах линукса конфиги Апача могут быть организованы по-разному и храниться в разных папках.


Насколько я помню, то для Arch (и, скорее всего для Red Hat based) нужно поменять apache_root с '/var/www' на '/srv/http', а виртуальные хосты класть в /etc/httpd/conf/extra, что в общем-то неважно, так как путь можно любой указывать. Другое дело, что там нет a2ensite/a2enmode, то есть мне придётся шаманить sed'ом подключение виртульных хостов в httpd.conf
Хорошо, я займусь этим, но попозже.
>>775178>>775180
#725 #775011
>>774909
спасибо ОП
буду думать

А что можешь посоветовать почитать по философии ООП в целом? Я похоже и правда не до конца понимаю суть ооп
>>775030>>779254
#726 #775013
>>774905

>>надо прочитать как минимум введение целиком и просмотреть мануал по всем ее функциям сначала.



Ты о каком введении говоришь?
>>779254
#727 #775030
>>775011
Cкорее всего ОП тебе посоветует почитать его пасту по ООП: http://archive-ipq-co.narod.ru/l1/pasta.html и решить задачки на вектор и студентов. Так что начинай уже сейчас.
51 Кб, 604x307
#728 #775033
>>774776
Спасибо!
Теперь попробую обновиться до РНР7.1.0 чуть позже.
Теперь, благодаря тебе, знаю про Dotdeb и sourcelist.
Про make install понял, спасибо.
#729 #775178
>>774967

Так, если в код не заглядывать, впечатление хорошее.

На форме регистрации нет подтверждения пароля. Это плохо, так как легко опечататься или ввексти не в той раскладке. пароль должен либо быть виден либо потверждаться.

Текст ошибки "CSRF-токены не совпадают" надо подправить, уменьшив объем технических подробностей в пользу советов, что делать пользователю.

> Я не знаю как на продакшене должно быть.


На продакшене хостс трогать не надо так как домен обслуживается ДНС сервером.

> Я же предлагаю сделать так:


> 1. Скачать скрипт и запустить его. В процессе установки cкрипт склонирует репозиторий и предложит ввести данные для подлючения к бд, которые запишутся в config.ini


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

> Хорошо, я займусь этим, но попозже.


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

> >> convertPcreRegexToHtml5($pcreRegex)


> Ты серьезно? Одной маленькой регуляркой ты преобразуешь один синтаксис в другой? Не, это не будет работать.


> Я почитал про регулярки в JS и так и не понял, что мне нужно менять в этих:


я имел в виду что синтаксис pcre нельзя преобразовать в синтаксис js выражений так просто. Значит, твой код работает только в части случаев. Если мы сейчас исправим регулярку, добавив в нее что-то pcre-специфичное, то этот код начнет выдавать некорретные регулярки. Какие я вижу решения? Например, сделать 2 регулярки вручную.
#730 #775180
>>774967

На форме логина https://secondtryphp-veryfirtsapp.rhcloud.com/auth/login стоило хотя бы проставить тип email и required.
#731 #775193
Какие бывают типичные задачи на cms?
Просто не представляю, что подразумевают под "знанием" cms. Полистал документацию - элементарщина, заглянул в код - каша конечно, но разобраться можно.

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

Короче перечислите типичные задачи под вордпресс и магазины (opencart/prestashop).
Потому что пока боязно, наверное недостаточно полистать документацию чтобы заносить в резюме знание cms, нужно наверное сначала что-то сделать на них, только не представляю что.
>>775272>>775324
#732 #775272
>>775193

>Короче перечислите типичные задачи под вордпресс и магазины (opencart/prestashop).



Короче заходишь на фриланс биржу и смотришь.
#733 #775324
>>775193
Например, такой плагин для WP, назовём его CodeInjection:
1. Сколь угодно можно создавать меню, просто текст (в который можно код рекламы запихнуть). Все они расположены списком на странице в админке.
2. Нажимаешь в админке на блок с меню, текстом или кодом - получаешь список всех страниц и записей сайта, рядом с каждой находится чекбокс. Ставишь "галочку" - указанные тобой меню или текст, код появятся на этой странице в сайдбаре.
3. То же самое - для разных частей самих статей: в верху, в середине, в низу статей. Тоже для размещения кода рекламы было бы удобно.
Перекат #734 #775472
Аноны, переходите в новый тред >>769611 (OP)

Не пишите здесь больше. Если я вас пропустил и не ответил, напомните о себе в новом треде.

Здесь сегодня-завтра напишу ответы на старые посты.
#735 #776997
Какие есть готовые функции поиска по массиву по нестандартным параметрам (с помощью пользовательской функции), кроме array_filter ?
Ответы 7-20 июня #736 #779251
>>762607

На 32-битных системах число типа int может принимать значение от -2 млрд до 2 млрд. Операция % тоже поддерживает корректно только числа типа int. Если ты на 32-битной системе делишь числа выходящие за разрешенный предел, результат получается неверный (по хорошему конечно надо в таких случаях выдавать ошибку, но с праивльной работой с ошибками в пхп все плохо).

>>763366

> Как можно описать в regex игнорирование символов " -()", чтобы была возможность указать кол-во цифр в телефоне равное 10?


Можно написать так:

(1 цифра, за ней любое число минусов, скобок, пробелов) повторяется 10 раз

>>763547

> Проблема в том что внутри группы подгруппы выделяются только один раз, в параметре $replacement функции preg_replace() нельзя вывести несколько подгрупп с одинаковыми номерами и совпавшими с разными участками текста.


Можно использовать разные регулярки для поиска слов и для выделения букв в них.

>>763827

program can't start часто бывает из-за того что не установлена нужная версия Visual Studio C++ Runtime (это не сама студия, а небольшая библиотека на несколько мегабайт, качается с оф сайта майкрософт). Посмотри где ты скачивал свой пхп и там наверняка есть упоминание этой библиотеки и какая версия нужна.

>>764269

Если в коде нет поддержки загрузки нескольких файлов, надо либо ее как-то прикрутить либо отказаться от идеи.

> Может быть я тупой и в функции привязанной к хуку save_post надо сделать как-то в цикле вызов другой функции в зависимости от колличества прикрепленных файлов, ибо я сохраняю мету в бд вордпресса и что-то мне подсказывает, что там должна быть мета одного файла и $id одного только post.


Я не могу ничем помочь так как не читал код вордпресса. Это можешь сделать только ты.

>>764664

В задаче про студентов из ОП поста много комментариев. Что значит "правильный"? В разных фреймворках это сделано по разному (Юи, Ларавель, симфони).

Также, у меня есть урок про общие принципы обработки форм: https://github.com/codedokode/pasta/blob/master/forms.md

Вообще, я тебе советую сделать сначала задачу про студентов. У меня ощущение (по формулировке вопроса) что ты довольно много теории пропустил или не знаешь и надо ее наверстать. Там в студентах как раз и формы, и база данных имеется.

>>764916

Честно говоря не вижу разницы. Раньше было:

- приходит запрос, ищутся нужные данные, отдается ответ

Сейчас:

- приходит запрос, отдается статическая страница
- приходит запрос, ищутся данные. отдается джейсон

Итог:

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

По моему ты где-то сильно ошибаешься. Выше ты думал что ob_start медленный, но тест показал что это не так.

Также, ты мельком упомянул что у тебя там выводится 400 кб данных. Я думаю, проблема может быть в этом - слишком много данных выбирается и выводится при каждой загрузке страницы. Уверен что это не требуется - пользователь все равно не способен прочитать 400 Кб текста.

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

Ну и насчет кеша - ты писал что у тебя там миллиард страниц - на таком количестве страниц любой кеш будет неэффективен так как запросы скорее всего идут по большому числу страниц и редко повторяются.
Ответы 7-20 июня #736 #779251
>>762607

На 32-битных системах число типа int может принимать значение от -2 млрд до 2 млрд. Операция % тоже поддерживает корректно только числа типа int. Если ты на 32-битной системе делишь числа выходящие за разрешенный предел, результат получается неверный (по хорошему конечно надо в таких случаях выдавать ошибку, но с праивльной работой с ошибками в пхп все плохо).

>>763366

> Как можно описать в regex игнорирование символов " -()", чтобы была возможность указать кол-во цифр в телефоне равное 10?


Можно написать так:

(1 цифра, за ней любое число минусов, скобок, пробелов) повторяется 10 раз

>>763547

> Проблема в том что внутри группы подгруппы выделяются только один раз, в параметре $replacement функции preg_replace() нельзя вывести несколько подгрупп с одинаковыми номерами и совпавшими с разными участками текста.


Можно использовать разные регулярки для поиска слов и для выделения букв в них.

>>763827

program can't start часто бывает из-за того что не установлена нужная версия Visual Studio C++ Runtime (это не сама студия, а небольшая библиотека на несколько мегабайт, качается с оф сайта майкрософт). Посмотри где ты скачивал свой пхп и там наверняка есть упоминание этой библиотеки и какая версия нужна.

>>764269

Если в коде нет поддержки загрузки нескольких файлов, надо либо ее как-то прикрутить либо отказаться от идеи.

> Может быть я тупой и в функции привязанной к хуку save_post надо сделать как-то в цикле вызов другой функции в зависимости от колличества прикрепленных файлов, ибо я сохраняю мету в бд вордпресса и что-то мне подсказывает, что там должна быть мета одного файла и $id одного только post.


Я не могу ничем помочь так как не читал код вордпресса. Это можешь сделать только ты.

>>764664

В задаче про студентов из ОП поста много комментариев. Что значит "правильный"? В разных фреймворках это сделано по разному (Юи, Ларавель, симфони).

Также, у меня есть урок про общие принципы обработки форм: https://github.com/codedokode/pasta/blob/master/forms.md

Вообще, я тебе советую сделать сначала задачу про студентов. У меня ощущение (по формулировке вопроса) что ты довольно много теории пропустил или не знаешь и надо ее наверстать. Там в студентах как раз и формы, и база данных имеется.

>>764916

Честно говоря не вижу разницы. Раньше было:

- приходит запрос, ищутся нужные данные, отдается ответ

Сейчас:

- приходит запрос, отдается статическая страница
- приходит запрос, ищутся данные. отдается джейсон

Итог:

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

По моему ты где-то сильно ошибаешься. Выше ты думал что ob_start медленный, но тест показал что это не так.

Также, ты мельком упомянул что у тебя там выводится 400 кб данных. Я думаю, проблема может быть в этом - слишком много данных выбирается и выводится при каждой загрузке страницы. Уверен что это не требуется - пользователь все равно не способен прочитать 400 Кб текста.

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

Ну и насчет кеша - ты писал что у тебя там миллиард страниц - на таком количестве страниц любой кеш будет неэффективен так как запросы скорее всего идут по большому числу страниц и редко повторяются.
Ответы 7-20 июня #737 #779252
>>764937

Ок, все верно.

> По регуляркам куча материала осталась. Про то как их составлять. Изучить это или можно двигаться дальше?


Стоит хотя бы прочитать это.

>>764951

> $timers = $mapper->getTimers();


Сдампь $timers и посмотри что в ней

>>765627

> Просто мне кажется, вы усложняете многое правильным и последовательным подходом


Праивльный и последовательный подход поможет много раз. А костыльное решение - только один.

>>766323

Доки почитал бы

>>767064

Нет проверки на ничью, а в остальном все правильно.
Ответы https://github.com/someApprentice/Students #738 #779253
>>774640

>>Вообще, это можно было бы делать в классе формы в методе fillDataFromArray


> Прежде чем задавать студенту хэш нужно проверить пароль на валидность. Из названии функции наверно кажется что я меня именно пароль, а не создаю хеши?


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

- записывать хеш независимо от того праивльный ли пароль
- записывать хеш только после успешной проверки

>>>if (Helper::validCSRFtoken($_GET['token']) and $this->loginAction->isLoggedIn()) {


>>> $student = $this->studentGateway->getStudentByСolumn('id', $_COOKIE['id']);


>>Вот здесь странно. Если у тебя есть сервис авторизации и ты через него проверяешь залогиненность, то разве не логично через него же и получать текущего пользователя? Почему у тебя проверка залогиненности в одном месте, а получение пользователя - в другом?


> Не знаю, мне казалось что если есть какая-то проверка на что-то, то результат должен быть true\false и не более.


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


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

Ну то есть если сформулировать по другому: работа с кукой 'id' должна быть собрана только в одном классе. Больше она не должна нигде использоваться.

И это должен быть сервис (хелпер), а не контроллер. А ты пытаешься использовать контроллер как будто это сервис.

>>$isEdit = $this->loginAction->isLoggedIn();


> Если результат этого метода будет сущность студента, то ничего страшного если переменная $isEdit будет содержать не булевое значение? Ведь на практике это можно применить точно так же.


Можно но тогда надо метод переименовать.

>>Более того, проверяешь авторизацию ты контроллером, а залогинаваешь пользователя в классе со странным названием StudentCookies.


> В каком именно месте это не правильно? В месте где я перезалогиниваю пользователя после редактирования?



1) код в контроллере не предназначен для повторного использования. для этого есть хелперы. Ты поместил код не туда (в контроллер вместо хелпера) и из-за этого вынужден использовать контроллер как хелпер.
2) каждый класс занимается своим делом. Работать с авторизационными куками должен один класс, который за это отвечает. У тебя работа с ними размазана по всей программе.

>>По моему это нелогично, что код, отвечающий за авторизацию разбросан по всему приложению. Мне кажется, логичнее сделать единый сервис авторизации, который умеет:


> Но ведь уже есть контроллер который занимается этим. Или ты имеешь ввиду переделать так чтобы контроллер пользовался вышеперечисленными методами сервиса?


Код в контроллере не стоит повторно использовать, например вызывать из других мест. Это не соответствует идее MVC. Контроллер это тот, кто управляет обработкой запроса от пользователя. Ты не должен создавать контроллер для каких-то других целей, например, чтобы узнать текущего залогиненного пользователя.

Надо было код отвечающий за авторизацию вынести в хелпер. ты вместо этого раскидал его по разным контроллерам.

>>Далее, нет логики в наследовании хелперов. Вот у тебя есть Helper и есть LoginHelper, который его наследует. Непонятно, а зачем? Там все равно почти все методы статические. Точнее, часть статическая, а часть нет, и почему, непонятно.


> А разве в одном классе все методы должны быть либо статические либо не статические? Почему?


Такого ограничения нет. Но должна быть какая-то логика по которой ты делаешь метод статическим или нет. Например, одинаково ли его поведение всегда или разное для разных объектов. Можно ли его вызывать не имея объекта или наоборот, он имеет смысл только если есть объект. У тебя там такой логики нету, слово static поставлено произвольно.

Пример. Допустим мы делаем класс для работы с файлом, имя файла передается в конструктор. Метод "удалить файл" очевидно должен быть нестатическим, так как он работает с объектом, представляющим файл. А вот метод "перевести размер из байтов в мегабайты" логично сделать статическим так как ему в принципе объект не нужен, он всегда одинаково работает, и может вообще использоваться не для файла, а для чего-то еще.

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


> Так токен нужен же для защиты от CSRF. Его удобно держать в студенте, потому что мы создаем куки на его основе.


Токен для защиты от CSRF не имеет никакого отношения к студенту. Потому что:

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

Ты точно читал урок про защиту от CSRF? Токен CSRF сохранять в базу не нужно. Одна копия токена хранится в куке, другая - в скрытом поле формы. База данных тут не нужна.
Ответы https://github.com/someApprentice/Students #738 #779253
>>774640

>>Вообще, это можно было бы делать в классе формы в методе fillDataFromArray


> Прежде чем задавать студенту хэш нужно проверить пароль на валидность. Из названии функции наверно кажется что я меня именно пароль, а не создаю хеши?


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

- записывать хеш независимо от того праивльный ли пароль
- записывать хеш только после успешной проверки

>>>if (Helper::validCSRFtoken($_GET['token']) and $this->loginAction->isLoggedIn()) {


>>> $student = $this->studentGateway->getStudentByСolumn('id', $_COOKIE['id']);


>>Вот здесь странно. Если у тебя есть сервис авторизации и ты через него проверяешь залогиненность, то разве не логично через него же и получать текущего пользователя? Почему у тебя проверка залогиненности в одном месте, а получение пользователя - в другом?


> Не знаю, мне казалось что если есть какая-то проверка на что-то, то результат должен быть true\false и не более.


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


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

Ну то есть если сформулировать по другому: работа с кукой 'id' должна быть собрана только в одном классе. Больше она не должна нигде использоваться.

И это должен быть сервис (хелпер), а не контроллер. А ты пытаешься использовать контроллер как будто это сервис.

>>$isEdit = $this->loginAction->isLoggedIn();


> Если результат этого метода будет сущность студента, то ничего страшного если переменная $isEdit будет содержать не булевое значение? Ведь на практике это можно применить точно так же.


Можно но тогда надо метод переименовать.

>>Более того, проверяешь авторизацию ты контроллером, а залогинаваешь пользователя в классе со странным названием StudentCookies.


> В каком именно месте это не правильно? В месте где я перезалогиниваю пользователя после редактирования?



1) код в контроллере не предназначен для повторного использования. для этого есть хелперы. Ты поместил код не туда (в контроллер вместо хелпера) и из-за этого вынужден использовать контроллер как хелпер.
2) каждый класс занимается своим делом. Работать с авторизационными куками должен один класс, который за это отвечает. У тебя работа с ними размазана по всей программе.

>>По моему это нелогично, что код, отвечающий за авторизацию разбросан по всему приложению. Мне кажется, логичнее сделать единый сервис авторизации, который умеет:


> Но ведь уже есть контроллер который занимается этим. Или ты имеешь ввиду переделать так чтобы контроллер пользовался вышеперечисленными методами сервиса?


Код в контроллере не стоит повторно использовать, например вызывать из других мест. Это не соответствует идее MVC. Контроллер это тот, кто управляет обработкой запроса от пользователя. Ты не должен создавать контроллер для каких-то других целей, например, чтобы узнать текущего залогиненного пользователя.

Надо было код отвечающий за авторизацию вынести в хелпер. ты вместо этого раскидал его по разным контроллерам.

>>Далее, нет логики в наследовании хелперов. Вот у тебя есть Helper и есть LoginHelper, который его наследует. Непонятно, а зачем? Там все равно почти все методы статические. Точнее, часть статическая, а часть нет, и почему, непонятно.


> А разве в одном классе все методы должны быть либо статические либо не статические? Почему?


Такого ограничения нет. Но должна быть какая-то логика по которой ты делаешь метод статическим или нет. Например, одинаково ли его поведение всегда или разное для разных объектов. Можно ли его вызывать не имея объекта или наоборот, он имеет смысл только если есть объект. У тебя там такой логики нету, слово static поставлено произвольно.

Пример. Допустим мы делаем класс для работы с файлом, имя файла передается в конструктор. Метод "удалить файл" очевидно должен быть нестатическим, так как он работает с объектом, представляющим файл. А вот метод "перевести размер из байтов в мегабайты" логично сделать статическим так как ему в принципе объект не нужен, он всегда одинаково работает, и может вообще использоваться не для файла, а для чего-то еще.

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


> Так токен нужен же для защиты от CSRF. Его удобно держать в студенте, потому что мы создаем куки на его основе.


Токен для защиты от CSRF не имеет никакого отношения к студенту. Потому что:

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

Ты точно читал урок про защиту от CSRF? Токен CSRF сохранять в базу не нужно. Одна копия токена хранится в куке, другая - в скрытом поле формы. База данных тут не нужна.
Ответы 7-20 июня #739 #779254
>>775011

Про ООП рассказывается в том числе в книгах которые есть в ОП посте (Зандстра, Шлосснейгл)

>>775013

Вот этот раздел официального мануала прочитать: http://php.net/manual/ru/book.mysqli.php

Наизусть запоминать ничего не надо, только почитать.
Тред закрыт #740 #779255
Этот тред закрыт. Не пишите здесь больше, все равно никто не прочтет.

Переходите в новый тред >>769611 (OP)

Если я вам не ответил, не проверил задачу, пропустил - напомните о себе в новом треде.
Обновить тред
Двач.hk не отвечает.
Вы видите копию треда, сохраненную 28 июня 2016 года.

Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
« /pr/В начало тредаВеб-версияНастройки
/a//b//mu//s//vg/Все доски