Это копия, сохраненная 5 ноября 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
Пожалуйста, пишите один большой пост вместо нескольких маленьких и не флудите не по теме.
Это тред для начинающих. Не написал за свою жизнь ни одной программы и имеешь тройку по математике? Ты наш человек.
Предыдущий тред был тут: >>1049651 (OP) . Еще предыдущие треды ищутся в гугле по словам "клуб изучающих php" или в архиваче.
Мейлач лежит? Есть запасной тред на доброчане: /s/res/23225.xhtml#i46467
Что самое главное для программиста? Умение аккуратно оформлять код (как, написано во втором посте).
Правила: ведем себя воспитанно, помогаем новичкам, читаем учебники, решаем задачки, постим ссылки на решения, ОП их проверяет и дает советы и замечания. ОП заходит редко, где-то раз в 2-3 дня, у него мало времени, не жди его, решай задачки дальше. ОП отвечает на все вопросы по его задачкам и учебнику, а вот насчет каких-то других вещей - только если останется время. Но в треде немало анонимных экспертов разного уровня, так что вряд ли вопрос останется без ответа.
С чего начать
У нас есть свои уроки по основам PHP, они собраны и выложены по адресу http://archive-ipq-co.narod.ru/ Это учебник для изучающих с нуля, то есть если ты вообще ничего не знаешь, то можно начать с него. Он простой и понятный. Там есть задачи, их нужно решать (чтобы стать программистом, надо писать код — иначе никак). Пости ссылки на решения в тред, мы их проверим, напишем замечания и дадим советы по улучшению. С другой стороны, если этот учебник тебе не нравится, можно читать любой другой. Или официальный мануал. Или все сразу.
Устанавливать пока что ничего не требуется, разве что редактор кода вроде Sublime Text 3, Notepad++, Visual Studio Code, Netbeans PHP или PhpStorm (с ним будет удобнее).
Если не знаешь как решать, запости код, напиши в каком месте остановился и попроси подсказку.
Ты прошел весь учебник? Молодец, но это были лишь основы языка 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/Symfony: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование https://gist.github.com/codedokode/a455bde7d0748c0a351a
- Если ты все решил, переходи к Symfony 3/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://github.com/codedokode/pasta/blob/master/db/databases.md
Что почитать
- Мануал по 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
Оформляй код аккуратно!!! — например пропусти через phpformatter.com . Также, если ты пользуешься IDE вроде PhpStorm, Netbeans, Eclipse, то в них эта опция встроена, подробнее: https://gist.github.com/codedokode/8759492
У ОПа нет аккаунтов и групп вконтакте, в фейсбуке, в твиттере, все "пхп-треды" там поддельные.
Платиновые вопросы
- Почему PHP? Потому что вакансий море, и учить легко.
- Сайт опять упал!!!!! — Не паникуй, а открой http://rghost.ru/6bfCY9lfl и получи личную немного устаревшую оффлайновую копию сайта (можно читать хоть на андроиде без интернета)
- Что надо знать чтобы найти работу - разработчику: PHP, SQL, HTML/CSS, JS, ООП, Git, композер, MVC, фреймворк. Верстальщику - HTML/CSS, JS, jQuery. У нас в треде были люди, которые практически с нуля учились и смогли найти работу.
- Что будут спрашивать на собеседовании если 0 опыта - гонять по теории, по официальному мануалу PHP, давать дурацкие задачки на переворачивание строк, гонять по SQL (транзакции, внешние ключи, напиши запрос), по JS (как сделать анимацию при нажатии кнопки), ну погугли, не ленись
- Можно подробнее про поиск работы, собеседования - нет, ОП писать не будет, но может кто из анонов захочет рассказать. Поищите тред перезвонивших, а также раздел /wrk/
- Сколько времени надо изучать все это? - все зависит от тебя, но не меньше 6-8 месяцев
- Нужен ли ООП, фреймворки, MVC, git, composer? — Да, однозначно. Посмотри любую вакансию.
Если тебе лень выравнивать код руками, закачай его на 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/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-1-basic-coding-standard.md
PSR-2: https://github.com/samdark/fig-standards-ru/blob/master/accepted/ru/PSR-2-coding-style-guide.md
Напомню, что надо проверить:
- >>1066512 26.09 https://github.com/vadimyen/students
- >>1066173 25.09 https://github.com/radiodog/studentlist
>Почкму ты думаешь проблема не в хостинге?
Хостинг заморский за кучу шекелей. Они клянуться что проблема не у них. На письма отвечают словами "баща данных" и прочими ругательствами
>>1067860
>почему бы не посмотреть логи ошибок веб-сервера
Maximum number of connection to host has been reached. Такие дела.
>Module 'PDO' already loaded in Unknown on line 0
И такое еще добро есть. Думаю-с что делать.
ОП, а задачу про студентов можно на фреймворке сделать? Или там весь смысл в "чистом php"?
ньюфаг
>Maximum number of connection to host has been reached
Это нагруженный проект?
Когда ты сам заходишь, получал ли 503?
Кинь ссылку, потестим. Если сикаешь, через pastebin закинь.
Если тебе самому выпадает через раз, попробуй
1) в корне html-страничку хелловорлд без PHP положи и раз 100 зайди.
2) Если будет опять 503, то, возможно:
а) >Боты-индексаторы, сканирующие ресурсы сайтов (поисковые системы, Sape и другие).
Nuff said. Настраивай robots.
б) >Использование элементов ресурсов или скриптов на чужих сайтах (ссылки на картинки, скрипты-информёры). Используйте антилич-модули/настройки.
Ну то есть очень много ссылаются на твои ресурсы напрямую извне и забивают процессорное время.
в) >На сайте установлен элемент, который периодически посылает на сервер AJAX-запросы (например, чат). Количество запросов зависит не только от числа посетителей, но и от их привычки открывать несколько вкладок в браузере.
Также все понятно.
г) >DDoS
Зависит от сайта, если он небольшой, кому он сдался дудосить?
>Maximum number of connection to host has been reached
Это нагруженный проект?
Когда ты сам заходишь, получал ли 503?
Кинь ссылку, потестим. Если сикаешь, через pastebin закинь.
Если тебе самому выпадает через раз, попробуй
1) в корне html-страничку хелловорлд без PHP положи и раз 100 зайди.
2) Если будет опять 503, то, возможно:
а) >Боты-индексаторы, сканирующие ресурсы сайтов (поисковые системы, Sape и другие).
Nuff said. Настраивай robots.
б) >Использование элементов ресурсов или скриптов на чужих сайтах (ссылки на картинки, скрипты-информёры). Используйте антилич-модули/настройки.
Ну то есть очень много ссылаются на твои ресурсы напрямую извне и забивают процессорное время.
в) >На сайте установлен элемент, который периодически посылает на сервер AJAX-запросы (например, чат). Количество запросов зависит не только от числа посетителей, но и от их привычки открывать несколько вкладок в браузере.
Также все понятно.
г) >DDoS
Зависит от сайта, если он небольшой, кому он сдался дудосить?
>Боты-индексаторы, сканирующие ресурсы сайтов (поисковые системы, Sape и другие).
This. Контрол панель без инглиша, онли на эльфийском. Пока нашел логи, то проклял свою работу, небо и аллаха. Пошел настраивать robots.
В любом случае, спасибо.
http://sandbox.onlinephpfunctions.com/code/b6bdc5bd19ad6af9c4c3ac0914c5236ecea111d7
Буду рад, если кто-то оценит.
Короче, нихрена пхп надо не первым языком учить, а после серьезной базы типа C/C++/Asm/Java
>Боты-индексаторы, сканирующие ресурсы сайтов (поисковые системы, Sape и другие).
Есть еще 1 вопрос на эту тему.
503 выдает 24/7, а googlebot не реагирует на delay. Единственный шанс снизить поток этого говна - Search Console, но я не могу подвердить правана сайт - он не отвечает.
Как поднять сайт максимально быстро 10 минут назад? бить по морде 403 всем подряд?
>The robots.txt file must be in the top-level directory of the host, accessible though the appropriate protocol and port number.
>accessible though the appropriate protocol and port number.
Еще за это поясни плз.
Вообще конечно смысл в том чтобы научиться основам работы с БД, формами, итд. Если ты это все понимаешь и мог бы легко сделать без фреймворка, то можно и на фреймворке. Если не понимаешь, то ты скорее всего и фреймворк ведь до конца не поймешь.
Если делать на фреймворке - то с модификациями. Ну например, авторизацию сделать как указано в задаче, а не как удобнее фреймворку.
Вчера, я не мог асинхронно выполнить цикл
>getMessages().then(function(messages) {
>
>for (var key in messages) {
>console.log("LOOP: " + messages[key].id);
>
>decrypt(messages[key].content).then(function(decrypted) {
>console.log("PROMISE: " + messages[key].id);
>});
>}
>
>});
>
>//LOOP: 1
>//LOOP: 2
>//PROMISE: 2;
>//PROMISE: 2;
Поискав в интернете я нашел похожую проблему https://stackoverflow.com/questions/40328932/javascript-es6-promise-for-loop , и из её решения я понял что нужно написать функцию, которая рекурсивно вызывает Обещание одно за другим, и написал обёртку
decryptMessages(messages) {
var that = this;
function loop(messages, i) {
if (i === undefined) {
i = 0;
}
var length = Object.keys(messages).length;
encrypted = messages.content;
// + check if privateKey added
decrypted = that.decrypt(encrypted);
decrypted.then(function(decrypted) {
messages.content = decrypted.data;
if (i < length - 1) {
loop(messages, i + 1);
}
});
}
loop(messages);
};
----
getMessages().then(function(messages) {
decryptMessages(messages);
// Object {0: Object {id: 1, content:"DECRYPTED"}, 1: Object {id:2, content:"ONE MORE DECRYPTED"}}
// Perfect
console.log(messages);
for (key in messages) {
console.log(messages[key].content; // -----BEGIN PGP MESSAGE...
}
});
Из примера выше, внутри цикла, свойства итерируемых объектов почему-то остаются нерасшифрованными, не смотря на то что в коллекции они расшифровались.
Ещё одно странное поведение, при обращении к объекту в коллекции по ключу (messages[0].content) значение тоже выводиться не расшифрованным, значит дело не цикле, а в функции которая преобразует эти объекты. Для меня странно, что моя функция decryptMessages() ничего не возвращает, но это, наверно, потому что передается ссылка на объект, и далее он преобразуется в функции. Я ошибся тут? Что ещё тут я делаю не правильно (потому что корень проблемы начался с того что нельзя выполнять асинхронный код в синхронных циклах)?
Вчера, я не мог асинхронно выполнить цикл
>getMessages().then(function(messages) {
>
>for (var key in messages) {
>console.log("LOOP: " + messages[key].id);
>
>decrypt(messages[key].content).then(function(decrypted) {
>console.log("PROMISE: " + messages[key].id);
>});
>}
>
>});
>
>//LOOP: 1
>//LOOP: 2
>//PROMISE: 2;
>//PROMISE: 2;
Поискав в интернете я нашел похожую проблему https://stackoverflow.com/questions/40328932/javascript-es6-promise-for-loop , и из её решения я понял что нужно написать функцию, которая рекурсивно вызывает Обещание одно за другим, и написал обёртку
decryptMessages(messages) {
var that = this;
function loop(messages, i) {
if (i === undefined) {
i = 0;
}
var length = Object.keys(messages).length;
encrypted = messages.content;
// + check if privateKey added
decrypted = that.decrypt(encrypted);
decrypted.then(function(decrypted) {
messages.content = decrypted.data;
if (i < length - 1) {
loop(messages, i + 1);
}
});
}
loop(messages);
};
----
getMessages().then(function(messages) {
decryptMessages(messages);
// Object {0: Object {id: 1, content:"DECRYPTED"}, 1: Object {id:2, content:"ONE MORE DECRYPTED"}}
// Perfect
console.log(messages);
for (key in messages) {
console.log(messages[key].content; // -----BEGIN PGP MESSAGE...
}
});
Из примера выше, внутри цикла, свойства итерируемых объектов почему-то остаются нерасшифрованными, не смотря на то что в коллекции они расшифровались.
Ещё одно странное поведение, при обращении к объекту в коллекции по ключу (messages[0].content) значение тоже выводиться не расшифрованным, значит дело не цикле, а в функции которая преобразует эти объекты. Для меня странно, что моя функция decryptMessages() ничего не возвращает, но это, наверно, потому что передается ссылка на объект, и далее он преобразуется в функции. Я ошибся тут? Что ещё тут я делаю не правильно (потому что корень проблемы начался с того что нельзя выполнять асинхронный код в синхронных циклах)?
Мне просто хочется плакать, я так хочу научится погромировать, но не могу блять, не понимаю я его. Я завидую людям которые умеют это делать. Говорят пхп освоит любой - хуйня это все ебаная, если ты тупой, а я тупой, то будь то пхп, питон, неважно, не освоить никак блять. Просто сижу нахуй и плачу от того, ебаное погромирование единственный шанс выбратся из говна ебаного, но почему я родился ТУПЫМ??????
Читаешь теорию - все понятно, после теории приступаешь к задаче и просто не одуупляешь что от тебя требуется! Как блять реализовывать и грамотно использовать изученный материал - у меня не хватает на это мозгов, я тупорылый даун.
А как люди генерируют идеи, а после все это реализуют на ЯП? Это просто за гранью воображения, я не понимаю этого, гении.
Как же меня демотивируют задачи которые я не могу решить, это какой-то психологический барьер или хуй знает. Например, читаю книгу и решаю параллельно задачи по книге и если какую либо из задач я не могу решить - злость, фрустрация, закрываю книгу и лежу неделями на диване хуесося себя.
Вот очередная моя попытка научится погромировать и она закончилась крахом:
Создайте две случайные даты (с помощью mt_rand()) и установив их в 2 объекта класса DateTime.
Найдите количество дней, часов, минут и секунд, на которое одна дата отличается от другой.
Сделайте разбиение на периоды с интервалом 1 день.
В цикле выведите все даты, которые содержатся между созданными в 1-м пункте, с интервалом из 3-го пункта.
Я не понимаю как можно генерировать случайную дату юзая мт_ранд, если мы генерим дату в формате d.m.Y H:i:s то на выходе получим 29.09.2017 16:55:16, точки двоеточия и прочее, а мт ранд работает с числами только. Разбивать регулярым вырежения или что, я понимаю что в этой ебучей задаче от меня требуют.
>Сделайте разбиение на периоды с интервалом 1 день.
>В цикле выведите все даты, которые содержатся между созданными в 1-м пункте, с интервалом из 3-го пункта.
Чего блять? Я вообще не одупляю условия эти, периоды, какие периоды, хуй твою мамть знает.
Сдался и смотрю курсы, потому что книги фрустратор пиздец.
я уебище тупое
Мне просто хочется плакать, я так хочу научится погромировать, но не могу блять, не понимаю я его. Я завидую людям которые умеют это делать. Говорят пхп освоит любой - хуйня это все ебаная, если ты тупой, а я тупой, то будь то пхп, питон, неважно, не освоить никак блять. Просто сижу нахуй и плачу от того, ебаное погромирование единственный шанс выбратся из говна ебаного, но почему я родился ТУПЫМ??????
Читаешь теорию - все понятно, после теории приступаешь к задаче и просто не одуупляешь что от тебя требуется! Как блять реализовывать и грамотно использовать изученный материал - у меня не хватает на это мозгов, я тупорылый даун.
А как люди генерируют идеи, а после все это реализуют на ЯП? Это просто за гранью воображения, я не понимаю этого, гении.
Как же меня демотивируют задачи которые я не могу решить, это какой-то психологический барьер или хуй знает. Например, читаю книгу и решаю параллельно задачи по книге и если какую либо из задач я не могу решить - злость, фрустрация, закрываю книгу и лежу неделями на диване хуесося себя.
Вот очередная моя попытка научится погромировать и она закончилась крахом:
Создайте две случайные даты (с помощью mt_rand()) и установив их в 2 объекта класса DateTime.
Найдите количество дней, часов, минут и секунд, на которое одна дата отличается от другой.
Сделайте разбиение на периоды с интервалом 1 день.
В цикле выведите все даты, которые содержатся между созданными в 1-м пункте, с интервалом из 3-го пункта.
Я не понимаю как можно генерировать случайную дату юзая мт_ранд, если мы генерим дату в формате d.m.Y H:i:s то на выходе получим 29.09.2017 16:55:16, точки двоеточия и прочее, а мт ранд работает с числами только. Разбивать регулярым вырежения или что, я понимаю что в этой ебучей задаче от меня требуют.
>Сделайте разбиение на периоды с интервалом 1 день.
>В цикле выведите все даты, которые содержатся между созданными в 1-м пункте, с интервалом из 3-го пункта.
Чего блять? Я вообще не одупляю условия эти, периоды, какие периоды, хуй твою мамть знает.
Сдался и смотрю курсы, потому что книги фрустратор пиздец.
я уебище тупое
>Советую автору померять время обработки запроса для разных страниц.
Нет доступа к верверу. Если буду мерять на локалке - поможет ли мне это?
>протокол http или https, соответствено порты 80 или 443.
Мне нада поднять сайт максимально быстро. Я вьебал
User-agent: *
Disallow: /
В роботс, т.к. он был пустым.
Боты игнорят это говно. Вопрос: говно с портами или ботам поебать?
Не умеешь срать, не мучай жопу. Займись чем нибудь другим, хуйли тебе этот кодинг так вперся?
Чем другим? Рисовать не люблю, верстать сайты не нравится, СЕО хуета, поступить в университет на какого-то ТИХНАРЯ? Так там тоже обосрусь из-за ебучих задачек, условий которые в голове не укладываются.
Я нищук с мухосранска 5к, кодинк это был мой ласт шанс стать человеком и перебратся в более крупный город, получать норм даллары и прочее.
Мне нравится стезя погромирования, мне интересно изучать это, но блять у меня нет мозгов чтобы реализовать изученное, бесит нахуй.
У тебя хуевое отношение к задачам. Если ты встречаешь задачу которую не можешь сходу решить: ЭТО ХОРОШО. Это значит, что ты научишься чему то НОВОМУ. В твоем случае, начни с узнавания что такое: unix timestamp, как это получить в PHP, как это конвертировать в понятный формат даты.
Твоя проблема в том, что ты не изучаешь как следует теорию, и берешься за те задачи, на которые у тебя не хватает знаний. Может учебник, по которому ты учишься, плохо объясняет, а может ты просто пропускаешь какие-то уроки и берешься сразу за сложное.
Ну вот например, смотри, у тебя задача на объект DateTime. А ты вообще изучал этот класс, знаешь, какие у него есть методы? Начни с изучения мануала и прочитай весь раздел про дату/время: http://php.net/manual/ru/book.datetime.php
Наизусть учить не надо, но прочесть надо. Раз учебник, по которому ты учишься, ничего подробно не объясняет, придется читать мануал.
Кто тебе сказал, что дату можно задавать только в формате дней/месяцев/лет? Это не так.
Также, можешь прочесть мой урок про дату/время, вдруг что полезное найдется: https://github.com/codedokode/pasta/blob/master/php/datetime.md
>Я не понимаю как можно генерировать случайную дату юзая мт_ранд, если мы генерим дату в формате d.m.Y H:i:s то на выходе получим 29.09.2017 16:55:16, точки двоеточия и прочее, а мт ранд работает с числами только. Разбивать регулярым вырежения или что, я понимаю что в этой ебучей задаче от меня требуют.
Можно преобразовать число в дату с помощью функции date() и получившуюся строку передать в класс DateTime.
https://secure.php.net/manual/ru/function.date.php
https://secure.php.net/manual/ru/datetime.construct.php
$format = ...;
$random = mt_rand();
$date = date($format, $random)
$datetime = new DateTime($date);
$datetime->format($format);
Если в книге нету такой или подобной подсказки, то наверно дело в ней.
>Сделайте разбиение на периоды с интервалом 1 день.
Здесь, наверно, имелось ввиду разделение полученной даты на дни. Т.е. если получившиеся значение было бы, к примеру, 2 дня и 12 часов, то получился бы массив состоящий из 0 => 24:00, 1 => 24:00, 2 => 12:00;
Ну вообще тут действительно не так очевидно.
P.S.
В шапке треда, кстати, есть задачи на любой уровень сложности.
>Это костыль, таймстамп можно напрямую передать в DateTime.
Значит можно обойтись без функции date(). В мануале просто написано что конструктор DateTime принимает именно строку.
https://secure.php.net/manual/ru/datetime.construct.php
public DateTime::__construct ([ string $time = "now" [, DateTimeZone $timezone = NULL ]] )
Во-первых, там есть метод для задания таймстампа. Во-вторых, там есть еще createFromFormat которая может принимать таймстамп.
https://ideone.com/EbjMYs
Я вбил данные из старой задачи про айфон. Там еще ответ за спойлером был, я его решил и сверить. И получается он разный.
Банки я пока что закомментил.
И еще есть вопросы:
1) Правильно ли я использую команду return ?
2) Можно ли было в данном случае использовать эту команду как-то по-другому, но тоже правильно? Спасибо.
Переделал. Теперь вроде все совпадает. Но вопросы по return остались. Прошу проверить, правильно ли я сделал. Пишу ли я как говнокодер? Если да, то как и где надо было правильно писать? Спасибо
Например - Жмем кнопку добавить новость, загружаем сначала к ней картинки (AJAX), далее пишем сам текст и только после этого жмем кнопку сохранить новость.
Как лучше загружать связанные файлы вообще до того как родитель существует?
>Я вбил данные из старой задачи про айфон. Там еще ответ за спойлером был, я его решил и сверить. И получается он разный.
У меня вывелось столько же сколько и под спойлером.
https://ideone.com/EbjMYs
>stdout
>61270.186744521
>1) Правильно ли я использую команду return ?
>2) Можно ли было в данном случае использовать эту команду как-то по-другому, но тоже правильно? Спасибо.
Оператор return нужен чтобы функция завершила своё выполнение и вернула какой либо результат. Как его использовать зависит от тебя.
https://secure.php.net/manual/ru/functions.returning-values.php
>>1068324
Небольшая придирка к оформлению кода - где-то есть лишнее пробелы и переводы строки, где-то их нет. Аккуратно оформленный код проще читать. Как правильно оформлять код можно почитать здесь >>1067945 В частности, советую почитать стандарты PSR-1 и PSR-2.
>>1068325
https://ideone.com/2EheEI
Выражения вида $a = $a + $b можно писать проще $a += $b.
К сожалению комментарий об этом на английском:
https://php.net/manual/ru/language.operators.assignment.php#40084
Вроде правильно, но лучше спросить у codedecode разрешает ли он "имитировать" количество месяцев в цикле, а не считать их самому.
https://3v4l.org/9rcVt
После отправки поста обновить записи о картинках к какому посту они привязаны.
Спасибо огромное!
Тут есть разные варианты. Обычно для учета делают таблицу картинок, и каждой картинке на диске соответствует запись в ней. В таком случае можно предусмотреть в ней поле, обозначающее что это "временная" картинка, которая позже будет прикреплена куда-то.
При загрузке картинки она сохраняется на сервер как "временная", а на клиент возвращается ее id. При отправке поста вместе с ним передаются id картинок, и они привязываются к посту после создания. Важно не забыть про безопасность и разрешить привязывать только картинки загруженные тем же самым пользователем.
При таком подходе, возможен вариант, что картинки были загружены, но пост так и не был создан. Понадобится скрипт-сборщик мусора, ищущий временные картинки старше определенной даты и удаляющий их с сервера.
Не забывай, что сначала мы сохраняем картинку на диск, а потом вставляем в таблицу. И в обратном порядке при удалении. Это гарантирует, что не будет записей в БД, которым не соответствуют файлы.
Создавать пост и привязывать к нему картинки лучше в рамках транзакции. Чтобы при падении скрипта в процессе в базе не оставалось неполных данных.
Также, тебе понадобится еще один скрипт, периодически сверяющий файлы на диске с БД и удаляющий или перемещающий в корзину файлы, для которых нет записи в БД.
Есть конечно и другие варианты - например, создавать "временную" папку и сохранять картинки туда. Но вариант с таблицей мне кажется более удобным.
Помни, что скрипт (да и сервер целиком) может упасть в любой момент и продумывай логику так, чтобы минимизировать урон. Например, использование транзакций гарантирует, что в БД не будет "не до конца" вставленных данных. Это немного усложняет код, но экономит тебе много времени на исправление ошибок в БД.
У тебя есть массив maxTime (странное название), который хранит минимальное время, за которое можно добраться от старта до какой-то точки. Можно сделать еще массив prevPoint, который хранит для каждой точки, откуда ты в нее пришел. По этому массиву потом можно будет восстановить путь.
> $numberOfPaths
Название неудачное, лучше назвать например pointIds
> for ($i = 0; $i < count($numberOfPaths); $i++){
Посмотри функции array_fill и array_fill_keys.
Вообще, массив communications можно было и не делать, эти данные уже есть в массиве paths.
> for ($i = 0; $i < count($connectedStops); $i++){
Для перебора массива лучше подойдет foreach
> //ПОСТРОЕНИЕ ТАБЛИЦЫ ДОРОГ
Что-то выглядит сложно и запутанно. Это точно нужно?
> $maxTime[$i] = 1000000;
Если что, в PHP есть константа INF, а также функция is_finite():
http://php.net/manual/ru/math.constants.php
http://php.net/manual/ru/function.is-infinite.php
Количество месяцев - это защита от вечного зацикливания. Можно сделать и по-другому, сделав например условие:
продолжать, пока (долг > 0) {
...
если (новый долг > предыдущего долга) {
получается вечный цикл, выходим;
}
}
Другой вариант - делать остановку после 200 лет например.
Желательно избегать циклов, где есть возможность зацикливания. Указание заведомо большего числа месяцев позволяет это сделать, хотя может вместо цифры 20 стоило бы как-то делать грубую оценку исходя из суммы долга и месячной платы, либо исходя из оценки времени жизни заемщика.
> Как сделать так, чтобы этот make_huynya не генерировал новую страницу, а дописывал содержимое к той, на которой форма?
Простая отправка формы всегда заставляет браузер рендерить ответ.
Поэтому есть ajax. Что бы вкатится вполне пойдет старый добрый jquey.
>т.е. без javascript я эту задачу вообще никак не решу?
Да. Без js не получится.
Но там на самом деле оч мало то нужно.
Лол, я JS знаю лучше чем php, просто удмал, что может как-то можно не плодя сущности и не добавляя js К существующей поделке
Кратко: смотри документацию.
Если ее нет, то пробуй без токена и может в ошибке, что вернет сервер, будет ответ.
А так, и в хидерах бывает, и в теле. У многих можно и так и так.
Но в теле, при гет запросе, не советуется. Т.к. при хттпс запросе, строка с адресом не кодируется.
> я JS знаю лучше чем php, просто удмал, что может как-то можно не плодя сущности и не добавляя js К существующей поделке
Ты сам подумай. Браузер должен знать, как твой ответ распарсить, чего там ковырнуть, как это отрендерить и куда это потом запихнуть.
Слушай ну если это форма ты можешь просто проверять наличие ПОСТА и инклудить ее.
Спасибо за ответы парни, я остыл и решил заново трайнуть решить задачу.
https://ideone.com/XyB3i1
Написал функцую которая генерирует рандомную дату, потому что блять я ума не приложу как это по другому сделать.
Если кто-то знает каким образом по другому генерить рандом дату - отпишитесь плиз.
я не выебываюсь, а просто нарабатываю привычку писать в стиле ооп
тупое уебище
Алсо, если часто обновлять страницу, то получим вместо рандом даты нужного диапазона мы получим дату 19700101, с чем может быть связана проблема? Установлен последний апач.
Самый изич, это сгенерить юникс теймстамп и потом спарсить в дейт тайм.
Правда, эта рандом дата никогда не будет ранее 1970 года.
Но твоя функция тоже норм. Единственное, сделай ее сразу конструктором твоего класса.
Ты точки забыл. Которые разделители в рандомной дате.
но ведь она будет отрисовываться заново
А куда делся DateTime? Ты же вроде хотел его использовать?
Если честно, то пока очень слабо. Во-первых, для сбора даты из кусочков не не нужно использовать strtotime, есть mktime. В моем уроке, на который я давал ссылку, эта функция упомянута, и в мануале тоже.
Во-вторых, ты передаешь дату в виде строки YYYYmmdd. Зачем? С этой строкой не будет работать ни одна функция. Я же писал в своем уроке, что время представляется либо в виде timestamp, либо в виде DateTime. С этими значениями можно делать что угодно и преобразовывать их потом в любой формат.
Наконец, с точки зрения ООП выглядит тоже довольно бессмысленно. Вот что у тебя представляет объект класса RandomDate? Непонятно. Непонятно, зачем у тебя свойство date, которое никак вообще не используется.
Если ты хотел сделать объект, представляющий дату, то надо было либо хранить внутри него timestamp, либо по отдельности год/месяц/день. Хотя не очень понятно зачем это делать, когда есть DateTime.
Я бы тебе советовал все же прочесть мой урок https://github.com/codedokode/pasta/blob/master/php/datetime.md . Насчет ООП, я бы советовал почитать учебник из ОП поста, главу про ООП, и попробовать решить там задачу про Вектор. Тут у тебя ООП просто за уши притянут, ты вроде как используешь класс, но смысла в нем никакого нет, проще было сделать просто функцию либо статический метод в классе без свойств.
С тем, что ты генерируешь неправильную дату (вроде 2017131) которая не парсится. Прочти уже мануал по strtotime. Прочти описание поддерживаемых форматов даты. Никто за тебя это делать не будет.
Вообще, почитай про алгоритм работы с формами https://github.com/codedokode/pasta/blob/master/forms.md
Что касается отделения логики от вывода, это делается за счет шаблонов: http://web.archive.org/web/20161119062218/http://www.phpinfo.su/articles/practice/shablony_v_php.html
Читал твой урок, я тупой поэтому наговнокодил только вот это, днем буду переделывать https://ideone.com/ItLFPe
Завтра продолжу изучать, спокойной ночи всем итт.
1. Чем в PDO bindValue и bindParam отличаются? Несколько раз перечитывал описание но так и не понял.
2. Нормально ли в конструкторе объекта дохуя кода писать? У меня такая привычка, я через него кучу всякой хуйни объявляю и даже некоторые вычисления, но подозреваю что это не очень хорошо.
3. Не очень понимаю что относить к моделям в MVC. Нет, ну понятно что работу с БД, сущности там. А всякие вещи типа валидации и пагинации - это тоже модели?
3. Ну вообще да, модели, а контроллеры для них выступают в роли клиентского кода (вызывают методы этих моделей)
Т.е. пагинатор можно пихать в пространство имен к моделям? У меня такие сервисы пока просто App
Не надо специально делать отдельное пространство имен для моделей. Лучше делать пространство имен для классов работы с Бд, для сервисов, для валидаторов, для вспомогательных классов итд.
Насчет пагинатора - трудно сказать, скорее это вспомогательный класс.
Спасибо. Собственно так и сделал, как самый простой вариант.
Только алгоритм сохранения такой:
- открыть транзакцию
- сохранить запись в бд
- если сохранилась сохранить файл
- если файл сохранился комит
- во всех остальных случая ролбэк
Таким образом насколько я понимаю я не получу загруженных файлов без записей в бд.
Получишь. Если скрипт упадет после сохранения файла, но до коммита. Но это не так страшно (по сути просто лишний файл), хуже если запись в БД есть, а файла на диске нет.
Понял. Спасибо еще раз.
Есть Слим 3 и есть Твиг в качестве шаблонизатора. Есть проект файлообменника и короче после загрузки файла, я редиректю пользователя на другой контроллер и есть ссылочка вот такого вида которую успешно обрабатывает контроллер /download/id/cocy-xyu.jpg я получаю данные из базы данных в объект и вот как теперь мне передать эти данные в странчку download.twig.
$this->view->render($response,'home.twig'); вот так я попадаю на главную странчику.
а вот так мне предглагает мануал
echo $this->view->render('download.twig', array('file' => $file));
Как делать я чего-то не ябу.
У меня отработал скрипт, в нем я получил данные которые нужны для того, чтобы сгенерировать страницу, как мне ее отобразить, ну не echo же. Могу ли я это сделать без шаблонизатора? Потому что не хочется его прикручивать ради двухстраничного тестового задания
...вариант подключения шаблона(в котором тоже php) через require подойдет?
Разобрался вроде
return $this->view->render($response,'download.twig', array('file' => $file));
Логировать, слать ошибку в телегу, юзеру показывать 500. Чего ты с ними еще сможешь сделать?
Ну вот да, а как это грамотно организовать? В set_exception_handler, ну и во всех имеющихся catch'ах просто вставить header('HTTP/1.1 500 Internal Server Error'); die()? Телега – это телеграм?
Div - это div, его нельзя сделать ссылкой, только средствами JS. Но возможно тебе подойдет обычный тег "a" с display:block. Возможно ошибаюсь, ибо последние 3 года занимаюсь только backend, может что-то поменялось в мире html
блин, да я обернул div в а, вот и все.... ты не понял вопроса, но я его уже решил. Зато появился другой вопрос.
Логика работы моей поделки: на главной странице форма, куда вбивается поисковая строка, результат обрабатывается php-скриптом и получается некий результат. На основе этого результата выдаем html страницу. На этой странице есть ссылка(пока одна, но потом будет много), она работает- направляет на правильную страницу, НО... на этой странице почему-то не работает php, вот просто игнорируется все, что внутри <?php ?>. Что за херня?
Можно ещё за место <div> использовать <label> с display:block и заключить его в ссылку.
На мой первый вопрос забей
1. Ну написано же русским языком в оффициальном php.net
>В отличие от PDOStatement::bindValue(), переменная привязывается по ссылке, и ее значение будет вычисляться во время вызова PDOStatement::execute().
Значит, в случае с bindValue ты привязываешь значение переменной, а bindParam привязываешь саму переменную. Например, у тебя есть подготовленное "pdo-выражение" bindParam, где ты привязал переменную $megaHash, а этот мега-хеш вычислять 10 раз потом и сделать $stmt->execute(). И у тебя привяжется последнее значение этого мега-хеша
2. Это плохо. В идеальном случае ты через конструктор должен передать только зависимости для твоего объекта.
3. Вот то, про что ты пишешь - так сделано вроде в Yii2. Но лучше, чтобы модель не была слишком толстой. В моем понимании модель - это бизнес-логика и все. Форма лежит рядом, но отдельно. Так как у тебя может быть одна модель User и куча форм с валидацией к ней: Registration, ChangePassword, etc.
Выглядит так, как будто ты хочешь чтобы php работал у тебя в браузере, такому не бывать. PHP выполняется на стороне веб-сервера, браузер лишь выполняет отрисовку результата работы веб-сервера + php
Блядь... и действительно
Да, нужно делать через require\require_once.
Переход через header нужен если нужно куда-то перенаправить. Например, на заглавное странице есть форма регистрации с action="register.php", в register.php мы обрабатываем данные и если всё ок, то куда-нибудь перенаправляем например на заглавную страницу.
>>1068812
>Как мне в href запихать переменную?
href="<?= $variable ?>"
Последний вопрос и я перестану трахать мозг:
вот пользователь ввел данные в форму и нажал кнопку отправки, включается скрипт, он вычисляет нужное и делает require_once('aaa.html')- внутри этого html я искпользую переменные из моего скрипта. Как мне сделать так, чтобы я по-прежнему мог внутри aaa.html использовать переменные из скрипта, но при этом именно перенаправлять пользователя на готовый aaa.html. Ведь при текущей реализации, после нажатия кнопки в форме я вижу в адресной строке /обработчик формы.php
>href="<?= $variable ?>"
Я думал об этом, но у меня там массив, который может быть недетской длины. Некрасиво как-то
Норм. Как решишь эту же задачу, если по условию будет, что на вход подается только однобайтная строка, а не utf8?
>>href="<?= $variable ?>"
>Я думал об этом, но у меня там массив, который может быть недетской длины. Некрасиво как-то
Тогда нужно использовать цикл.
Для шаблонов придумали альтернативный синтаксис:
https://php.net/manual/ru/control-structures.alternative-syntax.php
Я хочу, чтобы у пользователя в адресной строке всегда было/что_то_там.html Для этого, мне нужно использовать header(). Но мне на той странице, куда я перехожу, нужны переменные из скрипта. Есть ли решения,кроме передачи их параметрами запроса типа ?a=1&b=2 ???
Тебе нужно что-то вроде Rewrite Rules, чтобы, когда пользователь переходит на page.html, на самом деле выполнялся скрипт page.php
Почитай про Rewrite Rules в nginx, apache, lighttpd или что ты там используешь
Да даже к php -S, вроде, можно написать маршрутизацию как тебе надо
Гугли htaccess и RewriteEngine
Почитаю на досуге, мысль вроде ясна.
А вообще, когда я нажимаю на кнопку формы, получаю страницу результата, но вижу в адресной строке /обработчик_формы.php это вообще плохо?
для поделки и тестового задания - нет, для крупного интернет-магазина не очень.
Так. А если зайти с другой стороны. Сейчас я в php обработчике формы взаимодействую со сторонним api которое мне возвращает нужные данные, я это делаю с помощью file_get_contents.
Могу ли я делать то же самое на стороне клиента с помощью JavaScript? Если да, могу ли я потом передать результаты из скрипта другой html странице?
>Могу ли я делать то же самое на стороне клиента с помощью JavaScript?
Скорее всего нет, почитай про Access-Control-Allow-Origin
На досуге почитаю. Можешь в двух словах объяснить что помешает мне это сделать?
типа нельзя делать кроссдоменные запросы?
Смотри, мне дали такое задание:
попробуйте на любом бесплатном хостинге сделать страницу, которая будет позволять любому пользователю ввести адрес или кадастровый номер объекта недвижимости, а в ответ на введенные данные получить информацию по этому объекту. Далее выбрав объект (если их несколько) пройти процедуру оплаты. Саму интеграцию платежного шлюза делать не надо, это потребует времени.
Интеграцию получения сведений об объектах недвижимости необходимо производить через API проекта apirosreestr.ru
ТО есть стек технологий и технические пожелания по реализации не указаны. Делать это на php- норм, или изначально плохая идея?
... я не очень понимаю что они подразумевают под процедурой оплаты. Первая мысль- просто сделать страницу вида "вот тут мы будем платить за объект такой-то"
А если бы это был крупный интернет магазин. И нужно из php обработчика формы передать результат(большой массив) html странице. Неужели передаче через ?a=12b=22c=15... ,которые маячат в адресной строке, это нормально?
php, nodejs - проще простого. Но судя по твоим вопросам в треде, тобi пизда, ибо как я вижу наипростейший алгоритм
1) юзер на index.html вводит номер и нажимает поиск
2) аякс запрос на твой скрипт api.php, откуда возвращается список и рендерится на странице средствами js
3) юзер переходит по ссылке на /pay.php?objectId=7 и показывается простая форма оплаты с вводом номера Карты, имени с кода. И кнопка оплатить
4) по нажатию на кнопку форма ведёт на result.php?objectId=7, где ты выводишь инфу по объекту
Вот это самое простое решение
Мне было бы даже комфортнее на node.js, но
1) Хочется немного пощупать php
2) Думаю, что могут быть проблемы с поиском бесплатного хостинга поддерживающего ноду
Аякс запросы на php я не знал что так можно, лол. Идея хорошая, попробую реализовать
Из php в html ничего не передаётся. Считай, что php - это шаблонизатор, который может динамически в зависимости от запроса строить html страничку. Большие магазины сидят на jsonrpc, protobuff и не гоняют статику просто так.
У тебя аякс запрос уходит со странички в браузере на твой php скрипт. Он не в php.
хочу помогать ньюфажикам, но чёт пиздец, видимо поясняю как-то плохо или невнятно. Извините если что
У меня сейчас есть работоспособное решение такое:
У формы action='api.php' и там в конце этого скрипта require_one('results.html')
На странице results у найденных объектов ссылки вида /pay.php?тут данные описывающие объект которая ведет на страницу оплаты
Сюда залил https://afradkova.000webhostapp.com/
Оно пока совсем страшное, с каким-то предупреждениями(потом разберусь). Но свою задачу выполняет. Причешу и сделаю красиво завтра.
Только вбивай адрес не как можно более конкретный вплоть до номера дома, а то выдаст тебе 100500 объектов
Я могу сделать чтоюы по нажатию на кнопку и мой php скрипт запускался и параллельно с ним запускался js скрипт, который бы выводил вращающийся спиннер с надписью "ждем результатов"?
Почему он мне 5000 выдаёт? Я не понимаю. Я же написал как ему считать $paymentTotal, а он к ему только месячный взнос прибавляет. Он поехавший? Что он пишет?
?
>return возвращает управление программой модулю, из которого была вызвана функция.
Это почти как break работает?
>Значения возвращаются при помощи необязательного оператора возврата.
Что? Куда они возвращаются?
мне кидали хороший пример по return https://2ch.hk/pr/res/1049651.html#1067893 (М) и это https://ideone.com/0dAmrv
Во-первых, вот мой пост про return, прочти >>1067893
Во-вторых, функция это подпрограмма (вынесенная отдельно часть большой программы). Она не видит созданные снаружи переменные, у нее свой набор переменных, который изначально пуст. И вызов функции похож на вызов отдельной программы:
// определяем функцию, в этот момент просто создается функция, но ее код пока не запускается
function someFunc($a, $b)
{
// создаем временную переменную $c, которая
// существует только до момента выхода из функции
$c = $a + $b;
return $c;
}
// вызываем ее, PHP начинает выполнять функцию, а ее результат после выхода сохранит в $x
$x = someFunc(3, 4);
// а можно сразу вывести результат, без переменной
echo someFunc(3, 4); // выведет 7
Функция не видит переменные, созданные снаружи ее (это сделано специально, и это хорошо, иначе в большой программе был бы риск, что функция затрет какую-то созданную снаружи переменную). С помощью аргументов в скобках мы передаем значения ($a = 3, $b = 4) внутрь функции. Она выполняется. И затем команда return выходит из функции и возвращает результат, который сохраняется в переменную $x (в данном случае 7).
> Это почти как break работает?
Да, break выходит из цикла, return из функции. Но на этом аналогия заканчивается.
> Что? Куда они возвращаются?
В место, откуда была вызвана функция. В примере выше return вернет результат, который будет сохранен в переменную $x. Функция может, если хочет, вернуть одно какое-то значение как результат своей работы (если в функции нет команды return, то считается что она вернула значение null). А тот, кто вызвал функцию, может, если хочет, сохранить это значение, или сделать что-то еще с ним. А может ничего не делать.
Во-первых, вот мой пост про return, прочти >>1067893
Во-вторых, функция это подпрограмма (вынесенная отдельно часть большой программы). Она не видит созданные снаружи переменные, у нее свой набор переменных, который изначально пуст. И вызов функции похож на вызов отдельной программы:
// определяем функцию, в этот момент просто создается функция, но ее код пока не запускается
function someFunc($a, $b)
{
// создаем временную переменную $c, которая
// существует только до момента выхода из функции
$c = $a + $b;
return $c;
}
// вызываем ее, PHP начинает выполнять функцию, а ее результат после выхода сохранит в $x
$x = someFunc(3, 4);
// а можно сразу вывести результат, без переменной
echo someFunc(3, 4); // выведет 7
Функция не видит переменные, созданные снаружи ее (это сделано специально, и это хорошо, иначе в большой программе был бы риск, что функция затрет какую-то созданную снаружи переменную). С помощью аргументов в скобках мы передаем значения ($a = 3, $b = 4) внутрь функции. Она выполняется. И затем команда return выходит из функции и возвращает результат, который сохраняется в переменную $x (в данном случае 7).
> Это почти как break работает?
Да, break выходит из цикла, return из функции. Но на этом аналогия заканчивается.
> Что? Куда они возвращаются?
В место, откуда была вызвана функция. В примере выше return вернет результат, который будет сохранен в переменную $x. Функция может, если хочет, вернуть одно какое-то значение как результат своей работы (если в функции нет команды return, то считается что она вернула значение null). А тот, кто вызвал функцию, может, если хочет, сохранить это значение, или сделать что-то еще с ним. А может ничего не делать.
Во-первых, у тебя в начале стоит странная команда
$paymentTotal;
Во-вторых, попробуй внутри цикла поставить echo, которое будет писать какой это шаг по счету и чему равны значения разных переменных. За счет этого ты сможешь увидеть, что происходит внутри цикла.
>>1068989
Да, так нужно делать, чтобы пользователь видел мгновенно реакцию на нажатие. Интерфейс должен быть отзывчивым, то есть сразу реагировать на действия пользователя.
Проще всего это сделать, добавив в DOM анимированную картинку при нажатии кнопки. Не забудь также заблокировать кнопку до окончания запроса.
Почитай мой урок про использование аякс: https://github.com/codedokode/pasta/blob/master/js/ajax.md и делай, как там описано.
Вот кстати разработчики Медузы моим советам не следуют, и там в мобильной версии при медленном интернете при нажатии на статью просто ничего не происходит, а через несколько секунд она внезапно выскакивает на экран. Ай-я-яй, реакта и API там накрутили, а про такие простые вещи забывают.
>>1068977
Нужно сделать защиту от выдачи 100500 объектов.
А в чем проблема? Если это поиск по разные критериям, то это даже очень хорошо, так как при обновлении страницы критерии поиска не потеряются. А также, ссылку можно сохранить в закладки, переслать - и она откроется в том же виде.
Ну или мы о разных вещах думаем.
>>1068916
Так спроси.
>>1068914
Задание надо делать самому.
>>1068901
Если владельцы этого API разрешают кроссдоменные запросы, читай документацию или смотри заголовки.
>>1068895
Нет
>>1068875
Вообще, тебе надо изучать теорию .Есть 2 метода - GET и POST для отправки форм, у них свои недостатки и достоинства, читай урок https://github.com/codedokode/pasta/blob/master/forms.md
>>1068873
Ты про htmlspecialchars забыл. Обязательно используй его в примерах. А то будет XSS уязвимость (и что характерно, многие плохие учебники по PHP точно также про него либо не пишут либо упоминают вскользь).
А в чем проблема? Если это поиск по разные критериям, то это даже очень хорошо, так как при обновлении страницы критерии поиска не потеряются. А также, ссылку можно сохранить в закладки, переслать - и она откроется в том же виде.
Ну или мы о разных вещах думаем.
>>1068916
Так спроси.
>>1068914
Задание надо делать самому.
>>1068901
Если владельцы этого API разрешают кроссдоменные запросы, читай документацию или смотри заголовки.
>>1068895
Нет
>>1068875
Вообще, тебе надо изучать теорию .Есть 2 метода - GET и POST для отправки форм, у них свои недостатки и достоинства, читай урок https://github.com/codedokode/pasta/blob/master/forms.md
>>1068873
Ты про htmlspecialchars забыл. Обязательно используй его в примерах. А то будет XSS уязвимость (и что характерно, многие плохие учебники по PHP точно также про него либо не пишут либо упоминают вскользь).
bindValue передает значение для плейсхолдера. bindParam делает двухстороннюю привязку плейсхолдера к переменной по ссылке так, что база может в нее обратно что-то записать. Это нужно только при работе с хранимыми процедурами, и я не уверен, поддерживается ли это в MySQL. Ну то есть скорее всего тебе это не понадобится.
>>1068859
Расширение наверно надо сделать php, а не html.
>>1068812
div не может быть ссылкой, надо использовать тег a. Тебе стоило бы изучить HTML/CSS получше.
>>1068712
- логгировать в лог
- показывать страницу с простыми понятными словами для пользователя
- отдавать страницу с кодом 5xx
- при желании делать еще что-то
Описано у меня в уроке https://github.com/codedokode/pasta/blob/master/php/exceptions.md
Увы, по умолчанию PHP это не умеет, и это ошибка имхо. надо будет предложить им поменять поведение по умолчанию (хотя они вряд ли согласятся).
> 2. Нормально ли в конструкторе объекта дохуя кода писать? У меня такая привычка, я через него кучу всякой хуйни объявляю и даже некоторые вычисления, но подозреваю что это не очень хорошо.
В принципе запрета нет, но интуиция подсказывает мне, что скорее всего тут что-то не так. Почему у тебя объект выполняет много действий еще на этапе создания, хотя ты его пока не просил ничего делать?
> 3. Не очень понимаю что относить к моделям в MVC. Нет, ну понятно что работу с БД, сущности там. А всякие вещи типа валидации и пагинации - это тоже модели?
Вообще, ты можешь думать о модели как о ядре приложения БЕЗ интерфейса. Для веб-приложения интерфейс - это HTTP. Когда пользователь жмет ссылку или отправляет форму, тебе приходит HTTP запрос. Ты его обрабатываешь, и выдаешь в ответ страничку или редирект, то есть HTTP ответ.
Так вот, интерфейс, работа с запросами и выдача ответов - это не задача модели. Это задача контроллера и вью. А модель отвечает за "бизнес-логику". Ну то есть если у тебя сайт объявлений, то модель будет отвечать за поиск объявлений, добавление, удаление, итд. Но все это без интерфейса, через вызовы каких-то функций. Проще говоря, ты можешь выкинуть из приложения контроллеры и вью, оставить только модель - и по-прежнему можешь получить или изменить любую информацию, вызывая функции модели напрямую из кода.
То есть модель и есть само приложение, а контроллеры/вью, это так, обертка, чтобы человек мог взаимодействовать с моделью.
Также, хочу еще дополнить. Правильное разделение на MVC может увеличить объем работы и объем кода. Но без этого разделения скорее всего получится лапша (такое часто встречается, когда по сути приложение состоит из одних контроллеров, в которых и пишется весь код), с которой неудобно будет работать.
То есть мы это MVC используем не из фанатизма и не чтобы побольше денег взять с заказчика, а чтобы:
- изменение верстки страницы не требовало перелопатить половину кода
- изменение логики проверки каких-то данных не требовало перелопатить половину кода
- чтобы получить какие-то данные, нам достаточно было вызвать одну функцию из модели, и не надо было копипастить блок кода для получения этих данных
- и так далее
То есть это применение принципа "разделяй на слабосвязанные части", с помощью которого мы пытаемся снизить сложность кода в большом приложении. MVC работает, потому его используют.
Я могу сказать, что разделение может идти и дальше. Ну например, если у нас сложная верстка и какой-то блок есть на нескольких страницах, мы вполне можем его вынести отдельно, сделав для него свою модельку и свое маленькое view (обычно это вместе называют виджет). Чтобы не копипастить код получения данных для этого блока в нескольких контроллерах.
Я видел приложения без MVC, ну например, там регистрация пользователя дублировалась в нескольких контроллерах (так как было несколько мест, где это можно сделать). Если ты хочешь поменять логику проверки email, например, то надо было менять код в нескольких местах, и тестировать каждое по отдельности. Очень неудобно.
Проблема такая: я решил поставить скрипт на кнопку формы, для мгновенного отклика на нажатие, чтобы юзер понимал, нажалось ли, сработало ли и тп. Делают тег SCRIPT, туда функцию, в onclick ее указываю и.... ничего, не срабатывает. А если в onclick напрямую что-то указываю типа alert('bla-bla-bla'), то срабатывает.
И еще... сейчас подробнее опишу: форма, а кнопке отправки стоит JS обработчик, который делает AJAX запрос на PHP скрипт.(сам запрос выполняется, проверено) 2 проблемы:
1. Даже если в PHP скрипте нет ничего такого, что должно выводить что-то на экран, все равно появляется пустое окошко после нажатия кнопки.
2. Как отдать переменную $result как результат Ajax запроса?
Так... проблема вот в чем. У меня запрос отправляется и данные получаются обратно, в xhr.responseText все нужное я получаю. НО у меня почему-то после выполнения php страница перезагружается, как поправить?
No, a parent constructor have to be called explicitly as follows:
parent::constructor($value)
Это странно. Пишу сейчас программу и у меня есть класс Контроллер от которого другие контроллеры наследуются. И вот у контроллера есть конструктор, а у других нет. Хотя я обращаюсь к свойству родителя без проблем. Как так?
Потому что когда ты переопределяешь метод родителя у тебя два пути - или ты полностью пишешь новый метод затирая старый, или ты дополняешь старый - parent::__construct() в твоем случае.
Вообще, у IE есть особенность, влияющая на вывод картинок.
ИЕ и другие браузеры по-разному интерпретируют блок GAMA, который задает гамма-коррекцию для цветов в PNG.
Гамма-коррекция была введена из-за того, что одни и те же RGB цвета могли по-разному выглядеть на разных системах (Mac vs PC). Благодаря ей можно добиться того, что картинка будет выглядеть одинаково в этих системах.
IE интерпретирует эти значения и проводит коррекцию (как и задумано в стандарте). Другие браузеры - нет. При этом в статьях, разумеется, все ругают IE просто за то что он следует стандартам и отображает картинки не так.
То есть по хорошему, нужно спросить автора PNG, а зачем он засунул в картинку такое значение для гамма-коррекции.
https://jonathannicol.com/blog/2006/12/01/fixing-png-gamma/
https://hsivonen.fi/png-gamma/
Решение - не добавлять гамму при сохранении PNG (наверняка есть опция) или вырезать ее утилитами вроде pngcrush.
Кстати, на моем бледном экране оба логотипа на твоей картинке выглядят почти одинаково. Я даже на телефон скопировал картинку и там оба логотипа тоже выглядят одинаково. Но проверка гимпом (через окошка Pointer Info) показала - вверху красный цвет eb6661, а внизу ea6661, так что ты прав, что они разные.
Если ты не переопределяешь в наследнике конструктор, то при создании объекта используется заданный в предке конструктор.
Текст, который ты процитировал, относится к случаю, когда конструктор определен и в предке, и в наследнике - в этом случае конструктор предка по умолчанию не вызывается, если ты это не делаешь явно.
Не мой код.
Во первых убери у селекта тайп
Во вторых <option value="pizda">вагина</option>
Вот при отправке (при выборе "Вагина") отправляться будет pizda.
причем, если я тупо в адресной строке вбиваю путь к нему- все нормально переходит
Помню некоторые простые задачки по джс по 3-5 дней обдумывал. http://learn.javascript.ru/ за полгода осилил. А ты сколько над своей задачкой сидел?
>Я не понимаю как можно генерировать случайную дату юзая мт_ранд, если мы генерим дату в формате d.m.Y H:i:s то на выходе получим 29.09.2017 16:55:16, точки двоеточия и прочее, а мт ранд работает с числами только. Разбивать регулярым вырежения или что
Время в формате юникс не не слышал?
Займись лучше задачками опа, сделай МВЦ приложение, а потом файлообменник.
Нужно ли перекодировать видео для превью?
Бамп вопросу.
Выведи в консоль содержимое переменных, которые передаешь, если все в порядке, то пусть на сервере скрипт через эхо вернет содержимое $_POST. Будет видно где проебался.
Алсо, обычно содержимое формы через .serialize() конвертируют в массив и его передают. Хуй знает что у тебя в свойстве data, никогда так не пробовал
Я делал так https://github.com/grigoryMovchan/2ch_get_img/blob/master/public/js/download-result.js#L13-L40
https://ideone.com/FMplvx
При нажатии на кнопку получаю 404, wtf?
Object not found!
The requested URL was not found on this server. The link on the referring page seems to be wrong or outdated. Please inform the author of that page about the error.
If you think this is a server error, please contact the webmaster.
Error 404
localhost
Apache/2.4.27 (Win32) OpenSSL/1.0.2l PHP/7.0.22
Исправил ошибочку сам.
Спасибо за ответ заранее.
У О'рейли ток справочники нормальные. Да и то я в них что-то глоссария не наблюдаю удобного. Ну разве что в HTML Pocker reference.
Не тупой, просто больше практики нужно, вот и все. Не умеешь решить задачку - Не стоит себя обманывать, старайся думать, думать, думать. У меня когда я писал программы на C, пирамидку например, которая выводится с помощью символов алфавита, там нужно было выравнивание поставить, сделать так, чтобы с каждой линией символы менялись, кода там было... Сидел долго, перечитывал, но проблема была в одном - Я не писал код, а учил теорию, а этого делать нельзя. По статистике все выпускники из больших университетов учащих PC Science или как ее назвать - 99% не умеют программировать, совсем. Нужно уметь отдыхать и одновременно не расслабляться. Много ли людей решают задачи в один день? С одной стороны ответ - Да, потому что времени на самом деле не существует, а временные рамки созданы для удобства. Но если подумать, они ведь тоже создавались не один день, согласись? В общем, как это у нас говорят - ПИШИКОД.
Картинка не отображается потому что не в паблике лежит?
>- Что надо знать чтобы найти работу - разработчику: PHP, SQL, HTML/CSS, JS, ООП, Git, композер, MVC, фреймворк.
Опчик, поясни пожалуйста моменты:
по программированию: что значит "знать Гит"? Это же вроде программа с резервными копиями. На каком уровне я должен ее знать? Просто в ней работать? Или ее дорабатывать как-то?
И вопрос по верстке: я знаю jquery на уровне просто подключить с какой-нибудь каруселью и забыть. Верстальщики реально правят ее код?
Читаю документацию, но что-то понимаю смутно.
В доках говорится, что дескать любая запись\чтение происходит через транзакцию.
Даже небо, даже Аллах.
И в примерах кода всюду:
>var transaction = db.transaction(["customers"], "readwrite");
Но что если я просто сделаю
>DB.objectStore("hui").add({cocol:"semen"});
Без получения богомерзких транзакций?
Это легально вообще?
Будет создана транзакция негласно?
Или браузер сломается?
И если транзакция все равно автоматически будет созданна, почему нигде в примерах нет такого использования?
регулярные*
и что тогда делать?
Не на русском, но самое разжёванное и подробное, что находил: https://www.regular-expressions.info/tutorial.html
Алсо автор сайта из ОП-поста обитает в треде и отвечает на вопросы, ну и мы подскажем как сможем, так что уточняй что непонятно.
Добра тебе! Как раз что-то подобное искал.
Я не совсем по теме,так как работаю с нодой, но в жс-треде вряд ли ответят на такой вопрос.
Я пытаюсь подружить ноду и sql, пишу тестики. Дело в том, что перед каждым проходом тестов мне нужно дропнуть соответствующие таблицы, но код с первого пика не работает, они почему-то не дропаются. Кусок теста ниже должен проверить существование таблицы, а он не проходит, ибо таблица существует уже на начале теста, хотя должна создаться в процессе его выполнения.
Проблема может быть решена посредством закрытия/открытия соединения с БД, но это рушит всю архитектуру моего приложения и совсем не изящно. Подскажите, как дропать таблицы?
С этой, которую модифицирую, на скрине.
https://github.com/mapbox/node-sqlite3
Не знаю, почему. Просто эта первая на глаза попалась. Я вообще начал это копать для расширения кругозора, чтобы освоить SQL.
Проблема не может быть в промисах и асинхронности? Попробуй там console.log натыкать, чтобы увидеть что в каком порядке выполняется.
Также, промисы по умолчанию съедают ошибки, убедись что у тебя любые ошибки выбрасываются в виде исключений и отображаются.
Также, зачем ты функцию описываешь словом const? разве не логичнее использовать function, которое для этого и придумано? Читать тяжело эти скобки и стрелки.
Стрелочные функции были придуманы для ситуаций, когда нужно передать простой коллбек в стиле
array.map(x => x.getName());
По моему субъективному мнению, люди, которые все функции переписывают на стрелочные, просто плохо понимают что они делают и ухудшают читабельность кода.
function doSomething() { // ok
const doSomething = () => { // какая-то невнятная фигня
> Если верить логам, то тесты выполняются ещё до того, как сервер подключится к базе, но подключение внутри них работает.
Значит ты накосячил с промисами.
А мне вот конфиг еслинта от эйрбнб наоборот советует везде использовать стрелочные. Пожалуй, буду следовать его совету, а то тимлид обоссыт.
Да, накосячил. Один тест проходит, зато попадали все другие, и при ручном тестировании не работает. Ух, лучше бы дальше монгой пользовался.
Ну тут я даже не вижу, где ошибка и почему оно неправильно работает. Или правильно? Я не понимаю.
Неправильно, STR не может быть на один миллион. Ошибка в самом цикле или я return не туда впихнул?
Ошибка при подсчёте softcredit. Чего он отказывается его считать?
Допустим, на странице регистрации пользователей есть форма для ввода данных нового пользователя и таблица уже зарегистрированных юзеров, к каждому из которых прикреплена кнопка "Удалить". С регистрацией понятно: вводим данные, нажимаем "Зарегистрировать", срабатывает контроллер, проверяет данные, запускает модель и прописывает юзера в таблицу базы данных. А как правильно добавить удаление? Я пока что вижу такой алгоритм:
- Генерировать под каждую кнопку:
<?php $form = ActiveForm::begin(['id' => 'form1']); ?>
<?= $form->field($model, 'city_name')->textInput(); ?>
<?= Html::submitButton('button1', ['class' => 'btn btn-primary', 'name' => 'button1']); ?>
<?php ActiveForm::end(); ?>
- В контроллере разбирать, от какой кнопки прошло нажатие. И там же прописывать, что именно делать с моделью, добавлять или удалять юзера.
Или нужно делать две разных модели?
$word1[rand(1, count($word1))]
https://ideone.com/e.js/Bcxkl4
? Я имею ввиду какой-нибудь тим-лид - сноб от програмирования - не скажет "да вы гляяяньте на дурачка, тут же код будет выполняться на целую пикосекунду доооольше!"
Зачем тебе сабмит кнопки на удаление? Мути просто ссылки с айди или еще каким-нибудь уникальным атрибутом пользователя. И в роутере разбирай эти ссылки, делай чо надо и редиректь обратно. Хотя это просто мысли я сам вкатывальщик не знаю насколько это правильно
Зачем тебе сабмит кнопки на удаление? Мути просто ссылки с айди или еще каким-нибудь уникальным атрибутом пользователя. И в роутере разбирай эти ссылки, делай чо надо и редиректь обратно. Хотя это просто мысли я сам вкатывальщик не знаю насколько это правильно
Движок же. Там "ни единого слова в простоте". Я пока его не освоил (и освоение идёт, как восход солнца вручную).
Покажи ошибку в консоли браузера (там будет 404 и указан путь по которому он пытался найти картинку)
Потому что тег не может ее найти и она скорее всего вне директорий разметки.
При этом аплоад должен быть в паблике?
хтмл не может выйти выше из паблик директори?
Или я тупой?
../../../../../filename.jpg
спасибо друг!
Большое искреннее спасибо автору учебника, он няшка, а мать его - милашка.
До дома доеду - попробую. С телефона неудобно.
Мож инкремент имеют ввиду.
>MySQL uses the type keyword and these constructions produce DATE, TIME, and DATETIME values, respectively, including a trailing fractional seconds part if specified. The TIMESTAMP syntax produces a DATETIME value in MySQL because DATETIME has a range that more closely corresponds to the standard SQL TIMESTAMP type, which has a year range from 0001 to 9999. (The MySQL TIMESTAMP year range is 1970 to 2038.)
Ненавижу. Что имел ввиду автор документации?
Неправильно, индексы массивов начинаются с 0, а не с 1.
>>1070183
Для начала, надо изучить, что такое литерал: https://ru.wikipedia.org/wiki/Литерал_(информатика)
Литерал - это конструкция в исходном коде, обозначающая какое-то постоянное значение. Например, число, строку.
В синтаксисе стандартного SQL и в диалекте MySQL есть специальный синтаксис для записи литералов, представляющих значения даты или времени. Синтаксис описан в мануале. Пример синтаксиса: DATE '2010-01-01' описывает значение типа DATE, представляющее указанную дату. Пример использования литерала для сравнения с колонкой типа DATE:
SELECT ... WHERE addedDate = DATE '2010-01-01';
Абзац, который ты выделил, говорит о том, что синтаксис с ключевым словом TIMESTAMP или ts:
TIMESTAMP '1999-01-01T12:00:00.123' (из стандарта SQL, формат ISO8601)
{ ts '....' } (из ODBC, это общее API для соединения с разными видами БД)
- создает значение типа DATETIME, а не TIMESTAMP. Потому что DATETIME позволяет представить более широкий диапазон дат. Могут ли от этого быть проблемы? Для этого придется изучить в мануале отличия типов DATETIME и TIMESTAMP и сделать выводы.
От себя скажу, что мне не приходилось использовать такой синтаксис. MySQL позволяет использовать в INSERT или в WHERE просто строку:
INSERT INTO x (addedTime) VALUES ('2018-01-01 12:00:00');
SELECT ... WHERE x = '2012-01-01'
Но я не уверен, что это соответствует стандарту SQL и будет работать в любой СУБД. Стандарт SQL, увы, платный (180 евро по моему за самый новый), потому ссылку дать не могу, могу дать только ссылку на http://modern-sql.com/standard с сборником бесплатных ссылок.
Неправильно, индексы массивов начинаются с 0, а не с 1.
>>1070183
Для начала, надо изучить, что такое литерал: https://ru.wikipedia.org/wiki/Литерал_(информатика)
Литерал - это конструкция в исходном коде, обозначающая какое-то постоянное значение. Например, число, строку.
В синтаксисе стандартного SQL и в диалекте MySQL есть специальный синтаксис для записи литералов, представляющих значения даты или времени. Синтаксис описан в мануале. Пример синтаксиса: DATE '2010-01-01' описывает значение типа DATE, представляющее указанную дату. Пример использования литерала для сравнения с колонкой типа DATE:
SELECT ... WHERE addedDate = DATE '2010-01-01';
Абзац, который ты выделил, говорит о том, что синтаксис с ключевым словом TIMESTAMP или ts:
TIMESTAMP '1999-01-01T12:00:00.123' (из стандарта SQL, формат ISO8601)
{ ts '....' } (из ODBC, это общее API для соединения с разными видами БД)
- создает значение типа DATETIME, а не TIMESTAMP. Потому что DATETIME позволяет представить более широкий диапазон дат. Могут ли от этого быть проблемы? Для этого придется изучить в мануале отличия типов DATETIME и TIMESTAMP и сделать выводы.
От себя скажу, что мне не приходилось использовать такой синтаксис. MySQL позволяет использовать в INSERT или в WHERE просто строку:
INSERT INTO x (addedTime) VALUES ('2018-01-01 12:00:00');
SELECT ... WHERE x = '2012-01-01'
Но я не уверен, что это соответствует стандарту SQL и будет работать в любой СУБД. Стандарт SQL, увы, платный (180 евро по моему за самый новый), потому ссылку дать не могу, могу дать только ссылку на http://modern-sql.com/standard с сборником бесплатных ссылок.
>Неправильно, индексы массивов начинаются с 0, а не с 1.
Ой ладно тебе. Представь, что там не 6 + 1, а 5. Я вообще плюсы первый раз в жизни увидел, код надерган копипастой из гугла.
В Си++ вроде принято использовать для вывода потоки:
cout << question; (если у string определен оператор вывода в поток, я думаю, определен)
printf используется для форматированного вывода и вообще не очень правильно использовать его для вывода просто строки.
Да мне пофигу, если честно. Ты просил на плюсах - ты получил на плюсах.
>>1066173
>>1067949
> https://github.com/radiodog/studentlist/blob/master/composer.json
Тут name и description можно не указывать. У тебя же не библиотека.
> https://github.com/radiodog/studentlist/blob/master/mydb.sql
тут в дампе явно лишние команды, требующие администраторских привилегий, например, CREATE EXTENSION.
Плюс прописано конкретное имя пользователя. Лучше делать дамп, который содержит только таблицы и не привязан к конкретному пользователю или названию БД. Я думаю, надо просто разобраться с опциями pgdump.
Папку vendor нужно внести в gitignore.
Classes - плохое название для папки (и тем более для неймспейса), и так понятно что в ООП приложении большинство файлов содержат классы.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Router.php
В конструкторе класса Router указан аргумент $url, но на самом деле туда передается массив. Причем нигде не описано какой именно массив, с какими полями. Не нужно так делать, нужно указать конкретные аргументы.
Также, непонятно почему у тебя код разбора роута в конструкторе. Конструктор используется для создания объекта, а для разбора URL логично сделать отдельный метод. К тому же это позволит вызвать его несколько раз.
Тем более ненормально, что роутер еще и exit вызывает в конструкторе. Это вообще не роутер, а FrontController получается.
Сам алгоритм роутинга переусложнен, не проще сделать через сравнение строк или регулярки?
URL можно разобрать на части с помощью parse_url.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Controller.php
Базовый контроллер выглядит странно. Например, почему там прописана установка соединения с БД? Как-то немного странно. Зачем вообще в контроллере иметь объект PDO?
Обработка исключений при создании PDO сделана неправильно, читай мой (или чей-нибудь еще) урок про исключения на гитхабе.
Проверку/установку авторизационных кук лучше сделать в отдельном классе/функциях, а не размазывать кусочками по коду.
Для хранения данных формы можно было использовать объект Student, а не массив.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Controller.php
Тут у тебя в случае успеха сообщение об успехе выводится до DOCTYPE, это неправильно. Это вообще может привести к тому, что кодировка не определится правильно. И после успешной обработки POST-формы надо делать редирект, а не выводит снова эту форму. Это описано в моем уроке про формы.
> public function getValuesFromPost()
Тут надо было использовать цикл, а не копипастить код.
> $validator->validate($values,$dataGateway);
> $message = $validator->message;
Что мешает вернуть результат функции через return? Зачем городить такой странный способ передачи результата?
> if ($values['e_mail']==$valuesFromDB['e_mail']) {
> $errors['e_mail'] ='';
Лучше в валидаторе сделать проверку, что при редактировании можно использовать тот же email.
> $student->setId($this->dataGateway->getCount()+1);
Это неправильный и неэффективный способ, и не защищает от гонки (один поток считает число записей, другой в это время делает вставку новой записи), нужно использовать lastInsertId. И, конечно, делать это в классе работы с БД, а не в контроллере.
> getMarks($placeholder)
Это бы конечно лучше делать во view, а не тут.
Вообще, что-то в контроллере регистрации многовато кода получилось.
Название MainController неудачное, не отражает назначение контроллера. И PageController тоже.
https://github.com/radiodog/studentlist/blob/master/src/Classes/PageController.php#L22
> if ($_SERVER['REQUEST_METHOD']=="GET"){
А если не GET, то что тогда произойдет?
> public function createNext($request)
> public function createPrev($request)
Тут сплошная копипаста. Лучше сделать одну универсальную функцию для генерации URL, и не в контроллере.
> $numPattern = "/(0-9)*/ui";
нет привязки к краям строки (^$)
> https://github.com/radiodog/studentlist/blob/master/src/Classes/PageController.php#L42
> $request['order'] = ....
> $request['order'] = ....
Создается впечатление, что первая строчка ничего не делает и не нужна.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Pager.php#L25
Тут какая-то переусложненная формула. Посчитать число страниц можно проще.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Student.php#L16
Слишком много аргументов в конструкторе. Лучше сделать либо пустой конструктор, либо сделать метод вроде updateAttributes, принимающий массив.
Вот вообще, подумай, если надо будет добавить/убрать поле из студента - много ли придется менять? Что-то мне кажется, что много.
https://github.com/radiodog/studentlist/blob/master/src/Classes/UserDataGateway.php#L19
> return $row = ...
Зачем здесь создается переменная?
> https://github.com/radiodog/studentlist/blob/master/src/Classes/UserDataGateway.php
В этом файле не выдерживается единый стиль кода, посмотри на имена функций и на расстановку фигурных скобок.
https://github.com/radiodog/studentlist/blob/master/src/Classes/UserDataGateway.php#L33
> OFFSET $index");
Тут SQL инъекция.
> ORDER BY $sort $order
И тут
> $name = $student->getName();
> $stmt->bindValue(':name', $name);
Что мешает сразу писать $student->getName() без создания промежуточной переменной?
> $result = $stmt->fetch();
> return $result['count'];
Есть метод для получения одного значения.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Validator.php#L153
> checkArr($message)
Название ничего не говорит о том, что делает метод. "проверить массив" ничего не значит.
Для пола и locality нужно завести константы.
> [1-2][90]
Лучше вместо регулярки использовать сравнения вида $x > 1900 либо писать (19|20)
> OR ($form['name']=='Имя'))
Странная проверка.
> elseif ((preg_match($name_pattern, $form['name'])==1)&(mb_strlen($form['name'])>40)) {
> elseif ((preg_match($name_pattern, $form['name'])==1)&(mb_strlen($form['name'])>40)) {
> elseif ((preg_match($name_pattern, $form['name'])==1) &(preg_match($tag_pattern, $form['name'])==0) &(preg_match($digits_pattern,$form['name'])==0) &(40>mb_strlen($form['name'])) & (mb_strlen($form['name'])>0)){
Эта копипаста до добра не доведет. Надо либо перегруппировать ифы, либо вынести проверку имени в отдельный метод.
> href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css"
Лучше держать свои файлы на своем сервере, а не полагаться на другие.
https://github.com/radiodog/studentlist/blob/master/src/View/Form.php
HTML код не отформатирован (отступы не соблюдаются) и его тяжело читать. Вместо табов лучше использовать 4 пробела.
https://github.com/radiodog/studentlist/blob/master/src/View/Form.php#L27
> value = "<?=$values['name']?>"
Тут XSS уязвимость.
> placeholder = "<
А HTML стандарт позволяет ставить пробел между названием атрибута и знаком равенства? Поищи-ка https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
> <div class="invalid-feedback">
Возможно, стоит не показывать эти блоки, если ошибки нету.
> <a href='http://localhost/index.php/list'>Список студентов</a>
Используй относительные ссылки, где не указан протокол и домен. У меня есть урок про URL.
В шаблонах Form и List общая шапка и подвал, нужно убрать копипасту. Иначе замучаешься потом править в нескольких местах сразу.
https://github.com/radiodog/studentlist/blob/master/src/View/List.php#L49
> <?php $thisStudent = ($value->getEmail()==$this->dataGateway->getByHash($this->hashUser)['e_mail']) ? "table-active" : "" ?>
Этот код не должен быть во view. С каких это пор у нас View отвечает за проверку кук или поиск в БД?
https://github.com/radiodog/studentlist/blob/master/src/View/List.php#L64
Пагинатор очень громоздкий. Нельзя ли его сократить?
Вообще, ты бы мог сделать класс ViewHelper с обычными или статическими методами, которые бы помогали при выводе шаблона.
>>1066173
>>1067949
> https://github.com/radiodog/studentlist/blob/master/composer.json
Тут name и description можно не указывать. У тебя же не библиотека.
> https://github.com/radiodog/studentlist/blob/master/mydb.sql
тут в дампе явно лишние команды, требующие администраторских привилегий, например, CREATE EXTENSION.
Плюс прописано конкретное имя пользователя. Лучше делать дамп, который содержит только таблицы и не привязан к конкретному пользователю или названию БД. Я думаю, надо просто разобраться с опциями pgdump.
Папку vendor нужно внести в gitignore.
Classes - плохое название для папки (и тем более для неймспейса), и так понятно что в ООП приложении большинство файлов содержат классы.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Router.php
В конструкторе класса Router указан аргумент $url, но на самом деле туда передается массив. Причем нигде не описано какой именно массив, с какими полями. Не нужно так делать, нужно указать конкретные аргументы.
Также, непонятно почему у тебя код разбора роута в конструкторе. Конструктор используется для создания объекта, а для разбора URL логично сделать отдельный метод. К тому же это позволит вызвать его несколько раз.
Тем более ненормально, что роутер еще и exit вызывает в конструкторе. Это вообще не роутер, а FrontController получается.
Сам алгоритм роутинга переусложнен, не проще сделать через сравнение строк или регулярки?
URL можно разобрать на части с помощью parse_url.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Controller.php
Базовый контроллер выглядит странно. Например, почему там прописана установка соединения с БД? Как-то немного странно. Зачем вообще в контроллере иметь объект PDO?
Обработка исключений при создании PDO сделана неправильно, читай мой (или чей-нибудь еще) урок про исключения на гитхабе.
Проверку/установку авторизационных кук лучше сделать в отдельном классе/функциях, а не размазывать кусочками по коду.
Для хранения данных формы можно было использовать объект Student, а не массив.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Controller.php
Тут у тебя в случае успеха сообщение об успехе выводится до DOCTYPE, это неправильно. Это вообще может привести к тому, что кодировка не определится правильно. И после успешной обработки POST-формы надо делать редирект, а не выводит снова эту форму. Это описано в моем уроке про формы.
> public function getValuesFromPost()
Тут надо было использовать цикл, а не копипастить код.
> $validator->validate($values,$dataGateway);
> $message = $validator->message;
Что мешает вернуть результат функции через return? Зачем городить такой странный способ передачи результата?
> if ($values['e_mail']==$valuesFromDB['e_mail']) {
> $errors['e_mail'] ='';
Лучше в валидаторе сделать проверку, что при редактировании можно использовать тот же email.
> $student->setId($this->dataGateway->getCount()+1);
Это неправильный и неэффективный способ, и не защищает от гонки (один поток считает число записей, другой в это время делает вставку новой записи), нужно использовать lastInsertId. И, конечно, делать это в классе работы с БД, а не в контроллере.
> getMarks($placeholder)
Это бы конечно лучше делать во view, а не тут.
Вообще, что-то в контроллере регистрации многовато кода получилось.
Название MainController неудачное, не отражает назначение контроллера. И PageController тоже.
https://github.com/radiodog/studentlist/blob/master/src/Classes/PageController.php#L22
> if ($_SERVER['REQUEST_METHOD']=="GET"){
А если не GET, то что тогда произойдет?
> public function createNext($request)
> public function createPrev($request)
Тут сплошная копипаста. Лучше сделать одну универсальную функцию для генерации URL, и не в контроллере.
> $numPattern = "/(0-9)*/ui";
нет привязки к краям строки (^$)
> https://github.com/radiodog/studentlist/blob/master/src/Classes/PageController.php#L42
> $request['order'] = ....
> $request['order'] = ....
Создается впечатление, что первая строчка ничего не делает и не нужна.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Pager.php#L25
Тут какая-то переусложненная формула. Посчитать число страниц можно проще.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Student.php#L16
Слишком много аргументов в конструкторе. Лучше сделать либо пустой конструктор, либо сделать метод вроде updateAttributes, принимающий массив.
Вот вообще, подумай, если надо будет добавить/убрать поле из студента - много ли придется менять? Что-то мне кажется, что много.
https://github.com/radiodog/studentlist/blob/master/src/Classes/UserDataGateway.php#L19
> return $row = ...
Зачем здесь создается переменная?
> https://github.com/radiodog/studentlist/blob/master/src/Classes/UserDataGateway.php
В этом файле не выдерживается единый стиль кода, посмотри на имена функций и на расстановку фигурных скобок.
https://github.com/radiodog/studentlist/blob/master/src/Classes/UserDataGateway.php#L33
> OFFSET $index");
Тут SQL инъекция.
> ORDER BY $sort $order
И тут
> $name = $student->getName();
> $stmt->bindValue(':name', $name);
Что мешает сразу писать $student->getName() без создания промежуточной переменной?
> $result = $stmt->fetch();
> return $result['count'];
Есть метод для получения одного значения.
https://github.com/radiodog/studentlist/blob/master/src/Classes/Validator.php#L153
> checkArr($message)
Название ничего не говорит о том, что делает метод. "проверить массив" ничего не значит.
Для пола и locality нужно завести константы.
> [1-2][90]
Лучше вместо регулярки использовать сравнения вида $x > 1900 либо писать (19|20)
> OR ($form['name']=='Имя'))
Странная проверка.
> elseif ((preg_match($name_pattern, $form['name'])==1)&(mb_strlen($form['name'])>40)) {
> elseif ((preg_match($name_pattern, $form['name'])==1)&(mb_strlen($form['name'])>40)) {
> elseif ((preg_match($name_pattern, $form['name'])==1) &(preg_match($tag_pattern, $form['name'])==0) &(preg_match($digits_pattern,$form['name'])==0) &(40>mb_strlen($form['name'])) & (mb_strlen($form['name'])>0)){
Эта копипаста до добра не доведет. Надо либо перегруппировать ифы, либо вынести проверку имени в отдельный метод.
> href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css"
Лучше держать свои файлы на своем сервере, а не полагаться на другие.
https://github.com/radiodog/studentlist/blob/master/src/View/Form.php
HTML код не отформатирован (отступы не соблюдаются) и его тяжело читать. Вместо табов лучше использовать 4 пробела.
https://github.com/radiodog/studentlist/blob/master/src/View/Form.php#L27
> value = "<?=$values['name']?>"
Тут XSS уязвимость.
> placeholder = "<
А HTML стандарт позволяет ставить пробел между названием атрибута и знаком равенства? Поищи-ка https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
> <div class="invalid-feedback">
Возможно, стоит не показывать эти блоки, если ошибки нету.
> <a href='http://localhost/index.php/list'>Список студентов</a>
Используй относительные ссылки, где не указан протокол и домен. У меня есть урок про URL.
В шаблонах Form и List общая шапка и подвал, нужно убрать копипасту. Иначе замучаешься потом править в нескольких местах сразу.
https://github.com/radiodog/studentlist/blob/master/src/View/List.php#L49
> <?php $thisStudent = ($value->getEmail()==$this->dataGateway->getByHash($this->hashUser)['e_mail']) ? "table-active" : "" ?>
Этот код не должен быть во view. С каких это пор у нас View отвечает за проверку кук или поиск в БД?
https://github.com/radiodog/studentlist/blob/master/src/View/List.php#L64
Пагинатор очень громоздкий. Нельзя ли его сократить?
Вообще, ты бы мог сделать класс ViewHelper с обычными или статическими методами, которые бы помогали при выводе шаблона.
Решил проблему
Как я уже говорил, в моей обёртке ничего не возвращалось, и вообще странно что я в итоге что-то получил. Мне пришла в голову мысль, что странно, что я получил значения вне обещания (обычно мы в таком случае получаем undefined), и решил что сначала нужно получить все обещания, а потом проходить по ним циклом, в итоге даже обёртка не понадобилась:
getMessages.then(function(messages) {
var promises = [];
for (var key in messages) {
var decrypted = decrypt(messages[key]);
promises.push(decrypted); // Можно даже не выставлять ключ, обещания добавятся синхронно, а асинхронное выполнение будет позже
}
Promise.all(promises).then(function(decrypted) {
for (var key in messages) {
messages[key] = decrypted[key].data;
}
showMessages(messages);
});
});
Вот и всё! Всё оказалось очень просто.
Немого смущает что один и тот же цикл повторяется дважды, но в этом ничего плохого.
Немного пугает, что я не мучился над решением этой задачи, её решение пришло мне в голову само собой. Можно сказать, что мне просто повезло.
Я просто подумал, как бы я её решил если не было возможности получить вашего совета, и единственное что пришло в голову, это то что бы я просто выводил бы сообщения по одному внутри метода расшифровки, что являлось бы самим по себе нарушением инкапсуляции. Только через некоторое время мысль о том, что можно получить обещания и выполнить их все сразу, пришла сама собой.
Если бы не ваши наставления, я бы писал довольно хаотичный код, и даже не чувствовал за это угрызение совести.
Решил проблему
Как я уже говорил, в моей обёртке ничего не возвращалось, и вообще странно что я в итоге что-то получил. Мне пришла в голову мысль, что странно, что я получил значения вне обещания (обычно мы в таком случае получаем undefined), и решил что сначала нужно получить все обещания, а потом проходить по ним циклом, в итоге даже обёртка не понадобилась:
getMessages.then(function(messages) {
var promises = [];
for (var key in messages) {
var decrypted = decrypt(messages[key]);
promises.push(decrypted); // Можно даже не выставлять ключ, обещания добавятся синхронно, а асинхронное выполнение будет позже
}
Promise.all(promises).then(function(decrypted) {
for (var key in messages) {
messages[key] = decrypted[key].data;
}
showMessages(messages);
});
});
Вот и всё! Всё оказалось очень просто.
Немого смущает что один и тот же цикл повторяется дважды, но в этом ничего плохого.
Немного пугает, что я не мучился над решением этой задачи, её решение пришло мне в голову само собой. Можно сказать, что мне просто повезло.
Я просто подумал, как бы я её решил если не было возможности получить вашего совета, и единственное что пришло в голову, это то что бы я просто выводил бы сообщения по одному внутри метода расшифровки, что являлось бы самим по себе нарушением инкапсуляции. Только через некоторое время мысль о том, что можно получить обещания и выполнить их все сразу, пришла сама собой.
Если бы не ваши наставления, я бы писал довольно хаотичный код, и даже не чувствовал за это угрызение совести.
>$monthlyPay = 5000;
>if ($totalSum <= 5000)
Ежемесячная плата должна передаваться через аргументы, а не определяться по среди функции.
И ещё пара придирок:
>echo "{$month} месяц спустя: долг = {$totalSum} руб, выплачено всего {$paymentTotal} руб. \n";
Такой вывод, обычно, используется для проверки работы функции. Если функция рабочая, то достаточно просто вернуть какое-то значение.
Если это не редактор кода сломал оформление, то советую почитать >>1067945
Очень много лишних отступов и табуляций.
Неделю
чем вот эта: [a-z][a-z][0-9][0-9][0-9][a-z]
отличается от этой: [a-z]{2}[0-9]{3}[a-z]{1}
число в {} говорит о количестве повторений, правильно?
Спасибо большое!
Понимаю, что плохо и криво. Не понимаю, как сделать лучше. Очень хочется уйти от принципа "но ведь работает же!" и перестать писать говнокод.
я занимаюсь php вот уже который год два дня, но мне все нравится, особенно рандом внутри ключа массива. Идеальней ведь не напишешь. Есть тут гуру? Все же верно вроде и не говнокод
В пятом ПХП уже не ругается и компилит, но только с латиницей (пик два).
С кириллицей выходит лажа (пик три).
http://archive-ipq-co.narod.ru/l1/regexp.html
Вот список номеров:
// Правильные:
$correctNumbers = [
'84951234567', '+74951234567', '8-495-1-234-567',
' 8 (8122) 56-56-56', '8-911-1234567', '8 (911) 12 345 67',
'8-911 12 345 67', '8 (911) - 123 - 45 - 67', '+ 7 999 123 4567',
'8 ( 999 ) 1234567', '8 999 123 4567'
];
// Неправильные:
$incorrectNumbers = [
'02', '84951234567 позвать люсю', '849512345', '849512345678',
'8 (409) 123-123-123', '7900123467', '5005005001', '8888-8888-88',
'84951a234567', '8495123456a',
'+1 234 5678901', / неверный код страны /
'+8 234 5678901', / либо 8 либо +7 /
'7 234 5678901' / нет + /
];
Какой смысл корячится и изголяться с учетом скобок/пробелов/минусов, если можно просто убрать эти символы из строки?
>>1070551
>Какой смысл корячится и изголяться с учетом скобок/пробелов/минусов, если можно просто убрать эти символы из строки?
Но ведь юзер об этом не узнает, ввел он телефон в одном формате, а потом к примеру пытается восстановить пароль или залогиниться по номеру, а ты сохранил номер в другом виде. Вообще для этих целей используют masked input который не дает юзерам выстрелить себе в ногу неправильным вводом номера
>Но ведь юзер об этом не узнает
Спасибо за ответ, няша. Я имею ввиду зачем нам изголяться, учитывая скобки/палочки/минусы, если можно перед сравнением строки с регулярным выражением просто убрать из нее все не нужные символы автозаменой вот так
$wwq = array("\"", "'", ";", ",", ":", "/", "\\", "=", ")", "(", "%", "*", "?");
$row['title'] = str_replace($wwq, "", $row['title']);
а потом уже совать в регулярку голые цифры?
Меня будет будущий тимлид ругать за то, что я сделаю проще, а не через регулярку?
>$wwq = array("\"", "'", ";", ",", ":", "/", "\\", "=", ")", "(", "%", "", "?");
>$row['title'] = str_replace($wwq, "", $row['title']);
Проще же
preg_replace('/(\\D)/', '', $string) тогда.
>Меня будет будущий тимлид ругать за то, что я сделаю проще, а не через регулярку?
Редко приходится работать с регулярками, но ты должен иметь представление, что это и для чего их можно использовать
спасибо
Слим при том, что там есть простейший вариант конфига для фронт контроллера
А что ты изучал до Юи?
>>1070501
Да
>>1070502
Ты сначала пройди задачу про Вектор, а потом посмотрим. Чтобы разобраться в MVC и вообще в приложениях с таблицами и формами, есть задача про студентов в ОП посте.
>>1070544
Gateway timeout значит что нгинкс отправил запрос на бекенд (например на php-fpm), но ответа не пришло. Тебе надо разобраться в своем конфиге, куда он отправляет запросы и почему на них не отвечают вовремя.
>>1070558
Можно сделать так, но не думаю, что это проще. Применить одну регулярку явно проще чем что-то сделать со строкой, а только потом применить регулярку. Ты наверно просто не знаешь, как это сделать регуляркой.
>>1070564
> preg_replace('/(\\D)/', '', $string)
Это вырежет буквы, а наличие букв должно делать номер неправильным.
Голый php/js. Ну, ещё краем аякс и jquery захватил.
>Ты наверно просто не знаешь, как это сделать регуляркой.
не знаю, поэтому и спрашиваю ответ. А ответа именно к этой задаче нету.
Кроме того, мне кажется, что убрать одной регуляркой всё кроме цифр намного проще, чем писать регулярку, которая будет учитывать:
1.Начало с +7, + 7, 8
2.Палочки, скобочки, пробелы
3.Все вышеперечисленное определенной длины
Есть роут Route::group(['domain' => 'admin.' . env('APP_DOMAIN') где APP_DOMAIN = sitename.dev. На сервере у меня нормально заходит по этому адресу, но на локалке получаю Server not found (ошибка как будто я захожу на несуществующий сайт). В route:list всё нормально. Как настроить правильно?
вот код:
https://ideone.com/e.js/ZCPtZ5
он вроде пропускает все хорошие номера, но и часть плохих тоже пропускает
вот сама регулярка:
$regexp = "/(\+7|8|\+ 7)+[0-9\-\(\)\s]{10}/ui";
как сделать чтобы {10} применялось ко всей строчке, а не только, как я понимаю, к последнему куску, и как обрезать "позвать люсю"?
Квантификатор {10} применяется к идущей перед ним конструкции [0-9\-\(\)\s]
Чтобы явно указать, к чему он дложен применяться, можно использовать круглые скобки:
(выражение){10}
> и как обрезать "позвать люсю"?
Твоя регулярка не привязана к краям строки, то есть достаточно, чтобы с ней совпала только часть строки, а оставшиеся символы могут быть любыми, например:
aaaaaa +70001234567 ааааааааа
Нужно использовать привязку к краям строки с помощью ^ и $.
>- создает значение типа DATETIME, а не TIMESTAMP. Потому что DATETIME позволяет представить более широкий диапазон дат. Могут ли от этого быть проблемы? Для этого придется изучить в мануале отличия типов DATETIME и TIMESTAMP и сделать выводы.
Как тогда получить TIMESTAMP, если префикс TIMESTAMP означает DATETIME?
С помощью литералов - никак, но может быть там есть функция конвертации в TIMESTAMP?
Можно поискать по слову timestamp тут: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestamp
Но там даже функция TIMESTAMP() возвращает datetime. Я подозреваю, что видимо разработчики MySQL не видят особой выгоды в использовании TIMSTAMP и считают что DATETIME лучше. (она отличается только привязкой к временной зоне по моему).
А какой у тебя случай? Зачем тебе понадобилось именно значение типа TIMESTAMP, можно поинтересоваться? Что в нем есть такого, чего нет в DATETIME?
Если что, мануал по особенностям этих типов тут:
- https://dev.mysql.com/doc/refman/5.7/en/date-and-time-types.html
- https://dev.mysql.com/doc/refman/5.7/en/datetime.html
>А какой у тебя случай?
Я решил прочитать документацию MySQL, вот какой у меня случай. :3 Терплю умеренные бомбардировки тылов в связи с тем, как она написана.
Нгинкс никак не соотносится с твоим фронт-контроллером, всё зависит от ос которую ты используешь, равно как и апач, это так сказать сфера системного администрирования уже. Там написано только то, что тебе нужно сделать на стороне приложения, конфиг самого сервера нужно курить дополнительно.
>>1070590
Молодца, ежели разобрался.
Чо я не так написал? Вроде всё норм, но припопытке нажатия на кнопку жалуется мол "Warning: implode(): Invalid arguments passed in ..\json_answer.php on line 4"
Код json_answer.php посередине.
Ладно, посиотрим. А можно чуть подробнее суть проблемы?
Я совершенно случайно додумался сделать динамичную адаптивную верстку, не знаю это ли ты имел ввиду когда говорил, чтобы я сделал не механическую верстку. Я проверил страницу на 3х устройствах, сбоев нет. Пока не знаю как включить виртуалку, чтобы проверить на IE-7-11, но представляю что там будет, браузерстак пока покупать не в состояний, будущем подпишусь.
Сделать мульти-страничный CSS не смог, осознание пришло под самый конец, поисправлял кучу классов и.т.д
Верстка заняла примерно 4 дня, не полных конечно же.
https://theknacker.github.io/Webpaint/webpaint.html
Может кто-нибудь подробно объяснить логику рботы фреймворка, когда на вью страницы есть несколько кнопок?
Без него всё было просто: для логина три инпута и кнопка. На кнопке висит onclick="register();", запускающий предачу данных через аякс php-скрипту. А таблица генерируется динамически через foreach, столько строк, сколько есть в базе юзеров. И кнопка удаления на каждой строке onclick='delete_line($user_id, $table_users);' При нажатии, js-скрипт передаёт данные аяксом php-скрипту и тот удаляет из указанной таблицы указанную строку.
Теперь с фреймворком.
Создал модель SignupForm с атрибутами и парой методов. Подключил в контроллере, создал public function actionSignup(). В неём загрузка и проверка данных:
$model = new SignupForm(); //создаём объект модели UsersForm
if($model->load(\Yii::$app->request->post()) && $model->validate()){}
$user = new User(); //создаём объект модели User (эта модель указана в качестве компонента идентификации в файле config\web.php)
$user->username = $model->username; //передаём атрибут модели UsersForm в атрибут модели User
$user->full_name = $model->full_name; //заполним его полученными из формы данными
$user->password = \Yii::$app->security->generatePasswordHash($model->password); //Аналогично, только ещё и шифруем
if($user->save()){
return $this->render('users', compact('model')); //рендерим вью users, передав в него модель model
}
А во вью прописываем $form = ActiveForm::begin(), затем поля для ввода $form->field($model, 'username', ['template' => '{label} <div class="row"><div class="col-sm-2">{input}{error}{hint}</div></div>']), кнопку Html::submitButton('Регистрация', ['class' => 'btn btn-success', 'id' => 'add1', 'name' => 'add2']) и в конце ActiveForm::end().
Это всё как-то даже работает. Но как правильно сгенерировать кнопки удаления и обрабатывать их нажатия?
1) Все поля и кнопки во вью должны быть между begin() - end(), или для каждого блока эта конструкция должна быть своя?
2) Обработка идёт в контроллере? В одном и том же акшене? Как проверить, от какой кнопки пришло нажатие?
3) Модель не трогаем?
4) Что за \ в акшене? Я переписал это из урока по Yii, но нагуглить, что это такое, не смог.
5) Я не понимаю конструкцию $model->load(\Yii::$app->request->post()) && $model->validate()
По сути, она загружает в модель полученные данные, если они получены и провалидированы. Но если разбираться, то получается, что сначала данные приходят постом, потом валидируется модель, в которой пока что нет новых данных (и непонятно, зачем вообще её проверять), а потом идёт load непонятно чего.
6) Как вообще вытащить из post данные в контроллере? Я делал
echo '<pre>'; print_r($model); //распечатка модели
и получал все данные, а вот получить конкретное значение поля, которое ввёл юзер, не могу.
Может кто-нибудь подробно объяснить логику рботы фреймворка, когда на вью страницы есть несколько кнопок?
Без него всё было просто: для логина три инпута и кнопка. На кнопке висит onclick="register();", запускающий предачу данных через аякс php-скрипту. А таблица генерируется динамически через foreach, столько строк, сколько есть в базе юзеров. И кнопка удаления на каждой строке onclick='delete_line($user_id, $table_users);' При нажатии, js-скрипт передаёт данные аяксом php-скрипту и тот удаляет из указанной таблицы указанную строку.
Теперь с фреймворком.
Создал модель SignupForm с атрибутами и парой методов. Подключил в контроллере, создал public function actionSignup(). В неём загрузка и проверка данных:
$model = new SignupForm(); //создаём объект модели UsersForm
if($model->load(\Yii::$app->request->post()) && $model->validate()){}
$user = new User(); //создаём объект модели User (эта модель указана в качестве компонента идентификации в файле config\web.php)
$user->username = $model->username; //передаём атрибут модели UsersForm в атрибут модели User
$user->full_name = $model->full_name; //заполним его полученными из формы данными
$user->password = \Yii::$app->security->generatePasswordHash($model->password); //Аналогично, только ещё и шифруем
if($user->save()){
return $this->render('users', compact('model')); //рендерим вью users, передав в него модель model
}
А во вью прописываем $form = ActiveForm::begin(), затем поля для ввода $form->field($model, 'username', ['template' => '{label} <div class="row"><div class="col-sm-2">{input}{error}{hint}</div></div>']), кнопку Html::submitButton('Регистрация', ['class' => 'btn btn-success', 'id' => 'add1', 'name' => 'add2']) и в конце ActiveForm::end().
Это всё как-то даже работает. Но как правильно сгенерировать кнопки удаления и обрабатывать их нажатия?
1) Все поля и кнопки во вью должны быть между begin() - end(), или для каждого блока эта конструкция должна быть своя?
2) Обработка идёт в контроллере? В одном и том же акшене? Как проверить, от какой кнопки пришло нажатие?
3) Модель не трогаем?
4) Что за \ в акшене? Я переписал это из урока по Yii, но нагуглить, что это такое, не смог.
5) Я не понимаю конструкцию $model->load(\Yii::$app->request->post()) && $model->validate()
По сути, она загружает в модель полученные данные, если они получены и провалидированы. Но если разбираться, то получается, что сначала данные приходят постом, потом валидируется модель, в которой пока что нет новых данных (и непонятно, зачем вообще её проверять), а потом идёт load непонятно чего.
6) Как вообще вытащить из post данные в контроллере? Я делал
echo '<pre>'; print_r($model); //распечатка модели
и получал все данные, а вот получить конкретное значение поля, которое ввёл юзер, не могу.
Ну, это-то понятно, но зачем "\"? Без него никак нельзя? Что-то же он делает.
Благодарю, добрый анон.
Не работает команда ORDER BY. Параметр проходит правильно, в консоли запрос отлаживал. ЧЯДНТ?
С помощью плейхолдеров можно подставлять только числа и строки (в кавычках). Имена полей или таблиц подставлять нельзя.
Имя поля нужно вставлять напрямую в запрос, предварительно проверив его по списку разрешенных значений.
Да, я уже разобрался. Интересно, почему PDO не предусматривает возможности подставлять имя поля или таблиц? Вроде же логично что бы была и такая фича.
Плейсхолдеры задумывались для оптимизации многократного выполнения похожих запросов, чтобы СУБД могла бы один раз разобрать запрос, построить оптимальный план его выполнения и дальше уже выполнять несколько запросов, используя построенный план.
Для запроса вроде такого:
SELECT x FROM t WHERE a = ?
Здесь СУБД может построить план запроса, не зная подставляемого значения.
Если ты пропускаешь имя колонки, то построить план выполнения запроса нельзя.
Хотя я согласен, что есть смысл в том, что ты предлагаешь. Для этого можно написать библиотеку поверх PDO. Я такие возможности видел в одной старой библиотеке плейсхолдеров которую когда-то использовал (да, я почти с самого начала писал запросы с плейсхолдерами, хотя PDO тогда еще не было и в учебниках про них не писали): http://dklab.ru/lib/DbSimple/ (внимание! библиотека безнадежно устарела).
Вообще конечно, было бы хорошо, если бы какой-нибудь анон с запасом свободного времени сделал бы обзор разных библиотек для работы с БД.
Кстати там же у меня не работает WHERE LIKE, я так понимаю там тоже надо как-то хитро экранировать, не?
Нет, это не из-за плейсхолдеров.
Также, ORDER BY или WHERE правильнее будет назвать не "командой", а "конструкцией". По английски это называется clause (например, "This statement contains ORDER BY clause" - в этом запросе есть конструкция ORDER BY), а по-русски мне ничего, кроме "конструкция" в голову не приходит.
Вообще, clause переводится так: http://dictionary.cambridge.org/ru/словарь/англо-русский/clause
Основной смысл - статья (пункт) в договоре.
Тут https://postgrespro.ru/docs/postgresql/9.6/queries-table-expressions.html clause переводят как "предложение", но мне кажется, это неудачный перевод.
Если кто-нибудь из анонов видел другие переводы термина clause в книгах (желательно поофициальней), напишите пожалуйста.
Ну кусок "WHERE
name LIKE :search OR
secondName LIKE :search OR
groupNumber LIKE :search OR
summary LIKE :search "
У меня не работает, опять же если без плейсхолдеров то все норм.
Потому что, если у тебя в файле объявлен неймспейс, например
namespace frontend\controllers;
то Yii::$app->request->post() попытается обратиться к frontend\controllers\Yii::$app->request->post();
Чтобы этого избежать - как выше писал анон - можно сделать use Yii; либо указать \ (рут)
Лучше и школьников каких-то закажи визитку на вордпрессе и отдельно ищи услуги по раскрутке. Битрикс нахуй не нужен.
думаешь так лучше будет?а шаблонный на конструкторе совсем дно?
Но вот что именно ты сделаешь - большой вопрос. Наверни The7, она ахуенна!
ААААААА! Сука, что за хуйня там. Целая страница ёбаного кода. Я нихуя понять не могу, что не так блять.
вордпресс или джумла, там без проблем разобраться. А битрикс скорее нужен для сайтов с каталогами товаров и выгрузкой/загрузкой в 1с.
У битрикса дохуя возможностей, но без опыта кодинга там особо делать нечего
Лучше использовать DI: https://github.com/codedokode/pasta/blob/master/arch/di.md
Создаешь DI контейнер с сервисами, передаешь в контроллер, и пусть контроллер из него берет что ему нужно.
Там в статье есть часть кода простейшего контейнера, а можно в принципе сделать еще проще и использовать в качестве контейнера просто массив.
Уже почти все правильные варианты могу отобрать, кроме одного, при всего лишь трех ложных срабатываниях. Идти дальше по упражнениям или продолжать задрачивать?
Ты бы ссылки хоть давал, если упомниаешь какие-то статьи. А то непонятно, что смотреть.
По поводу приложения - по идее ошибки должны писаться в логи, и ты там можешщь их просмотреть (на продакшене не принято ошибки на всеобщее обозрение выставлять).
По поводу логов тут https://devcenter.heroku.com/articles/php-logging#logging-from-plain-php написано что ошибки должны идти в "heroku logs".
Соответственно тут дана команда просмотра логов: https://devcenter.heroku.com/articles/logging#view-logs
Попробуй с нее начать.
Также, можно получить доступ к консоли, если ты знаком с линуксовыми командами: https://devcenter.heroku.com/articles/getting-started-with-php#start-an-interactive-shell
Из консоли можно например попробовать соединиться с БД, выполнять какие-то SQL запросы.
Тут описано подключение к Postgres: https://devcenter.heroku.com/articles/getting-started-with-php#provision-a-database
Там тебе не дают привычных параметров соединения с БД (хост, пароль и тд) явно, а передают их в переменной окружения твоему приложению. Почитай в гугле, что такое переменные окружения, почитай мануал по getenv. Твое приложение, если оно запущено на хероку, должно брать параметры соединения из указанной в мануале переменной окружения. Там есть пример кода, но я бы его доработал - например, там нет никакой проверки на ошибки, нет действий в случае, если переменная не задана или пуста.
Я подозреваю, так сделано из-за динамичной природы хероку, твое приложение может запускаться на разных узлах, и база данных тоже может перемещаться между узлами, таким образом параметры подключения к БД меняются и их нельзя прописать в конфиг.
Идея передавать конфигурацию в переменных окружения есть в сборнике статей 12 factor app: https://12factor.net/ru/config
Мне эта идея не нравится, я считаю, что у нее есть недостатки, о которых авторы почему-то умалчивают (в итоге многие приходят к хранению перменных в .env файле, что не сильно отличается от обычного конфига). Но этот принцип хорошо работает в облачных системах, где твое приложение может сегодня запуститься на одном сервере, а завтра на другом. И где часто файловая система работает только на чтение, так что править конфиг нельзя.
Ты бы ссылки хоть давал, если упомниаешь какие-то статьи. А то непонятно, что смотреть.
По поводу приложения - по идее ошибки должны писаться в логи, и ты там можешщь их просмотреть (на продакшене не принято ошибки на всеобщее обозрение выставлять).
По поводу логов тут https://devcenter.heroku.com/articles/php-logging#logging-from-plain-php написано что ошибки должны идти в "heroku logs".
Соответственно тут дана команда просмотра логов: https://devcenter.heroku.com/articles/logging#view-logs
Попробуй с нее начать.
Также, можно получить доступ к консоли, если ты знаком с линуксовыми командами: https://devcenter.heroku.com/articles/getting-started-with-php#start-an-interactive-shell
Из консоли можно например попробовать соединиться с БД, выполнять какие-то SQL запросы.
Тут описано подключение к Postgres: https://devcenter.heroku.com/articles/getting-started-with-php#provision-a-database
Там тебе не дают привычных параметров соединения с БД (хост, пароль и тд) явно, а передают их в переменной окружения твоему приложению. Почитай в гугле, что такое переменные окружения, почитай мануал по getenv. Твое приложение, если оно запущено на хероку, должно брать параметры соединения из указанной в мануале переменной окружения. Там есть пример кода, но я бы его доработал - например, там нет никакой проверки на ошибки, нет действий в случае, если переменная не задана или пуста.
Я подозреваю, так сделано из-за динамичной природы хероку, твое приложение может запускаться на разных узлах, и база данных тоже может перемещаться между узлами, таким образом параметры подключения к БД меняются и их нельзя прописать в конфиг.
Идея передавать конфигурацию в переменных окружения есть в сборнике статей 12 factor app: https://12factor.net/ru/config
Мне эта идея не нравится, я считаю, что у нее есть недостатки, о которых авторы почему-то умалчивают (в итоге многие приходят к хранению перменных в .env файле, что не сильно отличается от обычного конфига). Но этот принцип хорошо работает в облачных системах, где твое приложение может сегодня запуститься на одном сервере, а завтра на другом. И где часто файловая система работает только на чтение, так что править конфиг нельзя.
Нужно чтобы не "почти все" номера проходили, а все. Там специально так много номеров, чтобы отлавливать неправильные регулярки.
В твоем случае я вижу такие проблемы:
- никак не задано точное число цифр в регулярке. [\d\s]{7,14} - это значит от 7 до 14 цифр и других знаков, а должно быть 7 или +8, за ней ровно 10 цифр
- используются противоречащие друг другу квантификаторы. Например: (\s?|...)+ "?" обозначает 0 или 1 повторение, "+" - 1 или больше. Так что ты хотел написать в итоге?
Если ты хотел написать "любое число скобок, минусов, пробелов" то лучше сделать это так:
- написать выражение для "одна скобка, минус или пробел"
- добаивить к нему квантификатор "от 0 до любого числа повторов"
А вообще, тут подошла бы такая регулярка:
- вначале идет +7 или 8
- за ней ровно 10 раз такое выражение: 1 цифра, за ней любое число минусов, скобок пробелов
Разумеется, копипастить выражение 10 раз не нужно, используй квантификатор.
>Если ты хотел написать "любое число скобок, минусов, пробелов"
Это и хотел.
>1 цифра, за ней любое число минусов, скобок пробелов
Почему не наоборот - сначала любое количество скобок, минусов и пробелов, а потом цифра? После +7 или 8 цифрты-то может и не быть.
То есть ты должен учиться выражать сложные шаблоны через сочетание простых условий, которые есть в регулярках, а именно:
- привязка к краям строки ^ и $
- привязка к краю слова \b
- один конкретный символ (a)
- один любой символ (.)
- один символ из определенной группы: \s, \d, \w
- один любой символ из набора [1234a-f]
- один любой символ, кроме указанных [^abc]
- одно из выражений: (X|Y|Z)
- повторение выражения указанное число раз: вопрос, звездочка, плюс, {N,M} в сочетании с круглыми скобками
Разумеется, ты должен знать все указанные выше конструкции наизусть.
Там еще есть другие конструкции (подробности в мануале http://php.net/manual/ru/pcre.pattern.php ) но для наших задач хватит того, что я привел
> Почему не наоборот
Можно и так, не принципиально. Я общую идею только привел, как сделать, чтобы было ровно 10 цифр. Главное, чтобы ты умел с помощью простых условий строить сложные шаблоны осознанно, а не наугад переставлял символы.
Можно сделать лучше. Во-первых,у тебя 2 раза повторяется +7 с небольшими изменениями.
Во-вторых, для квантификатора "от 0 до бесконечности повторов" есть более короткая запись.
Спасибо большое!
Так пройдет номер +78 и 10 цифр
>>1071378
Так пройдет номер с +8 в начале или с 7 без +.
>>1071262
Если у твоего сайта есть URL то сможешь. Но не надо тут устраивать флуд из кучи коротких сообщений.
>>1071223
Дело не в плейсхолдерах, проверь что ты куда там передаешь.
>>1071089
Трудно изучать Юи, если ты не изучил нормально объекты, классы и нейсмпейсы. Урок по основам ООП есть в учебнике в ОП посте, про неймспейсы доброанон тебе дал ссылку выше. И по хорошему, тебе бы не мешало решить задачку про студентов из ОП поста, чтобы освоиться с основами создания CRUD приложений. Тогда тебе многое было бы понятнее, мне кажется.
>>1071067
Вообще, тебе надо сначала прочесть документацию Юи по работе с формами. Я думаю, он умеет сам копировать данные из модели формы в модель сущности БД.
Разные кнопки можно различать, если дать им разные имена - нажатая кнопка передается в POST.
> Я не понимаю конструкцию $model->load(\Yii::$app->request->post()) && $model->validate()
Я тоже, по моему она неправильная
> Все поля и кнопки во вью должны быть между begin() - end(),
Ну ты изучи, что делают эти функции, какой HTML вставляют в шаблон.
> Как проверить, от какой кнопки пришло нажатие?
Ее имя будет содержаться в POST данных
> Как вообще вытащить из post данные в контроллере?
Они находятся в объекте request, изучи документацию по нему.
Так пройдет номер +78 и 10 цифр
>>1071378
Так пройдет номер с +8 в начале или с 7 без +.
>>1071262
Если у твоего сайта есть URL то сможешь. Но не надо тут устраивать флуд из кучи коротких сообщений.
>>1071223
Дело не в плейсхолдерах, проверь что ты куда там передаешь.
>>1071089
Трудно изучать Юи, если ты не изучил нормально объекты, классы и нейсмпейсы. Урок по основам ООП есть в учебнике в ОП посте, про неймспейсы доброанон тебе дал ссылку выше. И по хорошему, тебе бы не мешало решить задачку про студентов из ОП поста, чтобы освоиться с основами создания CRUD приложений. Тогда тебе многое было бы понятнее, мне кажется.
>>1071067
Вообще, тебе надо сначала прочесть документацию Юи по работе с формами. Я думаю, он умеет сам копировать данные из модели формы в модель сущности БД.
Разные кнопки можно различать, если дать им разные имена - нажатая кнопка передается в POST.
> Я не понимаю конструкцию $model->load(\Yii::$app->request->post()) && $model->validate()
Я тоже, по моему она неправильная
> Все поля и кнопки во вью должны быть между begin() - end(),
Ну ты изучи, что делают эти функции, какой HTML вставляют в шаблон.
> Как проверить, от какой кнопки пришло нажатие?
Ее имя будет содержаться в POST данных
> Как вообще вытащить из post данные в контроллере?
Они находятся в объекте request, изучи документацию по нему.
> код не смотрел прошлый, я его просто удалил, но судя по твоим замечаниям он был убог.
Ну вообще это может быть лишнее, я ведь писал замечания, чтобы ты их прочел, разобрался и учел в дальнейшей работе. Ну ладно, переписал так переписал.
browserstack можно (вроде бы) пользоваться бесплатно несколько раз, если зарегистрироваться. И можно даже без регистрации, если отправлять запрос с сайта modern.ie. Найдешь ссылку сам? Я проверил, работает.
Далее, сделаем простой тест. Возьмем и добавим на твою страницу section с HTML-кодом взятым отсюда http://motherfuckingwebsite.com/ или отсюда http://www.blindtextgenerator.com/snippets?snipps=EN-snippets-kafka . Или вообще очищаем содержимое body и вставляем туда HTML код.
Что мы должны увидеть? Аккуратно выглядящий и соответствующий стилю сайта текст. Абзацы не должны слипаться, списки должны быть как списки, ссылки как ссылки, курсив как курсив и так далее. Ты наверно сам знаешь, какие элементы бывают в HTML и как они должны выглядеть.
Что мы видим у тебя? https://pste.eu/p/HRFa.html - это явно нельзя назвать красиво выглядящим текстом в стиле сайта. Каша какая-то.
На динамических сайтах почти всегда контент добавляется через редактор в админке, и этот редактор выдает обычный HTML - с абзацами, списками, таблицами, картинками, заголовками. Нужно, чтобы тексты, которые будут править или добавлять редакторы, отображались хорошо и соответствовали стилю сайта.
Ну например, тут, я думаю, стоит сделать основной текст примерно таким шрифтом, который использован в блоке Consectetur.
То, что сейчас, никуда не годится, на твоей верстке нельзя нормально сделать сайт с произвольным контентом, понадобится много доработки. Ну представь, мы просто захотим добавить section с обычным списком - с твоими стилями он будет просто ужасно выглядеть. Это ненормально, что для добавления простого стандартного списка надо что-то править в CSS.
У тебя сейчас стили текста заданы только для абзаца внутри определенного блока: .service_item p { ... }. Это неправильно, нужно их задавать для html, чтобы они работали по умолчанию на всей странице.
Более того, ты исопльзуешь CSS reset, который обнуляет многие полезные стили. В итоге текст не выглядит как текст, а как нечитаемая каша. Если ты используешь CSS reset, ты обязан задать стили для всех элементов, для которых ты их сбросил тут в начале: https://theknacker.github.io/Webpaint/style.css (и если подумать, то окажется что выгоднее не использовать CSS reset вообще, чем сбрасывать стили и затем заново ставить им обратно те же значения).
Соответственно, нужно решить проблему со стилями, чтобы мы могли в любое место добавить текст со стандартными HTML элементами и он бы выглядел нормально.
В общем, это пока сделано слабо. Ты заботился о том, чтобы верстка выглядела похоже в браузере, но не подумал о том, как твою верстку будут интегрировать с системой управления контентом, что будет, если мы будем на ней делать правки и менять контент, что, если мы захотим добавить пару абзацев текста. Не беда, нужно просто использовать принципы, которые я описал выше, и все будет нормально.
Далее, у тебя там есть стили слишком широкого действия:
> a:not(.logo), label, img {
> transition: all 200ms linear
Этим ты ставишь транзишен для всех картинок и ссылок на сайте на все свойства. Такого не требовалось. Нужно сделать правило более специфичным, указав конкретные элементы и конкретные свойства.
Или тут:
> li a{
Ты вот так вот взял и переопределил стили для всех ссылок внутри любых списков на всем сайте. А ведь наверно тебе там надо было применить эти стили только к меню. Если кто-то завтра захочет добавить список со ссылками - у него все съедет и придется тратить время на правку.
Селекторы должны быть более точечного действия и применяться только к тем элементам, которые нужны.
Если тебе будет от этого легче, я иногда работаю с чужой версткой, которую делают "профессиональные" верстальщики, и там те же ошибки. Потому я и хочу тебя с самого начала научить их избегать.
Далее, ты там используешь width: fit-content, про который я первый раз слышу, и видимо не только я, так как он мало где поддерживается: https://developer.mozilla.org/ru/docs/Web/CSS/fit-content#Browser_compatibility и по моему ты даже используешь эту функцию неправильно.
Насчет тега cite я тоже не уверен - я тут почитал https://developer.mozilla.org/ru/docs/Web/HTML/Element/cite - можно ли его использовать для указания копирайта?
> input#graphic:checked ~ a:not([href="#graphic"]),
Это не подойдет, так как мы не можем менять ссылку на произвольную. И мы не можем поместить работу в 2 категории. Нужно использовать либо классы, либо специально придуманный data атрибут.
> <div class="service_image_android"></div>
Этот элемент не нужен, для картинки можно использовать псевдоэлемент.
Еще по моему на макете был курсив в шапке.
И вот тут вот проблема: безымянный див:
> <footer>
> <div>
div сам по себе не несет никакого смысла, он предназначен для нестандартных элементов, и смысл этих элементов задается id или классом. А ты не используешь тут класс и потом городишь какие-то трудные для понимания селекторы. Завтра кто-то добавит третий див, и все стили собъются потому что у тебя там используется :last-of-type.
То есть надо понимать, что верстка вряд ли будет всегда неизменной. Если сайт развивается, то на нем будут происходить разные изменения, добавление какого-то контента, перенос блоков в другое место, правки, и надо писать код так, чтобы не осложнять потом жизнь тем, кто будет делать эти правки. Соответственно селекторы должны быть максимально точечные и устойчивые к добавлению/переносу элементов.
Если тебе интересно, ты можешь еще почитать про методологию БЭМ, которая как раз придумана, чтобы упростить дальнейшую поддержку кода, чтобы верстку было как можно легче править в будущем: https://ru.bem.info/methodology/ У нас тут очень простая верстка, и БЭМ использовать не требуется, но если ты будешь верстать более сложные страницы, а тем более сайты с большим числом страниц, понимание БЭМ тебе пригодится. Прочитай, если есть время.
Насчет адаптивности: увы, пока есть недостатки. Ну например, в адаптивной версии шрифт h1/h2 в заголовке остается гиганстким, отступы большие (на маленьком экране наверно такая большая шапка и подвал не нужны).
Также у тебя нет метатега viewport ( http://frontender.com.ua/mobile-web/wtf-viewport/ ).
Или например, в мобильной версии у блоков с картинками (часы, андроид) можно было бы убрать или уменьшить картинки, чтобы эти блоки занимали меньше места. Они ведь там по большому счету только для красоты. Я имел в виду попробовать подумать над такими вещами, у тебя конечно есть в общем адаптация под размер экрана, но в идеале мы хотим не просто переставить исходные блоки вертикально, а подстроить верстку под особенности устройства, если экран маленький, то пользователю наверно не очень понравится пролистывать 10 страниц, которые получаются из-за большого шрифта и больших отступов.
Ну и еще, если у тебя есть картинки портфолио более высокого разрешения, я бы советовал в мобильной версии сделать их от края до края экрана, чтобы место не пропадало зря. Заодно изучи атрибут srcset и как можно указать несколько файлов картинок для разных разрешений. Обычная для десктопа и повышенного разрешения для мобильной версии.
Давай для начала с этим разберемся, а потом более внимательно остальное посмотрим.
Я бы конечно еще тебе хотел дать задачу исследовать варианты подключения SVG картинок, какие при этом возникают сложности, как они поддерживаются в разных браузерах, но не знаю, готов ли ты такую задачу сделать, есть ли время. Если есть, то потом я тебе объясню, что надо сделать и зачем.
> код не смотрел прошлый, я его просто удалил, но судя по твоим замечаниям он был убог.
Ну вообще это может быть лишнее, я ведь писал замечания, чтобы ты их прочел, разобрался и учел в дальнейшей работе. Ну ладно, переписал так переписал.
browserstack можно (вроде бы) пользоваться бесплатно несколько раз, если зарегистрироваться. И можно даже без регистрации, если отправлять запрос с сайта modern.ie. Найдешь ссылку сам? Я проверил, работает.
Далее, сделаем простой тест. Возьмем и добавим на твою страницу section с HTML-кодом взятым отсюда http://motherfuckingwebsite.com/ или отсюда http://www.blindtextgenerator.com/snippets?snipps=EN-snippets-kafka . Или вообще очищаем содержимое body и вставляем туда HTML код.
Что мы должны увидеть? Аккуратно выглядящий и соответствующий стилю сайта текст. Абзацы не должны слипаться, списки должны быть как списки, ссылки как ссылки, курсив как курсив и так далее. Ты наверно сам знаешь, какие элементы бывают в HTML и как они должны выглядеть.
Что мы видим у тебя? https://pste.eu/p/HRFa.html - это явно нельзя назвать красиво выглядящим текстом в стиле сайта. Каша какая-то.
На динамических сайтах почти всегда контент добавляется через редактор в админке, и этот редактор выдает обычный HTML - с абзацами, списками, таблицами, картинками, заголовками. Нужно, чтобы тексты, которые будут править или добавлять редакторы, отображались хорошо и соответствовали стилю сайта.
Ну например, тут, я думаю, стоит сделать основной текст примерно таким шрифтом, который использован в блоке Consectetur.
То, что сейчас, никуда не годится, на твоей верстке нельзя нормально сделать сайт с произвольным контентом, понадобится много доработки. Ну представь, мы просто захотим добавить section с обычным списком - с твоими стилями он будет просто ужасно выглядеть. Это ненормально, что для добавления простого стандартного списка надо что-то править в CSS.
У тебя сейчас стили текста заданы только для абзаца внутри определенного блока: .service_item p { ... }. Это неправильно, нужно их задавать для html, чтобы они работали по умолчанию на всей странице.
Более того, ты исопльзуешь CSS reset, который обнуляет многие полезные стили. В итоге текст не выглядит как текст, а как нечитаемая каша. Если ты используешь CSS reset, ты обязан задать стили для всех элементов, для которых ты их сбросил тут в начале: https://theknacker.github.io/Webpaint/style.css (и если подумать, то окажется что выгоднее не использовать CSS reset вообще, чем сбрасывать стили и затем заново ставить им обратно те же значения).
Соответственно, нужно решить проблему со стилями, чтобы мы могли в любое место добавить текст со стандартными HTML элементами и он бы выглядел нормально.
В общем, это пока сделано слабо. Ты заботился о том, чтобы верстка выглядела похоже в браузере, но не подумал о том, как твою верстку будут интегрировать с системой управления контентом, что будет, если мы будем на ней делать правки и менять контент, что, если мы захотим добавить пару абзацев текста. Не беда, нужно просто использовать принципы, которые я описал выше, и все будет нормально.
Далее, у тебя там есть стили слишком широкого действия:
> a:not(.logo), label, img {
> transition: all 200ms linear
Этим ты ставишь транзишен для всех картинок и ссылок на сайте на все свойства. Такого не требовалось. Нужно сделать правило более специфичным, указав конкретные элементы и конкретные свойства.
Или тут:
> li a{
Ты вот так вот взял и переопределил стили для всех ссылок внутри любых списков на всем сайте. А ведь наверно тебе там надо было применить эти стили только к меню. Если кто-то завтра захочет добавить список со ссылками - у него все съедет и придется тратить время на правку.
Селекторы должны быть более точечного действия и применяться только к тем элементам, которые нужны.
Если тебе будет от этого легче, я иногда работаю с чужой версткой, которую делают "профессиональные" верстальщики, и там те же ошибки. Потому я и хочу тебя с самого начала научить их избегать.
Далее, ты там используешь width: fit-content, про который я первый раз слышу, и видимо не только я, так как он мало где поддерживается: https://developer.mozilla.org/ru/docs/Web/CSS/fit-content#Browser_compatibility и по моему ты даже используешь эту функцию неправильно.
Насчет тега cite я тоже не уверен - я тут почитал https://developer.mozilla.org/ru/docs/Web/HTML/Element/cite - можно ли его использовать для указания копирайта?
> input#graphic:checked ~ a:not([href="#graphic"]),
Это не подойдет, так как мы не можем менять ссылку на произвольную. И мы не можем поместить работу в 2 категории. Нужно использовать либо классы, либо специально придуманный data атрибут.
> <div class="service_image_android"></div>
Этот элемент не нужен, для картинки можно использовать псевдоэлемент.
Еще по моему на макете был курсив в шапке.
И вот тут вот проблема: безымянный див:
> <footer>
> <div>
div сам по себе не несет никакого смысла, он предназначен для нестандартных элементов, и смысл этих элементов задается id или классом. А ты не используешь тут класс и потом городишь какие-то трудные для понимания селекторы. Завтра кто-то добавит третий див, и все стили собъются потому что у тебя там используется :last-of-type.
То есть надо понимать, что верстка вряд ли будет всегда неизменной. Если сайт развивается, то на нем будут происходить разные изменения, добавление какого-то контента, перенос блоков в другое место, правки, и надо писать код так, чтобы не осложнять потом жизнь тем, кто будет делать эти правки. Соответственно селекторы должны быть максимально точечные и устойчивые к добавлению/переносу элементов.
Если тебе интересно, ты можешь еще почитать про методологию БЭМ, которая как раз придумана, чтобы упростить дальнейшую поддержку кода, чтобы верстку было как можно легче править в будущем: https://ru.bem.info/methodology/ У нас тут очень простая верстка, и БЭМ использовать не требуется, но если ты будешь верстать более сложные страницы, а тем более сайты с большим числом страниц, понимание БЭМ тебе пригодится. Прочитай, если есть время.
Насчет адаптивности: увы, пока есть недостатки. Ну например, в адаптивной версии шрифт h1/h2 в заголовке остается гиганстким, отступы большие (на маленьком экране наверно такая большая шапка и подвал не нужны).
Также у тебя нет метатега viewport ( http://frontender.com.ua/mobile-web/wtf-viewport/ ).
Или например, в мобильной версии у блоков с картинками (часы, андроид) можно было бы убрать или уменьшить картинки, чтобы эти блоки занимали меньше места. Они ведь там по большому счету только для красоты. Я имел в виду попробовать подумать над такими вещами, у тебя конечно есть в общем адаптация под размер экрана, но в идеале мы хотим не просто переставить исходные блоки вертикально, а подстроить верстку под особенности устройства, если экран маленький, то пользователю наверно не очень понравится пролистывать 10 страниц, которые получаются из-за большого шрифта и больших отступов.
Ну и еще, если у тебя есть картинки портфолио более высокого разрешения, я бы советовал в мобильной версии сделать их от края до края экрана, чтобы место не пропадало зря. Заодно изучи атрибут srcset и как можно указать несколько файлов картинок для разных разрешений. Обычная для десктопа и повышенного разрешения для мобильной версии.
Давай для начала с этим разберемся, а потом более внимательно остальное посмотрим.
Я бы конечно еще тебе хотел дать задачу исследовать варианты подключения SVG картинок, какие при этом возникают сложности, как они поддерживаются в разных браузерах, но не знаю, готов ли ты такую задачу сделать, есть ли время. Если есть, то потом я тебе объясню, что надо сделать и зачем.
Если JSON не удалось раскодировать, json_encode вернет null. ты должен проверять этот случай. Также, посмотри, нет ли каких ошибок в логах веб-сервера или включи их отображение.
Алсо тут ошибка:
> data: 'json =' + JSON.stringify(json)
Спецсимволы должны кодироваться процентным кодированием при использовании метода application/x-www-url-encoded или как-то так. У меня есть урок https://github.com/codedokode/pasta/blob/master/network/urls.md и там это мельком упомянуто (там про query string, но принцип тот же):
> параметры (строка запроса, query string) - может содержать дополнительные параметры, которые будут переданы на сервер. Обычно параметры пишутся через знак =, и разделяются символом &, например ?a=1&b=2&c=hello%20world. Спецсимволы в именах и значениях параметров надо кодировать процентным кодированием. В примере выше в фразе hello world пробел (который нельзя использовать в ссылке) закодирован кодом %20.
Ну и правильно тебе сказали, изучить документацию по jQuery так как там есть более удобные способы передавать значения из формы или из массива. Ты навелосипедил какой-то кривой код.
>>1070599
У тебя переменная окружения, которая указана в коде, задана? Видна ли она в PHP? Проверь через getenv или phpinfo() например.
>>1070597
Можно сделать так:
- в начале идет +7 или 8
- за ним ровно 10 раз повторяется такое выражение: "любое число минусов, скобок, пробелов в любом порядке, за ним ровно одна цифра". Повтор задается через квантификатор конечно.
>>1070552
masked input мне крайне не нравятся, так как в них практически всегда безнадежно сломано редактирование, вставка и тд. Плюс ты не всегда можешь угадать, в каком формате будет номер, особенно когда стран много. Потому, возможно лучше на сервере как-тог нормализовать номер.
> Можно ли без своей реализации сделать на yii2 чтобы и httpBasicAuth работал и обычная браузерная аутентификация основанная на сессии? Мне надо чтобы сайт работал в двух режимах: и как обычный сайт и как API если передать определенный параметр, вот встал вопрос реализации аутентификации по токенам.
Начать нужно с изучения документации по авторизации/аутентификации в Юи и затем смотреть, как это реализовать. Она там настраивается, можно писать свои классы, так что наверно это возможно.
Если JSON не удалось раскодировать, json_encode вернет null. ты должен проверять этот случай. Также, посмотри, нет ли каких ошибок в логах веб-сервера или включи их отображение.
Алсо тут ошибка:
> data: 'json =' + JSON.stringify(json)
Спецсимволы должны кодироваться процентным кодированием при использовании метода application/x-www-url-encoded или как-то так. У меня есть урок https://github.com/codedokode/pasta/blob/master/network/urls.md и там это мельком упомянуто (там про query string, но принцип тот же):
> параметры (строка запроса, query string) - может содержать дополнительные параметры, которые будут переданы на сервер. Обычно параметры пишутся через знак =, и разделяются символом &, например ?a=1&b=2&c=hello%20world. Спецсимволы в именах и значениях параметров надо кодировать процентным кодированием. В примере выше в фразе hello world пробел (который нельзя использовать в ссылке) закодирован кодом %20.
Ну и правильно тебе сказали, изучить документацию по jQuery так как там есть более удобные способы передавать значения из формы или из массива. Ты навелосипедил какой-то кривой код.
>>1070599
У тебя переменная окружения, которая указана в коде, задана? Видна ли она в PHP? Проверь через getenv или phpinfo() например.
>>1070597
Можно сделать так:
- в начале идет +7 или 8
- за ним ровно 10 раз повторяется такое выражение: "любое число минусов, скобок, пробелов в любом порядке, за ним ровно одна цифра". Повтор задается через квантификатор конечно.
>>1070552
masked input мне крайне не нравятся, так как в них практически всегда безнадежно сломано редактирование, вставка и тд. Плюс ты не всегда можешь угадать, в каком формате будет номер, особенно когда стран много. Потому, возможно лучше на сервере как-тог нормализовать номер.
> Можно ли без своей реализации сделать на yii2 чтобы и httpBasicAuth работал и обычная браузерная аутентификация основанная на сессии? Мне надо чтобы сайт работал в двух режимах: и как обычный сайт и как API если передать определенный параметр, вот встал вопрос реализации аутентификации по токенам.
Начать нужно с изучения документации по авторизации/аутентификации в Юи и затем смотреть, как это реализовать. Она там настраивается, можно писать свои классы, так что наверно это возможно.
Боюсь что это баги соответствюущих сервисов, где криво настроен PHP. Попробуй еще другие какие-нибудь. Ну вот например https://repl.it/languages/php - тут все работает или 3v4l.org.
Или установи себе PHP на компьютер, и запускай встроенный в PHP сервер, и смотри результат в браузере, инструкции где-то в ОП посте.
Благодарю ОП, именно это я и имел ввиду когда говорил про стиль который действует на всех страницах. Я только под конец понял что ошибся. Методологию я вот собирался на днях изучать, ровно как и поработать с селекторами, чтобы лучше их понять.
>Насчет тега cite я тоже не уверен
Я думал что этот тег можно было для копирайта использовать. Заменю на <i>, пожалуй?
>нет метатега viewport
Я его хотел добавить, но подумал, что пользователь может увеличить страницу в случае чего. Судя по статье так делать нежелательно.
Еще проблема есть одна, во всех браузерах все отображается верно, но в Mozilla и ее мобильной версии один <div> элемент перед названием города съезжает вниз, т.е посередине, пока не знаю как фиксить.
Да ОП помоги чем сможешь. И еще хотел спросить, где все эти ресурсы искать? Я с книг беру всякие полезные сайты и т.д Бойлер плейты всякие итд. А у тебя прям набор какой то, опыт? Во всяком случае объясни, это все по мере работы находится?
спасибо
Поясните почему форма работает некорректно, а именно почему постоянно срабатывает 7 строка? Вроде корректно ввожу данные, а проверка проходит не так как положено.
https://ideone.com/3rQ5Cn
Теги i и b поменяли свое значение в HTML5. В любом случае, они тут не подходят, используй просто div с классом.
meta viewport сам по себе не блокирует зум. Он говорит мобильному браузеру, что страница оптимизирована под мобильные устройства и задает настройки для ее отображения (если тега нет, браузер думает, что это страница, не знающая про мобильные браузеры). Без него мобильное устройство отобразит десктопную широкую версию сайта в уменьшенном масштабе. Ты можешь открыть свой сайт в Хроме или ФФ и включить там в отладчике режим отладки адаптивной версии и увидишь. Ну или на реальном устройстве.
> но в Mozilla и ее мобильной версии один <div> элемент перед названием города съезжает вниз, т.е посередине, пока не знаю как фиксить.
Что отладчик показывает? Какие стили применены? Где она съезжает?
> Да ОП помоги чем сможешь.
Ты задавай конкретные вопросы тогда.
> И еще хотел спросить, где все эти ресурсы искать?
Информацию по HTML/CSS свойствам я ищу со словом MDN. например "mdn flexbox"
Учить наизусть все теги конечно не надо, просто достаточно прочитать список 1 раз, чтобы знать, что есть, что в принципе возможно.
Также есть дайджест новостей в таком формате https://habrahabr.ru/company/zfort/blog/331168/
Также есть caniuse для поиска информации о поддержке браузерами разных технологий.
Также, когда-то я читал еще блоги верстальщиков, но не уверен, что те статьи сейчас актуальны.
Если есть очень большое желание можно почитать спецификации по HTML/CSS (осторожно, много букв, но зато все очень подробно расписано). Я в них обычно ищу какие-то спорные вопросы, про которые нигде толком не написано. Ну вот к примеру, тут автоматическое определение размеров элементов в CSS очень подробно расписано: https://www.w3.org/TR/CSS2/visudet.html#q10.0
> Я с книг беру всякие полезные сайты и т.д Бойлер плейты всякие итд.
Ну это само по себе не плохо, но ты должен тогда все незнакомые теги и атрибуты погуглить, разобраться, что они делают, а не копировать бездумно.
> набор какой то, опыт?
Ну я версткой занимался еще во времена когда надо было старые ИЕ поддерживать, и документации тогда много читал.
Обычно, когда я сталкивался с чем-то, чего точно не знаю (например: как отцентрировать и отмасштабировать картинку, как сделать поддержку экранов с разным DPI), я гуглю статьи и решения, а потом уже читаю документацию, чтобы подробнее разобраться. И в итоге получаю сравнение разных методов, с достоинствами и недостатками каждого, и из этого выбираю.
Если ты будешь изучать все, с чем сталкиваешься, разбираться, а не просто копировать, браться за более сложные вещи, то я думаю, со временем твой уровень будет расти. Если захочется, можно будет после этого макета найти что-нибудь посложнее, или ты сам можешь взять, отскриншотить любой сайт и попробовать качественно сверстать все. А я могу потом посмотреть и дать какие-то советы и замечания.
Теги i и b поменяли свое значение в HTML5. В любом случае, они тут не подходят, используй просто div с классом.
meta viewport сам по себе не блокирует зум. Он говорит мобильному браузеру, что страница оптимизирована под мобильные устройства и задает настройки для ее отображения (если тега нет, браузер думает, что это страница, не знающая про мобильные браузеры). Без него мобильное устройство отобразит десктопную широкую версию сайта в уменьшенном масштабе. Ты можешь открыть свой сайт в Хроме или ФФ и включить там в отладчике режим отладки адаптивной версии и увидишь. Ну или на реальном устройстве.
> но в Mozilla и ее мобильной версии один <div> элемент перед названием города съезжает вниз, т.е посередине, пока не знаю как фиксить.
Что отладчик показывает? Какие стили применены? Где она съезжает?
> Да ОП помоги чем сможешь.
Ты задавай конкретные вопросы тогда.
> И еще хотел спросить, где все эти ресурсы искать?
Информацию по HTML/CSS свойствам я ищу со словом MDN. например "mdn flexbox"
Учить наизусть все теги конечно не надо, просто достаточно прочитать список 1 раз, чтобы знать, что есть, что в принципе возможно.
Также есть дайджест новостей в таком формате https://habrahabr.ru/company/zfort/blog/331168/
Также есть caniuse для поиска информации о поддержке браузерами разных технологий.
Также, когда-то я читал еще блоги верстальщиков, но не уверен, что те статьи сейчас актуальны.
Если есть очень большое желание можно почитать спецификации по HTML/CSS (осторожно, много букв, но зато все очень подробно расписано). Я в них обычно ищу какие-то спорные вопросы, про которые нигде толком не написано. Ну вот к примеру, тут автоматическое определение размеров элементов в CSS очень подробно расписано: https://www.w3.org/TR/CSS2/visudet.html#q10.0
> Я с книг беру всякие полезные сайты и т.д Бойлер плейты всякие итд.
Ну это само по себе не плохо, но ты должен тогда все незнакомые теги и атрибуты погуглить, разобраться, что они делают, а не копировать бездумно.
> набор какой то, опыт?
Ну я версткой занимался еще во времена когда надо было старые ИЕ поддерживать, и документации тогда много читал.
Обычно, когда я сталкивался с чем-то, чего точно не знаю (например: как отцентрировать и отмасштабировать картинку, как сделать поддержку экранов с разным DPI), я гуглю статьи и решения, а потом уже читаю документацию, чтобы подробнее разобраться. И в итоге получаю сравнение разных методов, с достоинствами и недостатками каждого, и из этого выбираю.
Если ты будешь изучать все, с чем сталкиваешься, разбираться, а не просто копировать, браться за более сложные вещи, то я думаю, со временем твой уровень будет расти. Если захочется, можно будет после этого макета найти что-нибудь посложнее, или ты сам можешь взять, отскриншотить любой сайт и попробовать качественно сверстать все. А я могу потом посмотреть и дать какие-то советы и замечания.
Насчет тегов i и b, решил дополнить. В HTML4 это были презентационные теги, задававшие внешний вид элемента (курсив и жирный шрифт). В HTML5 наконец-то решили покончить с презентационными тегами (внешний вид задается в CSS, а не в HTML) и поменяли им смысл. А также ввели strong и em которые задают смысловое выделение текста.
Чтобы сделать нормальные стили для текста, тебе надо начать с текста. То есть просто временно закомментировать контент и вместо него вставить простой текст с стандартными HTML тегами.
Затем:
- если reset не используется, задать на элементе html или body шрифт, межстрочный интервал, цвет, фон, чтобы они соответствовали стилю сайта. Шрифт и цвет наследуется, потому его достаточно задать на корневом элементе. Можно еще немного подправить стили стандартных элементов, например, заголовки, ссылки, отступы, так, чтобы они соответствовали дизайну и гармонично смотрелись.
- если reset используется, то придется восстанавливать большинство сброшенных стилей.
После того как обычный текст отображается нормально, можно его убрать и дальше делать стили для элементов с макета. Нужно писать таргетированные стили, которые применяются например к конкретному классу. Не надо ради картинки в портфолио или меню обнулять стили у всех картинок или списков на сайте.
Тогда скорее всего все будет нормально.
ОП, а я правильно понял про механическую адаптацию, или у меня как раз она получилась? Не могу понять верно или нет.
Я дегенерат ^^
if ($_POST['city'] == NULL || $_POST['street'] == NULL || $_POST['house'] == NULL || $_POST['apartment'] == NULL || $_POST['size'] == NULL || $_POST['weight'] == NULL){
print "<br><b>Форма заполнена некорректно, попробуйте еще!</b>" . showForm();
Кстати я как раз изучение html и css со спецификации начинал, каждый день их вкладки открыты. Значит я в правильном направлений. ОП если сможешь ответь на мой вопрос выше.
З.Ы Отладчик посмотрю.
Механическая адаптация это когда особо не адаптируют страницу, а просто выстраивают блоки вертикально, чтобы они влезали на узкий экран. При нормальной адаптации нужно внимательно смотреть на страницу, пробовать ее использовать, анализирвать неудобные места, в общем почти что дизайнить ее с нуля.
Ты можешь попробовать посравнивать например мобильные версии каких-то известных сайтов с десктопными. Ну вот букинг (booking.com) например - там вообще все переделано, там даже не адаптивная, а отдельная версия. Ну или твиттер - он тоже по-другому выглядит (помню, что мне чем-то не понравился, но не помню чем).
>>1071434
Ну вот и хорошо, это значит что технические вещи ты понимаешь, но теперь надо разобраться с вопросом удобства пользования, удобства поддержки программистами.
>>1071414
>>1071415
ОП я исправил версию на мозилле, там почему то адресный div элемент внутри ссылки ни в какую не хочет расширяться в fit-content, вот оно как раз твое замечание. В общем я так решил, пока буду пытаться максимально ужать классы и более логичней и удобней для всех. Методологию, почитать ресурсы, так же попробую поверстать еще странички и.т.д
Думаю не буду тебе надоедать своим тупоумием, если уж совсем сложно будет спрошу. И еще - Спасибо за то что ты делаешь.
Есть JS скрипт с "отзывами": https://ideone.com/BWZEXS
Нужно его добавить на страничку с отзывами, к примеру http://www.site.ru/otzyvy/
А он добавляется на все страницы сразу, которые есть на этом сайте.
Добавляю в xml файлик который отвечает на верстку html, не пойму как сделать что бы этот скрипт был на определенной странице.
если это важно, то движок umi.cms
Апдейт по Moz:
В элементе adr::before когда я ставлю ему контент иконки, он перестает быть inline-block элементом, фиксится либо изменением ширины, в результате чего в IE11 SVG элемент сразу масштабируется до нее и становится больших размеров, но в мозилле и хроме все в порядке. Я пробовал переделать svg с ФШ, не помогло. В общем чтобы элемент не перескакивал на след. строчку, приходится ему ставить display:inline-block;
заменяю начальные буквы в строке на заглавные:
$regexp = "/^([а-яёa-z])/u";
вопрос: я могу прямо в прегреплейсе сделать как-нибудь конструкцию вида:
$value = preg_replace($regexp, "strtoopper($1)", $textt);
или мне нужно выковыривать букву регуляркой, потом уже не регуряркой поднимать регистр, и обратно вставлять? Можно ли в одной строчке сделать автозамену?
я запускаю, не работает. Мне нужно понять, не работает потому что ЭТО В ПРИНЦИПЕ НЕЛЬЗЯ И ТАК НЕ ДЕЛАЕТСЯ, или не работает потому что МЕТОД ВЕРНЫЙ, НО СЕЙЧАС ЕСТЬ ОШИБКА В СИНТАКСИСЕ, И ЕСЛИ ЕЕ ИСПРАВИТЬ, ТО ВСЕ ЗАРАБОТАЕТ.
Можно же мне сейчас сказать, что это невозможно, чтобы я не тратил время зря и использовал другой метод
Как это реализовать без регистрации и смс человеку с опытом в полтора часа?
В гугле советуют писать свой парсер из говна и палок.
Занимался ли кто такими хитрыми делами товары, мейлы, телефоны, небо, Аллах? Мб есть чего готового для этих целей?
То есть посидеть, поковыряться и разобраться у тебя времени нет, а сидеть тут и ждать, пока ответят - есть? Ну ок.
Я не спец в ПХП, но если strtoupper() возвращает строку, а $0 ждет строку, то никаких препятствий я не вижу.
>я запускаю, не работает
У тебя в примере минимум две опечатки. Может, поэтому и не работает? Опять же, интерпретатор тебе ошибки писать должен, не бывает так, что "просто не работает".
Тебе нужен preg_replace_callback.
То, что ты хочешь сделать, раньше делалось специальным флагом, но позже это было признано опасным способом, вызывающим уязвимости.
Зачем strtoupper($1) в кавычках? У тебя сейчас буквально первая буква строки заменяется на подстроку "strtoopper($1)", я сомневаюсь, что ты именно этого добивался.
Как же я умиляюсь с таких мудаков как ты.
Во-первых, я спрашивал совета у знающего анона, а не у мимокрокодила, который никак в сабже не разбирается, но лезет учить.
Во-вторых, не смешивай понятия "просиди и подумай" с "трать все время на заведомо неправильное решение просто потому что снобам от программирования, сидящим в треде помощи, лень написать да или нет"
А вообще ты напоминаешь мне дяденьку-председателя колхоза из старого баяна, где солдаты-срочники строили гараж для сельхоз-техники, затаскивали огромную плиту на опорные балки вручную, как рабы, рискуя быть придавленными, а он каждый день приходил и сидел - смотрел на них. И под конец, когда балку затащили, председатель подошел и сказал "ребят, очень низко сделали, трактор не проедет". И на все вопросы "а что же ты, дядя, до этого момента молчал?", он отвечал "так я в отпуске был"
Так что будь добр, просто не лезь в то, в чем не разбираешься
>Зачем strtoupper($1) в кавычках?
ты у мамы не очень умный, да? Потому что без кавычек ideone выдает ПУСТУЮ ошибку без ничего, по которой ничего не понять. Или ты думаешь ты единственный, который подумал убрать ковычки, дыа?
Вот тебе спасибо, помогло
>>взял функцию в кавычки
>>удивляется почему не работает
>>мааам ну он дурак ну скажи ему мааам
Ты идиот?
дажи ни знаю, кто хуже, агрессивный мимокрокодил или дурачок, который считает себя невозмутимым Буддой, надрачивая тем самым свое чсв и самоутверждаясь засчет новичков
Имеешь право думать так, как умеешь. Пока я говорю, что твоя агрессия бесполезна.
>На вход скрипта дан введенный пользователем номер телефона в виде 8-911-404-44-11 или +7(812)6786767 (в начале 8 или +7, потом идут 10 цифр и, возможно, какие-то символы). То есть, как и в прошлой задаче, человек вводит номер как хочет. Надо проверить номер на правильность и привести любой номер к единому формату 89114044411 (то есть, заменить +7 на 8 и выкинуть весь мусор вроде пробелов, скобок и минусов, кроме цифр)
А эта задача вообще решаема в один проход? То есть в два прохода я ее решить могу - заменить сначала +7 на 8, а потом вырезать все не-цифры. Но как это сделать в один проход - ума не приложу.
Не, это другое. Распарсить номер и заменить символы - разные вещи.
Ну так это тоже в два прохода - ты же дважды preg_replace вызываешь. Так я тоже могу. Ты за один вызов реши.
Прости, няша, я не знаю. Подожди опа, он вечером вроде приходит. После двеннадцати.
Это значит "тут должна быть любая цифра от 0 до 9 ровно один раз". В двадцатичетырехчасовом формате времени на этом месте может быть любая цифра от 0 до 9.
Как вывести именно значение массива?
>зачем тогда число 12 стоит до этого ?
По аналогии с 0-9 - это будет любая цифра в диапазоне от 1 до 2.
мимо опыт пхп 14 минут
Там нету никаких знаков. Не 1-2, а просто 12.
Ладно. Позже попробую понять снова. Всем спасибо за отклик.
Квадратные скобки значат "один любой из указанных символов". Ну например [123456] значит одна цифра от 1 до 6.
При этом можно использовать минус для указания диапазона и [1-6] это то же самое, что [123456].
Если первый символ это ^ то смысл меняется на противоположный и скобки значат "один любой символ кроме указанных", например [^1-9ab] значит любой символ, кроме цифр 1-9 и букв a, b.
Мануал http://php.net/manual/ru/regexp.reference.character-classes.php
спс
Понял, спасибо ольшое
Немного знаю пхп, но никогда не работал с API социальных сетей, и всякие "токены для идентификации", "асинхронный обмен данными" внушают мне неподдельный ужас. Официальные гайды не объясняют, "куда вообще всё это вбивать и что нахуй делать шоб стало заебись", примеров мало, практики, скорее справочники какие-то, а не гайды. Ютуб наоборот заполнен всяким бредом вроде "поклацай клавишами в МэниБот или Снапчат, станет охуительно". Интересующие платформы: ФБ, ВК, Телеграм, Твиттер. Хочется поделать ботов-автоответчиков, реагрирующих на присылаемый текст и нетекст (схоронял присылаемые пикчи, например, или присылал обратно черно-белую версию, или конвертировал форматы), мб автопостеры какие-то или парсеры. Как, имея хостинг с пыхом, все это делать, есть какие-то Quick Startы?
нужно реальное знание РНР -- и тогда все официальные гайды соц.сетей внезапно просто и понятно предоставляют всё что нужно.
А для дураков -- бесконечно-бесполезные тренинги, курсы и видосики.
Предлагали в конструкторе основного контроллера (Controller.php) - не подходит ибо некоторые унаследованные контроллеры перегружают конструктор (и лезть туда не нужно)
Во-первых, API соцсетей основаны на HTTP, потому стоит в общем прочитать про этот протокол, чтобы знать его особенности и может тогда документация будет понятнее. Вот урок (если что-то там непонятно или плохо объяснено, напиши): https://github.com/codedokode/pasta/blob/master/network/http.md
Заодно прочитай на всякий случай урок про URL : https://github.com/codedokode/pasta/blob/master/network/urls.md
Как я уже написал выше, API используют протокол HTTP и чтобы вызывать методы API, ты должен слать HTTP-запросы на сервер и принимать ответы. Для этого тебе нужна программа HTTP-клиент.
Во-первых, если ты хочешь слать запросы вручную (например для тестирования), то есть такие программы-клиенты:
- curl - для командной строки
- программы с графическим интерфейсом ищутся по словам "http gui client"
Отправляя запросы вручную, ты можешь проверить как работает API. Но разумеется, дальше тебе нужно будет отправлять запросы автоматически из программы. Для этого тебе нужна будет библиотека-HTTp-клиент.
В PHP есть расширение curl, но оно довольно неудобное для использования. Гораздо удобнее использовать ООП-библиотеки вроде Guzzle. есть и другие библиотеки, они ищутся по словам "php http client library", еще можно поискать
- на phptrends: https://phptrends.com/search?q=http+client
- в packagist: https://packagist.org/?q=http client&p=0
Выбрав библиотеку и разобравшись с ней, ты сможешь использовать внешнее API из своего скрипта.
АПИ с авторизацией могут быть сложными для новичка, потому потренироваться можно на более простом АПИ, не требующем авторизации, например на АПИ геокодера из яндекс-карт: https://tech.yandex.ru/maps/doc/geocoder/desc/concepts/About-docpage/
Также, есть специальный сайт, который отдает заранее известные HTTP ответы который можно использовать для тренировки: http://httpbin.org/
Во-первых, API соцсетей основаны на HTTP, потому стоит в общем прочитать про этот протокол, чтобы знать его особенности и может тогда документация будет понятнее. Вот урок (если что-то там непонятно или плохо объяснено, напиши): https://github.com/codedokode/pasta/blob/master/network/http.md
Заодно прочитай на всякий случай урок про URL : https://github.com/codedokode/pasta/blob/master/network/urls.md
Как я уже написал выше, API используют протокол HTTP и чтобы вызывать методы API, ты должен слать HTTP-запросы на сервер и принимать ответы. Для этого тебе нужна программа HTTP-клиент.
Во-первых, если ты хочешь слать запросы вручную (например для тестирования), то есть такие программы-клиенты:
- curl - для командной строки
- программы с графическим интерфейсом ищутся по словам "http gui client"
Отправляя запросы вручную, ты можешь проверить как работает API. Но разумеется, дальше тебе нужно будет отправлять запросы автоматически из программы. Для этого тебе нужна будет библиотека-HTTp-клиент.
В PHP есть расширение curl, но оно довольно неудобное для использования. Гораздо удобнее использовать ООП-библиотеки вроде Guzzle. есть и другие библиотеки, они ищутся по словам "php http client library", еще можно поискать
- на phptrends: https://phptrends.com/search?q=http+client
- в packagist: https://packagist.org/?q=http client&p=0
Выбрав библиотеку и разобравшись с ней, ты сможешь использовать внешнее API из своего скрипта.
АПИ с авторизацией могут быть сложными для новичка, потому потренироваться можно на более простом АПИ, не требующем авторизации, например на АПИ геокодера из яндекс-карт: https://tech.yandex.ru/maps/doc/geocoder/desc/concepts/About-docpage/
Также, есть специальный сайт, который отдает заранее известные HTTP ответы который можно использовать для тренировки: http://httpbin.org/
ты одинок?
Погоди-погоди, это все примерно понятно, спасибо, анон, но мне нужен именно кьюик старт по конкретному апи соцсетки, пусть даже и не сложному для начала. В теории я понимаю и про заголовки http, и даже курлом когда-то пользовался, из пыха header'ы и setcookie вызывал, но читаю про АПИ и охуеваю. И даже не только про апи, а хотя бы про
>такие программы-клиенты
https://habrahabr.ru/post/271687/
Например в этой статье мне по-отдельности все более-менее понятно, если посимвольно буквально разбираться, но в сумме "блядь блядь как сложно нахуй вообще так сделано блядь что зачем это господи что за хуйня вообще ааааа". А в случае, когда я заделал, например, в
>в МэниБот или Снапчат
основу и теперь хочу добавить кастомные команды, выводящие ответы из моих скриптов (в зависимости от посланных командой этим скриптам данных), тут я вообще не понимаю даже, в какую сторону копать.
Если ты понимаешь HTTP, то чтения документации должно быть достаточно. API это всего лишь набор точек к которым можно отправлять HTTP запросы, тебе надо просто не спеша все прочесть и понять, какие именно запросы подойдут для твоей задачи. Теперь уже я не понимаю, что именно тебе непонятно.
> нужен именно кьюик старт
Зачем он нужен если есть документация? Ну хотя, в документации обычно бывают примеры кода.
> Например в этой статье мне по-отдельности все более-менее понятно, если посимвольно буквально разбираться, но в сумме "блядь блядь как сложно нахуй вообще так сделано блядь что зачем это господи что за хуйня вообще ааааа".
Мне идея понятна из первого абзаца. Есть много разных библиотек-HTTP-клиентов, и если ты использовал в своей программе одну, ты не можешь заменить ее на другую, так как у них разный интерфейс, разные классы, разные методы. Там люди пытаются придумать общий интерфейс, так, что ты пишешь код под него и после этого можешь легко подключить любую совместимую библиотеку и твой код автоматически окажется с ней тоже совместимым.
В статье нет конкретики, но если перейти по ссылкам, почитать документацию этого стандарта (?), то думаю станет понятно.
Там еще упоминается PSR-7, это интерфейсы дял объектов, представляющих HTTP запрос или ответ. Если ты знаком с ООП и если ты почитаешь документацию, то тебе все станет понятно, я думаю.
Дальше есть немного сложных моментов - про асинхронные запросы и discovery - это рассчитано на тех людей, кто с ними сталкивался и понимает о чем речь. Если ты не сталкивался, то конечно, статья ничем тут не помогает.
То есть у меня ощущение, что ты берешься за статью, но не знаешь чего-то, что надо знать перед тем как ее читать. Условно говоря, статья рассчитана на тех, кто знает ООП и работал с HTTP клиентами. И если ты хочешь разобраться, то придется брать каждое непонятное название, переходить по ссылке, разбираться, читать документацию.
Короткого пути нет. Точнее, есть один - нанять кого-то, кто умеет делать то, что тебе нужно. Или же разбираться постепенно самому.
> хочу добавить кастомные команды, выводящие ответы из моих скриптов
Для этого тебе сначала полностью разобраться как работает существующий код.
Если ты понимаешь HTTP, то чтения документации должно быть достаточно. API это всего лишь набор точек к которым можно отправлять HTTP запросы, тебе надо просто не спеша все прочесть и понять, какие именно запросы подойдут для твоей задачи. Теперь уже я не понимаю, что именно тебе непонятно.
> нужен именно кьюик старт
Зачем он нужен если есть документация? Ну хотя, в документации обычно бывают примеры кода.
> Например в этой статье мне по-отдельности все более-менее понятно, если посимвольно буквально разбираться, но в сумме "блядь блядь как сложно нахуй вообще так сделано блядь что зачем это господи что за хуйня вообще ааааа".
Мне идея понятна из первого абзаца. Есть много разных библиотек-HTTP-клиентов, и если ты использовал в своей программе одну, ты не можешь заменить ее на другую, так как у них разный интерфейс, разные классы, разные методы. Там люди пытаются придумать общий интерфейс, так, что ты пишешь код под него и после этого можешь легко подключить любую совместимую библиотеку и твой код автоматически окажется с ней тоже совместимым.
В статье нет конкретики, но если перейти по ссылкам, почитать документацию этого стандарта (?), то думаю станет понятно.
Там еще упоминается PSR-7, это интерфейсы дял объектов, представляющих HTTP запрос или ответ. Если ты знаком с ООП и если ты почитаешь документацию, то тебе все станет понятно, я думаю.
Дальше есть немного сложных моментов - про асинхронные запросы и discovery - это рассчитано на тех людей, кто с ними сталкивался и понимает о чем речь. Если ты не сталкивался, то конечно, статья ничем тут не помогает.
То есть у меня ощущение, что ты берешься за статью, но не знаешь чего-то, что надо знать перед тем как ее читать. Условно говоря, статья рассчитана на тех, кто знает ООП и работал с HTTP клиентами. И если ты хочешь разобраться, то придется брать каждое непонятное название, переходить по ссылке, разбираться, читать документацию.
Короткого пути нет. Точнее, есть один - нанять кого-то, кто умеет делать то, что тебе нужно. Или же разбираться постепенно самому.
> хочу добавить кастомные команды, выводящие ответы из моих скриптов
Для этого тебе сначала полностью разобраться как работает существующий код.
>Мне идея понятна из первого абзаца. Есть много разных библиотек-HTTP-клиентов, и если ты использовал в своей программе одну, ты не можешь заменить ее на другую, так как у них разный интерфейс, разные классы, разные методы. Там люди пытаются придумать общий интерфейс, так, что ты пишешь код под него и после этого можешь легко подключить любую совместимую библиотеку и твой код автоматически окажется с ней тоже совместимым.
Да, это-то понятно. Я про код. Сейчас объясню на живом примере. Я хочу гайды типа таких
https://pikabu.ru/story/api_vkontakte_dlya_python_3961240
https://tproger.ru/translations/telegram-bot-create-and-deploy/
или хотя бы типа таких
https://habrahabr.ru/post/281559/
https://habrahabr.ru/post/316666/
https://habrahabr.ru/post/278847/
https://habrahabr.ru/post/127237/
Но для пхп находится какое-то говно + все юзают разные библиотеки и я ебал так жить.
>В статье нет конкретики
>Дальше есть немного сложных моментов - про асинхронные запросы и discovery - это рассчитано на тех людей, кто с ними сталкивался и понимает о чем речь. Если ты не сталкивался, то конечно, статья ничем тут не помогает.
Вот, блеать. Я знаю основы пхп, но всю жизнь писал круды и админки, там хттп ограничивалось посыланием заголовков через header () и минимальным аяксом.
>Для этого тебе сначала полностью разобраться как работает существующий код.
Если ты пилишь бот каким-то конструктором, там и нет кода, вернее, ты его не видишь, он от тебя скрыт, перед тобой только кнопочки админки сервиса (в случае снапчата) для создания ботов или (в случае телеграма) само окошко той штуки, для которой ты делаешь бота (клиент телеграма с диалогом бот-криейтора или созданным ботом, в данном случае). Как к имеющейся хуйне добавить команду, которая не только ответ заготовленный возвращает, а хотя бы результат скрипта <? return random(); ?> не въезжаю :с
Если магазин маленький (до пары тысяч товаров) и пирсинг одноразовый -можно парсить скриптом написанным на коленке за час, если магазин большой и нужны актуальные данные всегда - готовься придумывать архитектуру, проектировать хранение, использовать абстракции над курлом типа angrycurl/rollingcurl с коллбеками. Алсо будь готов что тебя будут постоянно банить, сперва автобаны будешь ловить, потом по IP руками.
В любом случае опыт нужен не только с пхп, но и курлом, xpath или с другой либой которая работает с дом-деревом, знание MySQL
Бiмб
Сдача https://3v4l.org/LHVOQ
Лиличка https://3v4l.org/jc4PN
Считалка https://3v4l.org/dDAaI
Алфавит https://3v4l.org/d5PAs
Навигатор https://3v4l.org/75dUN
https://ideone.com/OTtUP3
Такой вариант имеет право на жизнь? Алсо, если объявить переменную шаблона стихотворения до массива с рандомными словами, то не работает. Подскажите, почему.
Назрел вопрос. Вот в юии есть виджеты, которые могут генерировать готовую html разметку из входящих данных и т.д.
Как это в ларе лучше сделать?
Хочу я, например, сделать метод, который получает массив, которым он заполнит value и name, после чего генерирует выпадающий селект из всего этого.
Вынести в отдельный класс для работы с массивами и выдающий html?
Если да, то как правильно?
Правильно - погуглить готовые виджеты и использовать их. Судя по тому, что ты просишь, достаточно будет этого пакета для генерации HTML:
https://laravelcollective.com/docs/5.2/html
https://laravelcollective.com/docs/5.2/html#drop-down-lists
Кстати раньше он был частью фреймворка. Есть ещё такой пакет: https://github.com/adamwathan/bootforms - по сути тоже самое, но с использованием Twitter Bootstrap.
Ну раз ты гугл не хочешь использовать, то давай немного подумаем и пройдёмся по исходникам. Тебе нужны глобальные переменные в шаблонах, это значит (как мне кажется), что при каждом создании рендерера вьюшек эти переменные должны туда передаваться, может в конструктор, может в метод какой, неважно. Открываем исходники компонента View:
https://github.com/laravel/framework/tree/5.5/src/Illuminate/View
видим так какой-то класс View:
https://github.com/laravel/framework/blob/5.5/src/Illuminate/View/View.php
Помню, что в контроллере мы используем метод render, находим его в этом классе, углубляемся по цепочке protected методов к методу gatherData и видим строчку:
$data = array_merge($this->factory->getShared(), $this->data);
Выглядит как то, что нам нужно - $this->data это массив, который передаётся через $this->render('template.name', ['key' => 'value']) и есть ещё какие-то shared переменные у фабрики. Смотрим её исходники и находим там массив с комментарием "Data that should be available to all templates.": https://github.com/laravel/framework/blob/5.5/src/Illuminate/View/Factory.php#L52
И тут же метод для добавления глобальных переменных:
https://github.com/laravel/framework/blob/5.5/src/Illuminate/View/Factory.php#L309
Итого тебе нужно получить доступ к фабрике View и добавить туда через share свою переменную. Самый простой способ - в AppServiceProvider в методе boot вызвать View::share('key', 'value')
Здесь View - это фасад. Если непонятно почему это работает, то почитай о service provider'ах в ларавеле и изучи как фреймворк резолвит такие статические вызовы (на самом деле он достаёт фабрику из DI-контейнера).
В провайдерах нельзя использовать фасад Auth, а мне он нужен. Но проблема решилась банальным мидлвером примененным ко всем роутам
жаль что программисты не умеют отвечать на вопрос парой строк
Он и не должен PHP файлы подключать, ты хочешь одновременно использовать 2 шаблонизатора (Twig и PHP)? Объясни зачем, может ты слишком много логики в шаблон пихаешь. Ты знаком с макросами твига и кастомными функциями?
я с твигом можно сказать только начинаю знакомство, поэтому вряд ли, есть задание по работе под твиг переписать существующий tpl шаблон, в нём было подключение класса, которое я уже вынес в контроллер и вроде как получил желаемый результат, плюс в этом tpl шаблоне было создание экземпляра класса, который через twig тоже не получилось присвоить, и сделал это через контроллер, ну а с выводом в twig уже вроде как проблем не составило, так что хоть как задумал изначально - не сделал, т.к. тупо нет такой возможности, но обходным путём воспользовался, посмотрим что скажут
Фига у вас всё расписано сначала то, потом это, даже сайтик свой, ни в одном треде на дваче нет такого продвинутого комьюнити
$stmt = $this->dbn->prepare("SELECT FROM student ORDER BY :sort DESC LIMIT 10 OFFSET :offset");
А вот так нет:
$stmt = $this->dbn->prepare("SELECT FROM student ORDER BY :sort :order LIMIT 10 OFFSET :offset");
$stmt->bindValue(':order','DESC');
постгресиквел
$строка = 'строка'.$переменная.'еще строка'.'\n';
ой, я чет не подумал, что надо новую пасту было создать
в суть не всматривался особо, но на 16й строке скрина в первом условии должно идти сравнение ==, вместо присвоения =
Наоборот. В js и php много вкатывальщиков.
Сори, я упорол косяка впринципе с видимостью классов, дело не в неймспейсе.
https://ideone.com/xqMIVT
Межушный ганглий уже не соображает, пойду спать.
Найти значение переменной z, заданной суммой функций. Для нахождения значения функции f(u,t) написать пользовательскую функцию. Числа a и b – случайные.
Давай посчитаем. На 2 костях может выпасть 6 x 6 = 36 разных комбинаций. Из них 6 комбинаций - это даблы (1 и 1, 2 и 2 итд). Следовательно, вероятонсть выпадения дабла на 2 костях = 6 / 36 = 1 / 6. Если бросать 2 кубика, дабл выпадает в среднем раз в 6 случаев (у кого есть кубики, можете попробовать проверить).
А что насчет выпадения даблов у 2 игроков? Очень просто, чтобы найти вероятность того, что произойдет 2 независимых события, надо перемножить их вероятности. Вероятность выпадения даблов у первого игрока = 1/6, у второго = 1/6, вероятность выпадения даблов у 2 игроков одновременно = 1/6 x 1|6 = 1/36 или чуть менее 3%.
Часто это или редко, думай сам.
математическая статистика всегда мне казалась сложной и непонятной
>Если магазин маленький (до пары тысяч товаров) и пирсинг одноразовый -можно парсить скриптом написанным на коленке за час
Это и есть моя задача. Сделать один раз - залить в мой магаз и продавать. Аритектуру и абстракции буду допиливать как разберусь.
>В любом случае опыт нужен не только с пхп, но и курлом, xpath или с другой либой которая работает с дом-деревом, знание MySQL
Знаю MySQL более-менее и с пхп разбираюсь. Можешь подкинуть чего по курлу?
>Алсо будь готов что тебя будут постоянно банить, сперва автобаны будешь ловить, потом по IP руками.
С этим проблем быть не должно.
В идеале я хотел найти готовый говноскрипт - пропарсить им 1 раз, залить товары и продавать, пока я допиливаю все к толковому виду.
>Для нахождения значения функции f(u,t) написать пользовательскую функцию.
Вот тебе функция:
функция малафья (говно, моча)
{
if говно>2 return 1 строчка
elseif говно <=2 return 2 строчка
esle return гроб, гроб, кладбище, пидор
}
Дальше сам
Короче в препаре нельзя пихать все подряд. Сначала нужно составить строку запроса в которой явно заданы названия полей и уже потом ее препарить.
Дело обстоит так, вкатился в пхп и все сопутствующее уже как 4 года.
За плечами создания анонимного чатика, форума, работа с неким неадекватным куном над браузеркой в качестве фронд-ендщика(рисовал анимацию к файтингу), все в порядке унубления( от более качественной к менее качественной реализации).
Пока я все это пилил, то не юзал ни фреймворков, ни ооп, ни мвц, ничегошечки их этого.
И вот ананасы, наступил мой 5 курс универа, мне уже надоело глять во всякую хню, с друзьями и т.д. Да и тян уже есть, и я подумал, - "а хуль бы мне не вкатиться прохрамистом?". В среде программистов со своего универа имею кое-какое уважения в качестве задрота(сам учусь на факультете не имеющим ничего общего с программированием), да и думал до этого что нет нерешаемых для меня задач.
Так вот, решил я вкатиться и начал смотреть вакансии, и тут мой взор упал на обилие всяких непонятных мне технологий (jqeury, фреймворки, git... ). Ну накатал я резюме которое затрагивает хоть немного из этого, хотя сам прочитал сугубо теорию о многом. Невероятно, но меня позвали на собеседование.
Собеседование прошло довольно радужно, два прогера меня интервьюировали около часа, правда один свалил на половине, болтали о всякой поеботе типа отличия js от php, всяком практическом и т.д.
В итоге дали некое проверочное задание, связанное с разработкой блога.
Вкратце используя php7, mysql DB не используя сторонних библиотек (я решил на этом задании надрочить знание jQuery а его использовать нельзя было, олололо, надо было внимательней читать, хотя рааньше его совсем не юзал)
Итог что написали, далее приведу жирным цветом что ответил HR и прокомментирую в скобках:
Здравствуйте, пока, к сожалению не можем вам ничего предложить, так как тестовое задание выполнено слабо(ну ок, слабо, но ведь все же работает)
Выполнено с использованием сторонних библиотек (jQuery)(как ни странно но эта технология мне понравилась, ибо действительно сокращает js код), отсутствует разделение логики и представления(это как их разделять, что такое мвц вообще? в задании не было сказано его использовать), ООП не использовано( зачем его юзать если есть процедурное программирование, и в задании не было сказано использовать ООП), множественное дублирование кода(один раз дублировал аякс запрос из-за пока что плохого понимания jquery, потому что не смог обратиться к ему же, а время поджимало разбираться), непродуманная организация базы данных(а вот тут вообще обидно, ибо использовал БД которая была приведена в задании).
Так вот ананасы, как смыть с себя этот позор(нет), ну допустим задрочу я эти все технологии, буду делать все используя мвц и паттерны, как искать вакансии в своем городе-то, если уже облажался с одной конторкой а другие не ищут пхп манагеров или я из задинамил?(
Соре за сумбурность и ашипке(
Дело обстоит так, вкатился в пхп и все сопутствующее уже как 4 года.
За плечами создания анонимного чатика, форума, работа с неким неадекватным куном над браузеркой в качестве фронд-ендщика(рисовал анимацию к файтингу), все в порядке унубления( от более качественной к менее качественной реализации).
Пока я все это пилил, то не юзал ни фреймворков, ни ооп, ни мвц, ничегошечки их этого.
И вот ананасы, наступил мой 5 курс универа, мне уже надоело глять во всякую хню, с друзьями и т.д. Да и тян уже есть, и я подумал, - "а хуль бы мне не вкатиться прохрамистом?". В среде программистов со своего универа имею кое-какое уважения в качестве задрота(сам учусь на факультете не имеющим ничего общего с программированием), да и думал до этого что нет нерешаемых для меня задач.
Так вот, решил я вкатиться и начал смотреть вакансии, и тут мой взор упал на обилие всяких непонятных мне технологий (jqeury, фреймворки, git... ). Ну накатал я резюме которое затрагивает хоть немного из этого, хотя сам прочитал сугубо теорию о многом. Невероятно, но меня позвали на собеседование.
Собеседование прошло довольно радужно, два прогера меня интервьюировали около часа, правда один свалил на половине, болтали о всякой поеботе типа отличия js от php, всяком практическом и т.д.
В итоге дали некое проверочное задание, связанное с разработкой блога.
Вкратце используя php7, mysql DB не используя сторонних библиотек (я решил на этом задании надрочить знание jQuery а его использовать нельзя было, олололо, надо было внимательней читать, хотя рааньше его совсем не юзал)
Итог что написали, далее приведу жирным цветом что ответил HR и прокомментирую в скобках:
Здравствуйте, пока, к сожалению не можем вам ничего предложить, так как тестовое задание выполнено слабо(ну ок, слабо, но ведь все же работает)
Выполнено с использованием сторонних библиотек (jQuery)(как ни странно но эта технология мне понравилась, ибо действительно сокращает js код), отсутствует разделение логики и представления(это как их разделять, что такое мвц вообще? в задании не было сказано его использовать), ООП не использовано( зачем его юзать если есть процедурное программирование, и в задании не было сказано использовать ООП), множественное дублирование кода(один раз дублировал аякс запрос из-за пока что плохого понимания jquery, потому что не смог обратиться к ему же, а время поджимало разбираться), непродуманная организация базы данных(а вот тут вообще обидно, ибо использовал БД которая была приведена в задании).
Так вот ананасы, как смыть с себя этот позор(нет), ну допустим задрочу я эти все технологии, буду делать все используя мвц и паттерны, как искать вакансии в своем городе-то, если уже облажался с одной конторкой а другие не ищут пхп манагеров или я из задинамил?(
Соре за сумбурность и ашипке(
Через плейсхолдеры можно подставлять только значения в виде чисел и строк в кавычках. Нельзя подставлять имена таблиц и полей.
Если нужно вставлять имя поля, то его надо проверить по списку разрешенных значений и после этого вставить напрямую в запрос.
Писать в телегу - @aleksShinobi1
php не нужен
>=>
http://archive-ipq-co.narod.ru/l1/arrays.html
Создает массив с вручную заданными ключами.
Есть 3 таблицы, через yiic сделал их ActiveRecord, CRUD скрипты сгенерировал, вьюхи для круда есть.
Теперь надо сделать поиск по БД через sql запросы, но я нихуя не вдупляю MVC, теория с практикой не сходится. Знаю, что такое м-в-к, а как их правильно самому сделать, и наладить взаимодействие- хз.
Прошу проверить, правильно ли я понял регулярки. Так как на специальном сайте из-за моей косожопости ничего не находило, я решил сделать в ideone.
Номер машины: https://ideone.com/7uAo3W
А вот с телефонными номерами пока не понимаю. Как сделать, чтобы игнорировало и пробелы, и другие символы?
Как сделать, чтобы искало плюс семь или восемь. У меня на плюс выдает ошибку, как я понял.
1. Парсер
2. Хуярсер
3...
А ещё там гугловская каптча.
>>1073113
>>1073070
Сделал задание без семерки с плюсом, потому что глупенький. https://ideone.com/kAfpHf
Боже мой, какой же я все-таки глупенький, потому что я допустил, что пропущенные символы могут быть цифрой.
Для этого взять язык Python, в нем есть многопоточность , и необходимые библиотеки. Этой штуки тебе за глаза хватит
https://github.com/lorien/grab
Молодец.
Покажи запрос хотя бы
Если ты его сделаешь успешно - они копипастнут его в проект, а на тебя положат хуй. Если не сделаешь - то просто положат хуй. Энджой.
[CODE]
$text = "жы шы";
$patterns = array();
$patterns[0] = "/(ж|ш)ы/ui";
$replacements = array();
$replacements[0] = preg_replace("/ы/ui", "и", $0);
echo preg_replace($petterns, $replacements, $text);
[/CODE]
Это потому, что там $0 в качестве аргумента на функцию подано? Так нельзя разве?
То есть меня не запарит сделать паттерн и реплейсер для каждого кейса, но хотелось покомпактнее как-то.
Допустим, есть таблица в БД. И данные из неё выводятся на страницу (тоже в виде таблицы). И есть кнопка "добавить ещё строку в таблицу".
Я правильно понимаю, что по нажатию на неё мы пинаем контроллер, тот добавляет строку, а затем заново рендерит страницу?
Я так сделал (и оно работает), но как-то медленно. Если обойтись без Yii, то по нажатии на кнопку данные улетают аяксом в пхп-скрипт, который добавляет их в таблицу, а потом возрващает success жс-скрипту. И тот добавляет новую строку на страницу через dom.
Протестировал оба вариата - dom работает раз в шесть быстрее yii и обходится без рефреша страницы. Как такое же сделать в Yii?
Сам ответил на свой вопрос- проблема в коде контроллера.
Один хуй и контроллер, и пхп скрипт у тебя выполняют одну и ту же операцию - insert в таблицу.
Нет, это понятно, что код так сделан, что получается оно это самое, етить его через коромысло.
Мне интересно, можно ли сделать так, чтобы нажатие на кнопку обрабатывал контроллер Yii, а дабавление строки далалось без рефреша страницы?
[CODE]
$text = "aaaaa.ffffff";
$regexp = "/\\w\\.\\S/ui";
$matches = array();
preg_match_all($regexp, $text, $matches);
var_dump($matches);
echo preg_replace('/\\./', '. ', $matches[0][0]);
[/CODE]
А вот этот код почему-то не хочет, хотя регулярка такая же и функция тоже. Неужели опять опечатка?
[CODE]
mb_internal_encoding('UTF-8');
$text = "вышел сдесь координально жы есть aaaa.fffff";
$patterns = array();
$patterns[0] = "/(ж|ш)ы/ui";
$patterns[1] = "/сдесь/ui";
$patterns[2] = "/здел(ал|ан|аю)/ui";
$patterns[3] = "/координально/ui";
$patterns[4] = "/\\w\\.\\S/ui";
$replacements = array();
$replacements[0] = preg_replace("/ы/ui", "и", "$0");
$replacements[1] = "здесь";
$replacements[2] = preg_replace("/з/ui", "с", "$0");
$replacements[3] = "кардинально";
$replacements[4] = preg_replace("/\\./", ". ", "$0");
echo preg_replace($patterns, $replacements, $text);
[/CODE]
[CODE]
$text = "aaaaa.ffffff";
$regexp = "/\\w\\.\\S/ui";
$matches = array();
preg_match_all($regexp, $text, $matches);
var_dump($matches);
echo preg_replace('/\\./', '. ', $matches[0][0]);
[/CODE]
А вот этот код почему-то не хочет, хотя регулярка такая же и функция тоже. Неужели опять опечатка?
[CODE]
mb_internal_encoding('UTF-8');
$text = "вышел сдесь координально жы есть aaaa.fffff";
$patterns = array();
$patterns[0] = "/(ж|ш)ы/ui";
$patterns[1] = "/сдесь/ui";
$patterns[2] = "/здел(ал|ан|аю)/ui";
$patterns[3] = "/координально/ui";
$patterns[4] = "/\\w\\.\\S/ui";
$replacements = array();
$replacements[0] = preg_replace("/ы/ui", "и", "$0");
$replacements[1] = "здесь";
$replacements[2] = preg_replace("/з/ui", "с", "$0");
$replacements[3] = "кардинально";
$replacements[4] = preg_replace("/\\./", ". ", "$0");
echo preg_replace($patterns, $replacements, $text);
[/CODE]
Можно. Если контрол умеет обрабатывать JSON.
Контроллер выполняет задачу, отдает JSON. AJAXовый контрол парсит данные и рефрешит элементы.
Бляя почитай какие символы можно использовать в регулярных
Алсо foreach'ем пройтись надо по массивам, откуда вы берётесь такие
А в чем проблема сделать аякс запрос в нужный route на сервер? Какая аяксу разница делаешь ты аякс-запрос в пхп-скрипт или в контроллер?
Контроллер делает то, что ты ему скажешь. Скажешь рендерить страницу, он будет рендерить страницу. Скажешь выплюнуть json-код - он его выплюнет. Скажешь ничего не делать и кинуть 500 эррор, он его кинет. Контроллер это тот же пхп скрипт, просто с кучей подтянутого на фоне бэкенда.
Командуешь аяксу кинуть запрос на нужный адрес - myfacebook.com/controller/method
Командуешь методу контроллера принять данные из запроса и return new Response(200) или че там в йии.
Нет. Что такое классы?
Добра тебе анон.
Прочел все по ссылкам про замыкания, колбек и анонимные функции. Вроде все понял, но я бы еще задачи порешал. Может у кого-то есть на эту тему? У ОПа только задача про айпад в уроках, которую я давно решил.
Главная особенность анонимных функций - то, что их можно сохранять в переменные, передавать в функции, возвращать из функций. Ну и вторая особенность, это способность сохранаять переменные снаружи функции (функция вместе со скопированными ей внешними переменными называется замыкание - closure).
Зачем они нужны? Разберем пример.
Представь, что у тебя есть склад. На складе лежат товары, у каждого товара есть вес (в кг), цена и название.
Склад можно описать с помощью массива товаров (попробуй). У меня получилось так:
$warehouse = [
['name' => 'картошка', 'weight' => 100, 'price' => 100500],
['name' => 'морковка', 'weight' => 50, 'price' => 5000],
...
];
Допустим, что у нас есть массив, который соответствует содержимому склада и мы хотим сделать функцию поиска товаров на складе. Если мы допустим хотим найти все товары с определенным названием, мы можем сделать такую функцию:
function findByName($warehouse, $name) { ... }
Ей передается содержимое склада и название, и она возвращает товары с таким названием (попробуй дописать).
Но эта функция умеет искать товары только по названию.
А что, если мы хотим сделать функцию, которая ищет товары на складе не только по имени, а по любым произвольным критериям? Например:
- товары с названием на букву "А"
- товары легче 100 кг
- товары, у которых цена за килограмм меньше 10
Как представить в коде и как передать в функцию эти критерии поиска? Как передать условие "легче 100 кг"? Тут-то и приходят на помощь анонимные функции. Мы можем выразить критерий поиска в виде анонимной функции, которая получает на вход товар и возвращает true или false в зависимости от того, соответствует товар условию поиска или нет.
Вот пример функции, которая получает на вход товар (массив с информацией об одном товаре) и проверяет, что он весит меньше 100 кг:
$checkWeightIsLessThan100 = function ($item) {
return $item['weight'] < 100;
};
Соответственно, после того как мы записали критерий поиска в виде функции-проверяльщика условия, мы можем его передать в функцию поиска:
$items = findItems($warehouse, $checkWeightLessThan100);
Задание:
1) допиши код, чтобы все это работало
2) прочитай в мануале про array_map и array_filter
3) прочитай в мануале про usort. Эта функция позволяет отсортировать (упорядочить) элементы массива по произвольному критерию. Напиши функцию, которая отсортирует товары на складе, чтобы они шли в таком порядке:
а) сначала группа товаров с ценой менее 1000
б) за ними группа товаров с ценой менее 5000
в) за ними оставшиеся товары
Внутри групп а, б, в товары сортируются по названию (по алфавиту).
4) Напиши функцию, которая создает функции-счетчики. Наверно понять, что имеется в виду, сложно, потому дам пример кода. createCounter - это функция, которую ты и должен написать:
function createCounter() { ... }
$c1 = createCounter(); // создаем первый счетчик. в $c1 должна записаться анонимная функция, которая при каждом вызове будет возвращать числа, начиная с 1
echo $с1(); // выводит 1
echo $c1(); // выводит 2
echo $c1(); // выводит 3
$c2 = createCounter(); // создаем вторую независимую функцию-счетчик
echo $c2(); // 1
echo $c2(); // 2
// при этом первая функция-счетчик тоже работает:
echo $c1(); // 4
echo $c1(); // 5
Думаю, этого хватит, чтобы получить общее представление об анонимных функциях. Спрашивай, если что-то непонятно.
Главная особенность анонимных функций - то, что их можно сохранять в переменные, передавать в функции, возвращать из функций. Ну и вторая особенность, это способность сохранаять переменные снаружи функции (функция вместе со скопированными ей внешними переменными называется замыкание - closure).
Зачем они нужны? Разберем пример.
Представь, что у тебя есть склад. На складе лежат товары, у каждого товара есть вес (в кг), цена и название.
Склад можно описать с помощью массива товаров (попробуй). У меня получилось так:
$warehouse = [
['name' => 'картошка', 'weight' => 100, 'price' => 100500],
['name' => 'морковка', 'weight' => 50, 'price' => 5000],
...
];
Допустим, что у нас есть массив, который соответствует содержимому склада и мы хотим сделать функцию поиска товаров на складе. Если мы допустим хотим найти все товары с определенным названием, мы можем сделать такую функцию:
function findByName($warehouse, $name) { ... }
Ей передается содержимое склада и название, и она возвращает товары с таким названием (попробуй дописать).
Но эта функция умеет искать товары только по названию.
А что, если мы хотим сделать функцию, которая ищет товары на складе не только по имени, а по любым произвольным критериям? Например:
- товары с названием на букву "А"
- товары легче 100 кг
- товары, у которых цена за килограмм меньше 10
Как представить в коде и как передать в функцию эти критерии поиска? Как передать условие "легче 100 кг"? Тут-то и приходят на помощь анонимные функции. Мы можем выразить критерий поиска в виде анонимной функции, которая получает на вход товар и возвращает true или false в зависимости от того, соответствует товар условию поиска или нет.
Вот пример функции, которая получает на вход товар (массив с информацией об одном товаре) и проверяет, что он весит меньше 100 кг:
$checkWeightIsLessThan100 = function ($item) {
return $item['weight'] < 100;
};
Соответственно, после того как мы записали критерий поиска в виде функции-проверяльщика условия, мы можем его передать в функцию поиска:
$items = findItems($warehouse, $checkWeightLessThan100);
Задание:
1) допиши код, чтобы все это работало
2) прочитай в мануале про array_map и array_filter
3) прочитай в мануале про usort. Эта функция позволяет отсортировать (упорядочить) элементы массива по произвольному критерию. Напиши функцию, которая отсортирует товары на складе, чтобы они шли в таком порядке:
а) сначала группа товаров с ценой менее 1000
б) за ними группа товаров с ценой менее 5000
в) за ними оставшиеся товары
Внутри групп а, б, в товары сортируются по названию (по алфавиту).
4) Напиши функцию, которая создает функции-счетчики. Наверно понять, что имеется в виду, сложно, потому дам пример кода. createCounter - это функция, которую ты и должен написать:
function createCounter() { ... }
$c1 = createCounter(); // создаем первый счетчик. в $c1 должна записаться анонимная функция, которая при каждом вызове будет возвращать числа, начиная с 1
echo $с1(); // выводит 1
echo $c1(); // выводит 2
echo $c1(); // выводит 3
$c2 = createCounter(); // создаем вторую независимую функцию-счетчик
echo $c2(); // 1
echo $c2(); // 2
// при этом первая функция-счетчик тоже работает:
echo $c1(); // 4
echo $c1(); // 5
Думаю, этого хватит, чтобы получить общее представление об анонимных функциях. Спрашивай, если что-то непонятно.
пишу скриптик по работе, как отправить смс в скрипте через свою мобилу? Есть ли какие то програмки с API на Android или IOS?
Ищем себе человечка. Джуна/Мидла.
Локация: Москва.
Нужно знание PHP7, Symfony 3 и MySQL/PostgresSQL (вообще похуй, т.к. есть DoctrineORM же).
Вообще у нас дают тестовое , после собеседования, но его (естесно)
никто не делает.
Так вот, анон, я предлагаю тебе запилить его! Я его проверю, помогу тебе в тихаря "причесать" и оформить так, чтобы тимлиду понравилось.
Если все будет ОК, то тебя пригласят на собес. Собес == взять на работу. Т.к. он больше будет нужен провети тебя на имбецильность и шизу (80% кандидатов такие).
Не все пункты задания обязательные, например 4 задание не нужно хуярить супер верстку, вообще можно ее не делать. Мы ищем PHP-шника, верстальщик у нас есть.
Время не ограничено, но учитывай, что пока ты делаешь, других людей тоже собеседуют!
http://rgho.st/6Sw48CLfT - само задание
С вопросами и выполненным заданием пишите в телегу: @spudro или в треде.
В сети предлагают разные
Занимаясь 3 месяца по 18 часов в день хватит освоить эти азы?
>чертежы
Это немного сложнее чем кописатить совковое говно.
Еще бля понабрал говна разного, ты вообще что хочешь?
Ебать ты даун братишка
Ты че так порвался-то? Опять зарплату канифолью выдали?
вроде бы есть, по поиску расширений поищи.
Кодировка строки не та.
>Контроллер выполняет задачу, отдает JSON.
Это можно. Но как организовать приём? То есть, вот эту штуку:
>AJAXовый контрол парсит данные и рефрешит элементы.
>>1073660
>А в чем проблема сделать аякс запрос в нужный route на сервер? Какая аяксу разница делаешь ты аякс-запрос в пхп-скрипт или в контроллер?
Получится лишняя прослойка. На вью кнопка, при нажатии срабатывает js (а не контроллер) и передаёт аяксом в контроллер данные, а потом принимает оттуда json и изменяет вью. Так я уже делал и оно работает. Но по фен-шую ли это? То есть, не монтирую ли я велосипед?
>>1073664
То есть, всё же, считывать нажатие на кнопку не контроллером, а js-скриптом - это правильно? Но я тогда не понимаю, как это согласуется с моделью MVC. Не претендует ли скрипт на роль второго контроллера?
> и MySQL/PostgresSQL (вообще похуй, т.к. есть DoctrineORM же).
Это типичное заблуждение, что можно не знать SQL если ты используешь ORM. Это не так. SQL знать все равно надо (а в случае с доктриной еще и DQL).
Также, где гарантия что ты именно работодатель, а не соискатель, желающий, чтобы ему кто-нибудь сделал тестовое задание?
Щас бы тестовуху джуна на ебаном yii 1.0.0 положить в проект. Энджою.
>>1074158
Если есть возможность - вынести логику в отдельный сервис/хелпер, который потом можно будет вызывать из любого контроллера, из консоли, в юнит-тестах. Да кого я обманываю - какие юнит-тесты у похапешников?
Метод попроще и похуже - вынести в трейт.
Самый плохой - наследование. Завтра у него появится другая функция, которую нужно переиспользовать в разных контроллерах, а множественного наследования в PHP, к счастью, нет.
>>1074201
Это вообще не норм.
>>1073798
sms.ru
И какое отношение "Android или IOS?" имеют к треду?
https://github.com/codedokode/pasta/blob/master/arch/di.md
https://github.com/jupeter/clean-code-php
http://blog.byndyu.ru/2009/10/solid.html (если не знаешь C#, то читни туториал на learnxinyminutes, там очень сжато про синтаксис)
Советую изучать ООП в целом. Так как на классах вполне себе можно писать процедурный сложно читаемый код. Я вот сейчас работаю с проектом, в котором люди лепят наследование вместо DI, по ходу выполнения программы создают у объекта свойства (почему это вообще не запретят в PHP?), а потом повсюду проверяют if (isset($obj->property1) && isset($obj->property2))
Читать такой код очень тяжело, вместо того, чтобы доверять объектам с инкапсуляцией приходится держать в голове кучу внутренностей класса. Ну а вообще вот слова для гугления:
- Dependency Injection (контейнер тебе пока не нужен)
- SOLID/GRASP
- Composition over inheritance
- Law of Demeter
- Cohesion/Coupling
В ссылках выше всё это есть. И самое главное - практикуйся. В ОП-посте есть хорошие задачи, ты можешь написать игру консольную (например шахматы, без ИИ). Недавно наткнулся на такую задачу: https://gist.github.com/wbars/2c3590206ee4a590eca5
>>1074158
Вообще, это можно решить наследованием от общего предка, где и реализовать метод. Но тут стоит подумать. Наследованием не стоит злоупотреблять, и в базовый класс стоит добавлять только методы которые в теории могут быть полезны всем потомкам.
Лучше бы ты конечно привел конкретную ситуацию, а то так абстрактно трудно комемнтировать.
Алсо почитай мой урок про MVC https://github.com/codedokode/pasta/blob/master/arch/mvc.md
>>1074070
Для ответа на вопрос нужно открыть код метода и посмотреть.
>>1074036
> считывать нажатие на кнопку не контроллером, а js-скриптом - это правильно?
А как PHP-код, который выполняется на сервере, может "считать" (обработать) нажатие на кнопку в браузере? По моему кроме JS, это никак не сделать (если только через отправку формы, но это тебе не подходит).
> Получится лишняя прослойка. На вью кнопка, при нажатии срабатывает js (а не контроллер)
Ты делаешь ошибку в определении того, что является частью MVC-приложения, а что нет. MVC приложение на PHP работает на сервере. Входные данные для него - это приходящие с клиента HTTP-запросы, а на выходе оно выдает HTTP-ответ со страницей. Откуда приходят эти запросы - из-за перехода по ссылке, отправки формы, отправлены JS-скриптом через аякс - это PHP-приложению не важно.
Соответственно, будешь ты использовать аякс или нет - с MVC никак не связано, так как MVC применяется в данном случае для описания только кода на сервере. Формально можно сказать, что JS скрипт является частью вью, но ведь он не выполняется на сервере и он для сервера ничем не отличается от HTML-разметки - это просто какие-то текстовые данные, которые надо отдать в HTTP-ответе.
Потому MVC никак не запрещает использовать аякс. Аякс-запросы в MVC стоит обрабатывать так же, как и обычные, пропуская их через тот же самый фронт-контроллер или роутер, а затем вызывая контроллер.
Впрочем, бывают сложные приложения (SPA), где JS код также использует архитектуру MVC. В этом случае мы имеем аж 2 отдельных MVC приложения - серверное и клиентское, работающее в браузере.
> Не претендует ли скрипт на роль второго контроллера?
Нет, так как он не на PHP и не выполняется на сервере.
> Мне интересно, можно ли сделать так, чтобы нажатие на кнопку обрабатывал контроллер Yii, а дабавление строки далалось без рефреша страницы?
Код на сервере не может добавить строку в DOM. Это может сделать только JS-код.
>>1074158
Вообще, это можно решить наследованием от общего предка, где и реализовать метод. Но тут стоит подумать. Наследованием не стоит злоупотреблять, и в базовый класс стоит добавлять только методы которые в теории могут быть полезны всем потомкам.
Лучше бы ты конечно привел конкретную ситуацию, а то так абстрактно трудно комемнтировать.
Алсо почитай мой урок про MVC https://github.com/codedokode/pasta/blob/master/arch/mvc.md
>>1074070
Для ответа на вопрос нужно открыть код метода и посмотреть.
>>1074036
> считывать нажатие на кнопку не контроллером, а js-скриптом - это правильно?
А как PHP-код, который выполняется на сервере, может "считать" (обработать) нажатие на кнопку в браузере? По моему кроме JS, это никак не сделать (если только через отправку формы, но это тебе не подходит).
> Получится лишняя прослойка. На вью кнопка, при нажатии срабатывает js (а не контроллер)
Ты делаешь ошибку в определении того, что является частью MVC-приложения, а что нет. MVC приложение на PHP работает на сервере. Входные данные для него - это приходящие с клиента HTTP-запросы, а на выходе оно выдает HTTP-ответ со страницей. Откуда приходят эти запросы - из-за перехода по ссылке, отправки формы, отправлены JS-скриптом через аякс - это PHP-приложению не важно.
Соответственно, будешь ты использовать аякс или нет - с MVC никак не связано, так как MVC применяется в данном случае для описания только кода на сервере. Формально можно сказать, что JS скрипт является частью вью, но ведь он не выполняется на сервере и он для сервера ничем не отличается от HTML-разметки - это просто какие-то текстовые данные, которые надо отдать в HTTP-ответе.
Потому MVC никак не запрещает использовать аякс. Аякс-запросы в MVC стоит обрабатывать так же, как и обычные, пропуская их через тот же самый фронт-контроллер или роутер, а затем вызывая контроллер.
Впрочем, бывают сложные приложения (SPA), где JS код также использует архитектуру MVC. В этом случае мы имеем аж 2 отдельных MVC приложения - серверное и клиентское, работающее в браузере.
> Не претендует ли скрипт на роль второго контроллера?
Нет, так как он не на PHP и не выполняется на сервере.
> Мне интересно, можно ли сделать так, чтобы нажатие на кнопку обрабатывал контроллер Yii, а дабавление строки далалось без рефреша страницы?
Код на сервере не может добавить строку в DOM. Это может сделать только JS-код.
Это зависит от того, какая у тебя ОС и как ты устанавливал PHP. В Windows точно можно удалить одну версию PHP и установить другую, в Дебиане, я думаю тоже, хотя там могут быть подвохи (например, старая версия PHP требует старую библиотеку, которая не совместима с другими программами). Для линукса также есть скрипт phpenv, который умеет по команде скачивать и компилировать любую версию PHP, а также делать другие интересные вещи.
>>1073806
Не очень, но в PHP7 есть полезные улучшения, о которых надо знать. Погугли статьи "что нового в PHP7".
>>073798
С андроида СМС можно отправить через встроенный в смартфон модем.
Также, ты бы мог наверно сделать Телеграм-бота и получать сообщения через него, но я не уверен.
>>1073765
Гугли JS beautify. Код правда может быть обфусцирован (запутан) и ты все равно его не разберешь. Если это библиотека то лучше найти исходники.
> и обратно?
Гугли "минификация JS"
>>1073418
Да, и тебе не придется долго учиться так как ООП в PHP очень похож на ООП в Java.
> $replacements[0] = preg_replace("/ы/ui", "и", "$0");
Ты наверно думаешь, что preg_replace будет вызван для замены найденного текста. Но это не так. Ты не понимаешь, в каком порядке выполняется код.
А выполняется код (если нет if, циклов и тд) сверху вниз. Соответственно, эта строчка выполнится так:
PHP вызовет функцию preg_replace("/ы/ui", "и", "$0"), которая ищет в строке "$0" соответствие шаблону "/ы/ui". Соответствия нет, потому функция вернет просто строку "$0", которая и запишется в массив.
Вот пример, как правильно использовать $0-$9 при замене текста:
echo preg_replace("/(\S+)@(\S+)/", '$1 [at] $2', "Напишите мне на aa6aZaANUSex#1}amplePUNCTUMco;[#m");
// Напишите мне на aaa [at] example.com
Если тебе нужно, чтобы при нахождении совпадения с регуляркой вызывался твой код, то тебе нужна функция preg_replace_callback и анонимные функции (с помощью анонимной функции ты описываешь, что делать при нахождении совпадения с шаблоном). Прочесть при них можно в мануале, а я дам пример их использования: https://repl.it/M3uo/1
mb_internal_encoding('utf-8');
$text = "здравствуйте. до свидания.";
echo preg_replace_callback("/(\A|\.\s*)\w/u", function ($m) {
return mb_strtoupper($m[0]);
}, $text);
echo "\n";
// Здравствуйте. До свидания.
\A значит "начало текста".
>>1073188
С джойнами? Джойн без ограничений дает присоединение каждой строки к каждой и в твоем случае выдаст таблицу с 5 * 2 * 12 = 120 строками.
>>1073187
Твое выражение, к сожалению, не годится, так как .* значит "любое число любых символов, кроме \n". Очевидно, что оно будет соответствовать вообще любым текстовым строкам, где есть цифры.
Ты тестировал свою регулярку на https://regex101.com/r/qF7vT8/3 ?
Вот, как надо ее решать:
Сначала надо внимательно изучить примитивные конструкции, из которых составляются шаблоны: точка, квантифкаторы (звездочки, плюсы, фигурные скобки), вертикальная черта, круглые скобки, квадратные скобки, условия вроде ^ или \b.
Потом мы пишем такое выражение:
- в начале идет 8 или +7
- за ним 10 раз повторяется такое выражение: "любое число минусов, скобок или пробелов в любом порядке, за ними ровно 1 цифра"
- разумеется, копипастить выражение 10 раз не надо, надо использовать квантификатор
Мануал в помощь: http://php.net/manual/ru/pcre.pattern.php
> $replacements[0] = preg_replace("/ы/ui", "и", "$0");
Ты наверно думаешь, что preg_replace будет вызван для замены найденного текста. Но это не так. Ты не понимаешь, в каком порядке выполняется код.
А выполняется код (если нет if, циклов и тд) сверху вниз. Соответственно, эта строчка выполнится так:
PHP вызовет функцию preg_replace("/ы/ui", "и", "$0"), которая ищет в строке "$0" соответствие шаблону "/ы/ui". Соответствия нет, потому функция вернет просто строку "$0", которая и запишется в массив.
Вот пример, как правильно использовать $0-$9 при замене текста:
echo preg_replace("/(\S+)@(\S+)/", '$1 [at] $2', "Напишите мне на aa6aZaANUSex#1}amplePUNCTUMco;[#m");
// Напишите мне на aaa [at] example.com
Если тебе нужно, чтобы при нахождении совпадения с регуляркой вызывался твой код, то тебе нужна функция preg_replace_callback и анонимные функции (с помощью анонимной функции ты описываешь, что делать при нахождении совпадения с шаблоном). Прочесть при них можно в мануале, а я дам пример их использования: https://repl.it/M3uo/1
mb_internal_encoding('utf-8');
$text = "здравствуйте. до свидания.";
echo preg_replace_callback("/(\A|\.\s*)\w/u", function ($m) {
return mb_strtoupper($m[0]);
}, $text);
echo "\n";
// Здравствуйте. До свидания.
\A значит "начало текста".
>>1073188
С джойнами? Джойн без ограничений дает присоединение каждой строки к каждой и в твоем случае выдаст таблицу с 5 * 2 * 12 = 120 строками.
>>1073187
Твое выражение, к сожалению, не годится, так как .* значит "любое число любых символов, кроме \n". Очевидно, что оно будет соответствовать вообще любым текстовым строкам, где есть цифры.
Ты тестировал свою регулярку на https://regex101.com/r/qF7vT8/3 ?
Вот, как надо ее решать:
Сначала надо внимательно изучить примитивные конструкции, из которых составляются шаблоны: точка, квантифкаторы (звездочки, плюсы, фигурные скобки), вертикальная черта, круглые скобки, квадратные скобки, условия вроде ^ или \b.
Потом мы пишем такое выражение:
- в начале идет 8 или +7
- за ним 10 раз повторяется такое выражение: "любое число минусов, скобок или пробелов в любом порядке, за ними ровно 1 цифра"
- разумеется, копипастить выражение 10 раз не надо, надо использовать квантификатор
Мануал в помощь: http://php.net/manual/ru/pcre.pattern.php
Спамботы не нужны.
>>1073183
Плюс - это спецсимвол, который обозначает повторение предыдущего символа от 1 до ∞ раз. Чтобы написать в шаблоне просто "ищи символ плюс", его надо экранировать бекслешем: \+ и он потеряет свое специальное значение.
Спецсимволы в регулярках надо выучить наизусть ( http://php.net/manual/ru/regexp.reference.meta.php ).
Бекслеш также можно писать 2 раза, так как бекслеш имеет специальное значение при записи строк ( http://php.net/manual/ru/language.types.string.php ) и когда мы пишем \\+, то \\ интерпретируется как \ и в строку попадает просто \+.
>>1073113
Нужно писать "любое количество символов" между цифрами.
>>1073070
Правильно.
>>1072962
Читал мой урок? Там и пример MVC кода есть https://github.com/codedokode/pasta/blob/master/arch/mvc.md
>>1072955
Это символы, которые используются при описании массивов и в конструкции foreach:
$a = [1 => 100, 2 => 50];
foreach ($a as $k => $v) { ... }
Стрелка является частью этих конструкций и отдельно от них не несет никакого смысла.
Спамботы не нужны.
>>1073183
Плюс - это спецсимвол, который обозначает повторение предыдущего символа от 1 до ∞ раз. Чтобы написать в шаблоне просто "ищи символ плюс", его надо экранировать бекслешем: \+ и он потеряет свое специальное значение.
Спецсимволы в регулярках надо выучить наизусть ( http://php.net/manual/ru/regexp.reference.meta.php ).
Бекслеш также можно писать 2 раза, так как бекслеш имеет специальное значение при записи строк ( http://php.net/manual/ru/language.types.string.php ) и когда мы пишем \\+, то \\ интерпретируется как \ и в строку попадает просто \+.
>>1073113
Нужно писать "любое количество символов" между цифрами.
>>1073070
Правильно.
>>1072962
Читал мой урок? Там и пример MVC кода есть https://github.com/codedokode/pasta/blob/master/arch/mvc.md
>>1072955
Это символы, которые используются при описании массивов и в конструкции foreach:
$a = [1 => 100, 2 => 50];
foreach ($a as $k => $v) { ... }
Стрелка является частью этих конструкций и отдельно от них не несет никакого смысла.
> ни ооп, ни мвц, ничегошечки их этого
Это сильно ограничивает твои возможности и на твоем фоне кандидаты с ООП и фреймворками выглядят на порядок лучше.
> это как их разделять, что такое мвц вообще? в задании не было сказано его использовать
Есть урок https://github.com/codedokode/pasta/blob/master/arch/mvc.md
> как искать вакансии в своем городе-то, если уже облажался с одной конторкой а другие не ищут пхп манагеров или я из задинамил
Искать удаленно.
Алсо, в ОП посте в учебнике написано про ООП. Также, там есть задача про студентов, которая поможет изучить MVC.
>>1072762
Целиком, так что результат работы - это работающий сайт, на который легко может зайти заказчик и увидеть.
Смысл выражения "под ключ" описан тут: https://ru.wiktionary.org/wiki/под_ключ
> не требующий доделки, доводки, настройки; в полностью готовом к немедленной эксплуатации состоянии
>>1072407
Нельзя PHP файлы подключать. Но ты конечно можешь расширить твиг функциями или даже новым синтаксисом, или поискать готовое расширение.
>>1072366
Он тебе как раз правильно ответил, показав, как нужно решать такие задачи. Если тебе лень лазать по коду, значит в следующий раз ты просто не сможешь решить проблему.
>>1072070
Решено верно.
>>1071905
> Сдача https://3v4l.org/LHVOQ
> foreach ($bills as $key => $value) {
Лучше было дать переменным key/value более осмысленные имена (номинал и число купюр).
> while ($key <= $amount){
> $billsForDelivery[$key]++;
Используй деление вместо цикла.
Также, не проверяется наличие нужного набора купюр. Вот например, купюр номиналом 200 нет, а он пишет, что выдать сумму возможно: https://3v4l.org/JX2Hd
Пока что неправильно.
> Лиличка https://3v4l.org/jc4PN
Тут важно предупредить, что в Windows некоторые программы кодируют новую строку как \r\n ( ). Этот символ может испортить расчет длин строк и вывод текста, потому для надежности можно его удалять, или делать разбиение по выражению \r?\n
> preg_split('/\n/',
Можно было просто explode использовать
Найти макс. длину строки может быть удобнее через max() и array_map(), сможешь?
А так, работает верно.
> Считалка https://3v4l.org/dDAaI
> for($j = $numberLeft; $j < $total; $j++){
> $positions[$j] = $positions[$j+1];
Удаление элемента удобнее делать через array_slice.
> if ($total - $numberLeft < $skip - 1){
> $numberLeft = $skip - ($total - $numberLeft) - 1;
> } else {
Для того, чтобы увеличивать число с возвратом к числу 1, удобнее использовать оператор % - деление с остатком, только придется считать номера с 0.
> $total--;
Вместо этой переменной можно было использовать count().
Так, работает верно.
> Алфавит https://3v4l.org/d5PAs
> $letters = preg_split("//u", $phrase);
там надо добавлять флаг PREG_SPLIT_NO_EMPTY, а то в массив добавляются 2 пустых элемента с краев. Видимо по этой причине тебе пришлось в $i <= $phraseLength; написать <= вместо <.
> for ($y = 0; $y < $height; $y++){
> $screen[$y] = array_fill(0, 150, ' ');
Можно было 2 раза использовать array_fill вместо цикла.
> $coordinateYOfLetter
Лучше $letterX
> foreach ($value as $a) {
> echo $a;
Можно было использовать implode.
Так, работает верно.
> Навигатор https://3v4l.org/75dUN
> $paths[$startPoint][1][0] = 0;
А что значит [1][0] ? Что-то я не очень понимаю. Ты зря в справочник расстояний добавляешь какие-то странные элементы, лучше было сделать отдельный массив для хранения времени до точки.
> foreach ($paths as $key => &$value) {
Тут надо помнить, что после окончания цикла переменная $value продолжает указывать на последний элемент массива и команда $value = 1 запишет туда единицу например. И цикл foreach ($x as $value) тоже запишет значение по ссылке.
Это вроде бы описано в мануале.
Если ты используешь алгоритм, например, Дейкстру, хорошо бы дать в комментарии его название или ссылку.
> if ($value2 == $key){
> continue 2;
А тут не просто continue должно быть?
Вместо key и value лучше было выбрать более понятные имена.
Часть кода можно было вынести в функции, например, поиск ближайшей к текущей точки, ради повышения читабельности кода.
> ни ооп, ни мвц, ничегошечки их этого
Это сильно ограничивает твои возможности и на твоем фоне кандидаты с ООП и фреймворками выглядят на порядок лучше.
> это как их разделять, что такое мвц вообще? в задании не было сказано его использовать
Есть урок https://github.com/codedokode/pasta/blob/master/arch/mvc.md
> как искать вакансии в своем городе-то, если уже облажался с одной конторкой а другие не ищут пхп манагеров или я из задинамил
Искать удаленно.
Алсо, в ОП посте в учебнике написано про ООП. Также, там есть задача про студентов, которая поможет изучить MVC.
>>1072762
Целиком, так что результат работы - это работающий сайт, на который легко может зайти заказчик и увидеть.
Смысл выражения "под ключ" описан тут: https://ru.wiktionary.org/wiki/под_ключ
> не требующий доделки, доводки, настройки; в полностью готовом к немедленной эксплуатации состоянии
>>1072407
Нельзя PHP файлы подключать. Но ты конечно можешь расширить твиг функциями или даже новым синтаксисом, или поискать готовое расширение.
>>1072366
Он тебе как раз правильно ответил, показав, как нужно решать такие задачи. Если тебе лень лазать по коду, значит в следующий раз ты просто не сможешь решить проблему.
>>1072070
Решено верно.
>>1071905
> Сдача https://3v4l.org/LHVOQ
> foreach ($bills as $key => $value) {
Лучше было дать переменным key/value более осмысленные имена (номинал и число купюр).
> while ($key <= $amount){
> $billsForDelivery[$key]++;
Используй деление вместо цикла.
Также, не проверяется наличие нужного набора купюр. Вот например, купюр номиналом 200 нет, а он пишет, что выдать сумму возможно: https://3v4l.org/JX2Hd
Пока что неправильно.
> Лиличка https://3v4l.org/jc4PN
Тут важно предупредить, что в Windows некоторые программы кодируют новую строку как \r\n ( ). Этот символ может испортить расчет длин строк и вывод текста, потому для надежности можно его удалять, или делать разбиение по выражению \r?\n
> preg_split('/\n/',
Можно было просто explode использовать
Найти макс. длину строки может быть удобнее через max() и array_map(), сможешь?
А так, работает верно.
> Считалка https://3v4l.org/dDAaI
> for($j = $numberLeft; $j < $total; $j++){
> $positions[$j] = $positions[$j+1];
Удаление элемента удобнее делать через array_slice.
> if ($total - $numberLeft < $skip - 1){
> $numberLeft = $skip - ($total - $numberLeft) - 1;
> } else {
Для того, чтобы увеличивать число с возвратом к числу 1, удобнее использовать оператор % - деление с остатком, только придется считать номера с 0.
> $total--;
Вместо этой переменной можно было использовать count().
Так, работает верно.
> Алфавит https://3v4l.org/d5PAs
> $letters = preg_split("//u", $phrase);
там надо добавлять флаг PREG_SPLIT_NO_EMPTY, а то в массив добавляются 2 пустых элемента с краев. Видимо по этой причине тебе пришлось в $i <= $phraseLength; написать <= вместо <.
> for ($y = 0; $y < $height; $y++){
> $screen[$y] = array_fill(0, 150, ' ');
Можно было 2 раза использовать array_fill вместо цикла.
> $coordinateYOfLetter
Лучше $letterX
> foreach ($value as $a) {
> echo $a;
Можно было использовать implode.
Так, работает верно.
> Навигатор https://3v4l.org/75dUN
> $paths[$startPoint][1][0] = 0;
А что значит [1][0] ? Что-то я не очень понимаю. Ты зря в справочник расстояний добавляешь какие-то странные элементы, лучше было сделать отдельный массив для хранения времени до точки.
> foreach ($paths as $key => &$value) {
Тут надо помнить, что после окончания цикла переменная $value продолжает указывать на последний элемент массива и команда $value = 1 запишет туда единицу например. И цикл foreach ($x as $value) тоже запишет значение по ссылке.
Это вроде бы описано в мануале.
Если ты используешь алгоритм, например, Дейкстру, хорошо бы дать в комментарии его название или ссылку.
> if ($value2 == $key){
> continue 2;
А тут не просто continue должно быть?
Вместо key и value лучше было выбрать более понятные имена.
Часть кода можно было вынести в функции, например, поиск ближайшей к текущей точки, ради повышения читабельности кода.
Это надо смотреть документацию по UMI для разработчиков, я не знаю.
>>1071847
Если ты делаешь бота через конструктор,то не знаю. А там нельзя получить код бота и его исправить? Если нельзя, то не знаю как.
>>1071671
[abc] - один любой символ из набора a, b, c
[a-d] - любой символ от a до d
[a-fmn] - любой символ от a до f, или m или n
>>1071608
В один проход наверно никак.
>>1071615
Основы то изучить нетрудно, и learn.javascript.ru пройти. не будешь же за каждой правкой бегать к верстальщику.
>>1071513
> В элементе adr::before когда я ставлю ему контент иконки, он перестает быть inline-block элементом,
Лучше сделать ::before просто блоком или абсолютно позиционированным относительно колонки блоком. В контент поставить пустую строку. Задать размеры. Поставить картинку как фоновую.
Еще вариант - попробовать поставить картинку как фоновую на саму колонку с текстом, расчистив место за счет паддинга, но не уверен что ее можно будет удобно спозиционировать.
>>1071463
> ни в какую не хочет расширяться в fit-content,
Зачем его использовать, он пока толком нигде не поддерживается.
Если ты исправляешь верстку, напиши потом, когда исправишь замечания, чтобы я посмотрел еще. Я ведь может быть не все проблемы нашел.
>>1074209
Просто сделать отдельный класс, который делает что нужно, и использовать его в твоих 3 контроллерах.
Это надо смотреть документацию по UMI для разработчиков, я не знаю.
>>1071847
Если ты делаешь бота через конструктор,то не знаю. А там нельзя получить код бота и его исправить? Если нельзя, то не знаю как.
>>1071671
[abc] - один любой символ из набора a, b, c
[a-d] - любой символ от a до d
[a-fmn] - любой символ от a до f, или m или n
>>1071608
В один проход наверно никак.
>>1071615
Основы то изучить нетрудно, и learn.javascript.ru пройти. не будешь же за каждой правкой бегать к верстальщику.
>>1071513
> В элементе adr::before когда я ставлю ему контент иконки, он перестает быть inline-block элементом,
Лучше сделать ::before просто блоком или абсолютно позиционированным относительно колонки блоком. В контент поставить пустую строку. Задать размеры. Поставить картинку как фоновую.
Еще вариант - попробовать поставить картинку как фоновую на саму колонку с текстом, расчистив место за счет паддинга, но не уверен что ее можно будет удобно спозиционировать.
>>1071463
> ни в какую не хочет расширяться в fit-content,
Зачем его использовать, он пока толком нигде не поддерживается.
Если ты исправляешь верстку, напиши потом, когда исправишь замечания, чтобы я посмотрел еще. Я ведь может быть не все проблемы нашел.
>>1074209
Просто сделать отдельный класс, который делает что нужно, и использовать его в твоих 3 контроллерах.
Кодировка выбирается в настройках редактора или при сохранении. Нужно выбирать utf-8 without BOM.
Сделал задачу на функцию счетчик:
https://ideone.com/ADY3k4
Правильно? Алсо, лучей добра за объяснение.
static не годится, это по идее глобальная переменная и по идее она там должна бы была быть одна для всех счетчиков. Подумай еще.
Ну или хотя нет, давай тогда изменим задание. В функцию createCounter() должно передаваться начальное значение счетчика, например:
$c1 = createCounter(3);
echo $c1(); // 3
если значение не передано, то оно равняется 1.
trait
>Соответственно, будешь ты использовать аякс или нет - с MVC никак не связано, так как MVC применяется в данном случае для описания только кода на сервере.
Спасибо, стало понятнее.
>Если тебе лень лазать по коду, значит в следующий раз ты просто не сможешь решить проблему.
ох уж эти программисты, так заботятся обо мне, вместо того, чтобы просто ответить
Виртуальный хостинг
>где можно скачать бесплатно и без смс?
Мы в этом итт треде против пиратства и за интеллектуальную собственность. Лучше конечно купить. Но вдруг ты гол как сокол в жерновах вечного постсовкового кризиса? Что ж тебе теперь книжек не читать?
gen.lib.rus.ec
Как регистрировать пользователей через бд я осилил. И они даже потом могут залогиниться. Но стоит нажать на любую другую ссылку, логин пропадает.
Возможно это от того, что при логине меняется PHPSESSID. До логина там одно значение, а после - другое. Нагуглил только, что Yii::$app->user->login($this->getUser() изменяет куку и это нормально. Но в дефолтном примере всё то же самое и работает нормально. Юзер один раз логинится и его логин весит, не отваливаясь.
Вот собственно задача http://dkab.github.io/jasmine-tests/?spec=4
А вот мое неправильное решение:
function fmap(a, gen) {
return function b() {
c = a(gen(arguments[0],arguments[1]));
return c;
}
}
В задании говорится чтобы нужно чтобы gen принимала любое количество аргументов. А я вот не знаю как это сделать. Конечно можно туда тупо передавать массив со всеми аргументами. Но дело в том что функция ген принимает в качестве аргументов два числа. Я конечно бы мог просто переписать этот ген. Но вроде как нужно написать все в этой функции.
Погугли Function.prototype.call и Function.prototype.apply.
Функции в JS это объекты и у них есть прототип с несколькими полезными методами.
что-то я не понимаю как это работает совсем. Прочитал несколько статей и все равно. Какая-то каша фаршу. Может есть какое-то более доступное объяснение?
А тут читал?
- https://learn.javascript.ru/call-apply
- https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
Вот пример:
function f(a, b) { ... }
var context = {};
f.call(context, 100, 200); // вызывает f, передавая ей this = context, a = 100, b = 200
f.apply(context, [100, 200]); // вызывает f, передавая ей this = context, a = 100, b = 200
Вместо context можно передавать null, тогда this будет указывать на глобальный объект (window в браузере, global в Node.JS).
Что именно непонятно? Или тебе непонятны объекты, методы и прототипы?
Непонятно например как функции это объекты.
Да я понял уже что рано залез в задачи. Пошел читать learn.javascript.ru. Просто я не думал что настолько все сложно для меня будет.
Ну не бойся, поначалу там действительно сложно, особенно если ты учился по учебникам, которые обошли эти моменты стороной. Но разобраться в этом можно. Яваскрипт не очень сложный язык. Так что читай learn.javascript.ru и решай задачи как только поймешь, что можешь решить.
> например как функции это объекты.
Ну это особенность языка (довольно удобная), что функции это еще и объекты. То есть когда ты объявляешь функцию, создается объект с прототипом Function. Соответственно, если ты пишешь f() то происходит вызов функции, а если f.x или f.x() то происходит обращение к свойству или методу объекта.
Аналогично и массивы являются объектами, у них тоже есть свойства и методы. И регулярные выражения - это тоже объекты.
Когда ты разберешься, ты увидишь, что это само по себе очень разумно и удобно сделано.
Спасибо за поддержку друг!
>Ну или хотя нет, давай тогда изменим задание. В функцию createCounter() должно передаваться начальное значение счетчика, например:
$c1 = createCounter(3);
echo $c1(); // 3
если значение не передано, то оно равняется 1.
Переделал с новым условием:
https://ideone.com/rATnXa
>>1066512
>>1072015
> `gender` tinyint(1) NOT NULL COMMENT '0 - male, 1 - female',
Тут можно было использовать ENUM 'male', 'female', а в коде для пола прописать константы.
> ADD KEY `gender` (`gender`),
Индексы ускоряют поиск по значению поля, но на поля вроде gender, где по одному значению выбирается полтаблицы или больше, их ставить особого смысла нет (это мельком упомянуто например тут https://ruhighload.com/post/Работа+с+индексами+в+MySQL в пункте про селективность).
Но конечно, окончательный ответ - выгоден индекс или нет - можно получить только тестами.
> extract ($router->getController());
Я не уверен, что хорошая идея так писать, так как непонятно, в какие переменные будет записан результат. По моему опыту, удобно писать либо так:
list($controller, $method) = someFunc();
либо так:
$result = someFunc();
echo $result['controller'];
либо может так:
$result = someFunc();
echo $result->controller;
Я бы не советовал по этой причине использовать тут extract. В других языках вроде Go, есть специальный синтаксис для возврата нескольких значений.
> echo "<b>Искоючение:</b> ", $exception->__toString();
Это хорошо бы отключать на продакшене - например, используя ini-параметр display_errors.
Что касается функций, в принципе никакого запрета использовать функции нет (даже без неймспейсов). Но по моему это неудобно, так как для функций нет автозагрузки и тебе надо вручную их все инклудить. Вдобавок, нет стандарта для выбора имени таких файлов (можешь написать предложение в PSR, если есть идеи). Удобнее просто сделать их статическими методами в классе HtmlUtil например (паттерн utility class). Вроде как у тебя даже это сделано.
Подключать конфиг удобнее в файле dependencies.php - он ведь нужен именно там. А у тебя этот файл полагается на то, что кто-то создаст нужные переменные перед его подключением. Не очень понятно, откуда они берутся.
Что касается констант, удобнее не использовать глобальные константы, а отнести их к какому-то классу. Хотя в общем-то ничего против глобальных констант не имею. Ну и если что, их можно тоже в неймспейсы класть \PageType\HOME или добавить префикс: PAGE_TYPE_HOME. А то не очень понятно, что они обозначают.
> https://github.com/vadimyen/students/blob/master/app/Router.php
Тут лучше передавать URI снаружи, а не делать, чтобы роутер сам его откуда-то магически получал. Будет логичнее: на вход получаем URL, на выходе даем параметры контроллера.
Также, твой роутер имеет недостатки, что одному действию может соответствовать несколько URL:
/, /Index, /Index/, /Index/index
Это плохо для поисковой оптимизации да и не очень логично.
В этом файле съехали отступы https://github.com/vadimyen/students/blob/master/app/Router.php из-за смешивания табов и пробелов. В PSR рекомендуют использовать 4 пробела для отступа, настрой свой редактор.
Далее, ты используешь PHP7, значит используй его возможности и ставь тайп-хинты на string/int/bool, а также тайп-хинты для возвращаемых значений. Это документирует твой код и защищает от ошибок.
В контейнер обычно кладут объекты без состояния, которые можно смело выдать нескольким потребителям и с которыми ничего не случится. Объект Security у тебя имеет состояние, а значит, он должен каждый раз создаваться заново через new либо при выдаче из контейнера (в Pimple такое возможно, смотри factory). Вообще, к сожалению, даже в Симфони можно увидеть несоблюдение этого приципа - они там кладут в контейнер объекты вроде Request, User, итд. Но это плохо по нескольким причинам:
- за счет нахождения в контейнере объекты доступны везде, что скорее плохо: лучше явно передавать их туда, где они нужны
- если мы захотим создать 2 контроллера и параллельно обрабатывать 2 запроса, то это невозможно
- если мы хотим последовательно обработать 2 запроса, то объект, созданный при обработке первого запроса, может попасть в код, обрабатывающий второй запрос
Соответственно создать новый объект Security при создании контроллера куда как логичнее, на мой взгляд. А так получается какая-то кривоватая архитектура.
> } catch (SException $e) {
> die("<b>There's some trouble with your cookie: </b>" . $e->__toString());
не нужно тут ловить исключение, есть же глобальный обработчик. Ну и кривые куки наверно проще игнорировать, чем выдавать ошибку. Пользователь-то что с этим сделает?
https://github.com/vadimyen/students/blob/master/app/Helper/Pager.php
Валидацию параметров лучше наверно делать в контроллере, а не в пагинаторе.
> public function renderPaginator()
Это наверно лучше было бы сделать отдельным шаблоном, а не тащить HTML код в PHP-код.
> private function generateURL($params) {
Функция называется generateUrl, но на деле генерирует только query string.
> public function logIn(Student $student)
> {
> $student->setCookie($this->generateHash(32));
Тут функция не проверяет, что у студента может быть уже есть хеш. может это загруженный из БД студент. У тебя тут неявно заложено, что она должна вызываться в определенной ситуации (до вставуки студента в БД), это очень ненадежно, нет никаких гарантий что функция будет использоваться именно так.
Я бы советовал тогда сделать по-другому, например:
- генерировать хеш при вставке в БД
- или вообще сделать метод регистрации, который и хеш с генерирует, и куки выставит
> public function logout(Student $student)
Справедливости ради, для разлогинивания студент в принципе не нужен
Проверку CSRF наверно стоило отделить от авторизации в отдельный класс. У них ведь ничего общего нет, и твой класс Security выглядит как 2 склеенных вместе класса.
> PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, Student::class, array_fill(0, 8, null)
Ага, вот ты и понял, что PDO не очень удобен для заполнения объектов.
https://github.com/vadimyen/students/blob/master/app/Mapper/StudentMapper.php#L70
Тут нет проверки переменных $field, $direction, получается SQL инъекция
> if (isset($pattern)) {
isset проверяет переменную на существование, лучше писать !is_null или !== null, чтобы яснее были видны намерения.
> public function getStudentsWithPagination(
> public function getStudents
Их можно было бы объединить в одну функцию, добавив для $limit значение 0 или \INF
Ты там собираешь запросы руками, но вообще, знай, что для условной сборки запросов есть паттерн Query Builder и библиотеки с его поддержкой - например, Doctrine DBAL.
https://github.com/vadimyen/students/blob/master/app/Entity/Student.php#L24
конструктор с таким числом аргументов неудобен: легко перепутать их порядок, и неудобно создавать объекты. Лучше либо убрать их вообще, либо предусмотреть возможность передачи массива.
> public function __toString ()
Хочу предупредить, что из-за неявного преобразования в строку можно сразу не заметить ошибку. Ну например, ты думаешь, что в $student лежит id, а там лежит объект. И пытаешься использовать его так:
$query .= " WHERE id = $student ";
Если метода toString нет, это выдаст ошибку. Если же он есть, то ошибка вывалится потом в другом месте и ее труднее будет найти.
> if (filter_var($student->getGender(), FILTER_VALIDATE_INT, ["options" => ["min_range" => 0, "max_range" => 1]]) === false) {
Тут по моему проще in_array было использовать.
Также, в мануале по filter_var написано:
> Возвращает отфильтрованные данные или FALSE, если фильтрация завершилась неудачей.
Это ничего, что ты не используешь возвращаемое значение кроме как для проверки на false?
>>1066512
>>1072015
> `gender` tinyint(1) NOT NULL COMMENT '0 - male, 1 - female',
Тут можно было использовать ENUM 'male', 'female', а в коде для пола прописать константы.
> ADD KEY `gender` (`gender`),
Индексы ускоряют поиск по значению поля, но на поля вроде gender, где по одному значению выбирается полтаблицы или больше, их ставить особого смысла нет (это мельком упомянуто например тут https://ruhighload.com/post/Работа+с+индексами+в+MySQL в пункте про селективность).
Но конечно, окончательный ответ - выгоден индекс или нет - можно получить только тестами.
> extract ($router->getController());
Я не уверен, что хорошая идея так писать, так как непонятно, в какие переменные будет записан результат. По моему опыту, удобно писать либо так:
list($controller, $method) = someFunc();
либо так:
$result = someFunc();
echo $result['controller'];
либо может так:
$result = someFunc();
echo $result->controller;
Я бы не советовал по этой причине использовать тут extract. В других языках вроде Go, есть специальный синтаксис для возврата нескольких значений.
> echo "<b>Искоючение:</b> ", $exception->__toString();
Это хорошо бы отключать на продакшене - например, используя ini-параметр display_errors.
Что касается функций, в принципе никакого запрета использовать функции нет (даже без неймспейсов). Но по моему это неудобно, так как для функций нет автозагрузки и тебе надо вручную их все инклудить. Вдобавок, нет стандарта для выбора имени таких файлов (можешь написать предложение в PSR, если есть идеи). Удобнее просто сделать их статическими методами в классе HtmlUtil например (паттерн utility class). Вроде как у тебя даже это сделано.
Подключать конфиг удобнее в файле dependencies.php - он ведь нужен именно там. А у тебя этот файл полагается на то, что кто-то создаст нужные переменные перед его подключением. Не очень понятно, откуда они берутся.
Что касается констант, удобнее не использовать глобальные константы, а отнести их к какому-то классу. Хотя в общем-то ничего против глобальных констант не имею. Ну и если что, их можно тоже в неймспейсы класть \PageType\HOME или добавить префикс: PAGE_TYPE_HOME. А то не очень понятно, что они обозначают.
> https://github.com/vadimyen/students/blob/master/app/Router.php
Тут лучше передавать URI снаружи, а не делать, чтобы роутер сам его откуда-то магически получал. Будет логичнее: на вход получаем URL, на выходе даем параметры контроллера.
Также, твой роутер имеет недостатки, что одному действию может соответствовать несколько URL:
/, /Index, /Index/, /Index/index
Это плохо для поисковой оптимизации да и не очень логично.
В этом файле съехали отступы https://github.com/vadimyen/students/blob/master/app/Router.php из-за смешивания табов и пробелов. В PSR рекомендуют использовать 4 пробела для отступа, настрой свой редактор.
Далее, ты используешь PHP7, значит используй его возможности и ставь тайп-хинты на string/int/bool, а также тайп-хинты для возвращаемых значений. Это документирует твой код и защищает от ошибок.
В контейнер обычно кладут объекты без состояния, которые можно смело выдать нескольким потребителям и с которыми ничего не случится. Объект Security у тебя имеет состояние, а значит, он должен каждый раз создаваться заново через new либо при выдаче из контейнера (в Pimple такое возможно, смотри factory). Вообще, к сожалению, даже в Симфони можно увидеть несоблюдение этого приципа - они там кладут в контейнер объекты вроде Request, User, итд. Но это плохо по нескольким причинам:
- за счет нахождения в контейнере объекты доступны везде, что скорее плохо: лучше явно передавать их туда, где они нужны
- если мы захотим создать 2 контроллера и параллельно обрабатывать 2 запроса, то это невозможно
- если мы хотим последовательно обработать 2 запроса, то объект, созданный при обработке первого запроса, может попасть в код, обрабатывающий второй запрос
Соответственно создать новый объект Security при создании контроллера куда как логичнее, на мой взгляд. А так получается какая-то кривоватая архитектура.
> } catch (SException $e) {
> die("<b>There's some trouble with your cookie: </b>" . $e->__toString());
не нужно тут ловить исключение, есть же глобальный обработчик. Ну и кривые куки наверно проще игнорировать, чем выдавать ошибку. Пользователь-то что с этим сделает?
https://github.com/vadimyen/students/blob/master/app/Helper/Pager.php
Валидацию параметров лучше наверно делать в контроллере, а не в пагинаторе.
> public function renderPaginator()
Это наверно лучше было бы сделать отдельным шаблоном, а не тащить HTML код в PHP-код.
> private function generateURL($params) {
Функция называется generateUrl, но на деле генерирует только query string.
> public function logIn(Student $student)
> {
> $student->setCookie($this->generateHash(32));
Тут функция не проверяет, что у студента может быть уже есть хеш. может это загруженный из БД студент. У тебя тут неявно заложено, что она должна вызываться в определенной ситуации (до вставуки студента в БД), это очень ненадежно, нет никаких гарантий что функция будет использоваться именно так.
Я бы советовал тогда сделать по-другому, например:
- генерировать хеш при вставке в БД
- или вообще сделать метод регистрации, который и хеш с генерирует, и куки выставит
> public function logout(Student $student)
Справедливости ради, для разлогинивания студент в принципе не нужен
Проверку CSRF наверно стоило отделить от авторизации в отдельный класс. У них ведь ничего общего нет, и твой класс Security выглядит как 2 склеенных вместе класса.
> PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, Student::class, array_fill(0, 8, null)
Ага, вот ты и понял, что PDO не очень удобен для заполнения объектов.
https://github.com/vadimyen/students/blob/master/app/Mapper/StudentMapper.php#L70
Тут нет проверки переменных $field, $direction, получается SQL инъекция
> if (isset($pattern)) {
isset проверяет переменную на существование, лучше писать !is_null или !== null, чтобы яснее были видны намерения.
> public function getStudentsWithPagination(
> public function getStudents
Их можно было бы объединить в одну функцию, добавив для $limit значение 0 или \INF
Ты там собираешь запросы руками, но вообще, знай, что для условной сборки запросов есть паттерн Query Builder и библиотеки с его поддержкой - например, Doctrine DBAL.
https://github.com/vadimyen/students/blob/master/app/Entity/Student.php#L24
конструктор с таким числом аргументов неудобен: легко перепутать их порядок, и неудобно создавать объекты. Лучше либо убрать их вообще, либо предусмотреть возможность передачи массива.
> public function __toString ()
Хочу предупредить, что из-за неявного преобразования в строку можно сразу не заметить ошибку. Ну например, ты думаешь, что в $student лежит id, а там лежит объект. И пытаешься использовать его так:
$query .= " WHERE id = $student ";
Если метода toString нет, это выдаст ошибку. Если же он есть, то ошибка вывалится потом в другом месте и ее труднее будет найти.
> if (filter_var($student->getGender(), FILTER_VALIDATE_INT, ["options" => ["min_range" => 0, "max_range" => 1]]) === false) {
Тут по моему проще in_array было использовать.
Также, в мануале по filter_var написано:
> Возвращает отфильтрованные данные или FALSE, если фильтрация завершилась неудачей.
Это ничего, что ты не используешь возвращаемое значение кроме как для проверки на false?
>>1066512
>>1072015
https://github.com/vadimyen/students/blob/master/app/View/index/index.php#L1
> <?php extract($params); ?>
Это лучше наверно было сделать в методе render()
> <a href="/?<?=$pager->getSortingLink('firstName')?>">
Если строго говорить, то тут данные должны тоже экранироваться. Что, если там кавычка или знак &?
https://github.com/vadimyen/students/blob/master/app/View/index/index.php#L31
> <?php if(isset($students)) :
Вот это мне не нравится, что переменная может быть, а может не быть. Как тогда код писат надежно в таких условиях?
https://github.com/vadimyen/students/blob/master/app/View/profile/index.php#L4
Вот этот use тут - плохо. Надо хотя бы переместить его в самый верх файла.
> echo "<li>{$value}</li>";
echo не используют в шаблонах, данные нужно экранировать.
> required=""
Можно просто required
> value="<?=isset($user) ? html($user->getFirstName()) : ""?>
Вот опять же, isset тут плохо. Лучше создать пустой объект.
https://github.com/vadimyen/students/blob/master/app/Controller/ProfileController.php#L30
> try {
> $this->isSubmitted();
> } catch(SException $e) {
> header('Location: /profile');
> exit();
> }
Вот это странно смотрится, почему метод с названием isSubmitted выбрасывает исключение? Не лучше ли было бы сделать if (!$this->isSubmitAllowed()) ... ? Ну и редиректить молча тоже нехорошо, надо хотя бы в URL код ошибки добавить или страницу ошибки показать.
https://github.com/vadimyen/students/blob/master/app/Controller/ProfileController.php#L61
> private function getProcessedData() {
Не лучше сразу заполнить объект Student вместо передачи туда-сюда массивов?
> if ($isNew) {
> $student = new Student(...$args);
Очень неудачно так как этот код полагается на то, что переменные в getProcessedData() идут в том де порядке, что и в конструкторе, это нигде не документировано и сломается при первой же правке.
Лучше сделать так:
- обработку GET и POST сделать в одном методе
- алгоритм примерно такой:
Если (юзер залогинен) {
$user = загрузить данные из БД ;
} иначе {
$user = пустой объект;
}
Если (форма отправлена) {
обновить $user значениями из POST;
}
...
А у тебя там все очень хрупко. Ну например у тебя при обновлении может сброситься хеш или другие значения полей, которых нет в форме. Так как ты создаешь новый объект из данных формы.
В случае успешной обработки формы надо редиректить для защиты от повторной отправки, посмотри мой урок про формы на гитхабе.
Так, в общем сделано неплохо. Подправить код и будет совсем хорошо.
Не знаю, думал еще предложить тебе сделать тесты, но наверно это будет рановато и может быть их лучше сделать к следующей задаче.
>>1066512
>>1072015
https://github.com/vadimyen/students/blob/master/app/View/index/index.php#L1
> <?php extract($params); ?>
Это лучше наверно было сделать в методе render()
> <a href="/?<?=$pager->getSortingLink('firstName')?>">
Если строго говорить, то тут данные должны тоже экранироваться. Что, если там кавычка или знак &?
https://github.com/vadimyen/students/blob/master/app/View/index/index.php#L31
> <?php if(isset($students)) :
Вот это мне не нравится, что переменная может быть, а может не быть. Как тогда код писат надежно в таких условиях?
https://github.com/vadimyen/students/blob/master/app/View/profile/index.php#L4
Вот этот use тут - плохо. Надо хотя бы переместить его в самый верх файла.
> echo "<li>{$value}</li>";
echo не используют в шаблонах, данные нужно экранировать.
> required=""
Можно просто required
> value="<?=isset($user) ? html($user->getFirstName()) : ""?>
Вот опять же, isset тут плохо. Лучше создать пустой объект.
https://github.com/vadimyen/students/blob/master/app/Controller/ProfileController.php#L30
> try {
> $this->isSubmitted();
> } catch(SException $e) {
> header('Location: /profile');
> exit();
> }
Вот это странно смотрится, почему метод с названием isSubmitted выбрасывает исключение? Не лучше ли было бы сделать if (!$this->isSubmitAllowed()) ... ? Ну и редиректить молча тоже нехорошо, надо хотя бы в URL код ошибки добавить или страницу ошибки показать.
https://github.com/vadimyen/students/blob/master/app/Controller/ProfileController.php#L61
> private function getProcessedData() {
Не лучше сразу заполнить объект Student вместо передачи туда-сюда массивов?
> if ($isNew) {
> $student = new Student(...$args);
Очень неудачно так как этот код полагается на то, что переменные в getProcessedData() идут в том де порядке, что и в конструкторе, это нигде не документировано и сломается при первой же правке.
Лучше сделать так:
- обработку GET и POST сделать в одном методе
- алгоритм примерно такой:
Если (юзер залогинен) {
$user = загрузить данные из БД ;
} иначе {
$user = пустой объект;
}
Если (форма отправлена) {
обновить $user значениями из POST;
}
...
А у тебя там все очень хрупко. Ну например у тебя при обновлении может сброситься хеш или другие значения полей, которых нет в форме. Так как ты создаешь новый объект из данных формы.
В случае успешной обработки формы надо редиректить для защиты от повторной отправки, посмотри мой урок про формы на гитхабе.
Так, в общем сделано неплохо. Подправить код и будет совсем хорошо.
Не знаю, думал еще предложить тебе сделать тесты, но наверно это будет рановато и может быть их лучше сделать к следующей задаче.
Привет.
Сверстал макет, понимаю html+css, основы php, отличу get от post, базовые знания ООП, что делать дальше не знаю, в интернетах нет толковых книг по php+sql с хорошими практическими задачками вроде тех которые в ОП посте. Вот по блядскому питону миллиарды книг на торрентах, по парсингу, хуярсингу, графике и проч.
Просмотрел курс Русакова, вполне сносно, вкратце поясняет и дает задачки, в отличии от СПЕЦЫАЛИСТА где за 15 часов поясняют что такое условия иф елсе и циклы.
Вроде как пхп один из самых "хайповых" языков, а путных книг вовсе нет, книг которые дали бы сильную базу от А до Я.
Короче хуй знает что со всеми этими знаниями делать, база есть, идей нет.
Чем занимаюсь сейчас? Читаю книжку по ООП и учу SQL, нахуя? Сам не знаю.
То есть, всё же, считывать нажатие на кнопку не контроллером, а js-скриптом - это правильно? Но я тогда не понимаю, как это согласуется с моделью MVC. Не претендует ли скрипт на роль второго контроллера?
ОМГ, что у тебя за каша в голове? Тебе надо подучить матчасть. Контроллер ничего не считывает, он принимает запрос от клиента и ему пофиг каким образом этот запрос на стороне клиента был сформирован, через жс, напрямую формой в браузере отправлено либо через какой-нибудь Postman вручную созданный запрос. Его задача принять запрос и обработать его - все. Бэкенд никак твой фронтэнд не считывает и ему по большому счету плевать, что у тебя на фронте (ну, если только это не какой-нибудь говно-мутант типа C# WebForm, но оно тебе не надо). Модель MVC это вообще про другое. Скрипт может быть контроллером, т.к. во фронтенде тоже можно реализовать тот же MVC - гугли про фронт энд фреймворки.
Но перед этим сначала возьми и перечитай книги по пыхе заново, чтобы базовые знания в мозгах появились. Пока их там нет, отсюда и все твои проблемы с непониманием того как надо и как не надо.
На кодеварс есть сложные задачи по всем языкам.
Рег. выражение на проверку авт. номеров верное?
На regex101 оно никак не выделяет примеры.
пофиксил скобочку на квадратную у тебя в регулярках и все сработало
https://ideone.com/I7zfCZ
мимо>>1075168 который сам в регулярках запутался немного
Типа arr = ["хуе","моё","залупа","якорь"];
function fn(a,b){
return a-b;
}
arr.sort(fn());
залупа,моё,хуе, якорь
Как оно сортирует? Расскажите пожалуйста.
посмотрел твои ифы. это можно сделать через подборку элементов массива с помощью команды foreach. Быстренько написал, но должно быть понятно. https://ideone.com/NIcPaE.
>не выделяет
Вроде работает, но я сам этим сайтом не пользуюсь пока поэтому весь функционал не знаю: https://regex101.com/r/oHw9aW/1
Самыми полезными я считаю ревью ООП задач. Интересно, что тут много анонов несправедливо считают все эти задачи абстрактными и оторванными от реальности. А я решал их все + скидки и калькулятор с поддержкой чисел произвольной длины и скажу следующее: советы ОПа научили меня прагматичному и осторожному подходу к выделению абстракций, избавили от догматизма в отношении паттернов (теперь для меня паттерн - это прежде всего идея, а не диаграмма классов). Юнит-тесты помогли лучше понять DI и инкапсуляцию. Думаю, эти концепции более масштабируемы и универсальны, чем любые фреймворки. Этот фундамент позволяет сейчас без особого труда читать исходники фреймворков. Очень жизненными оказались задачи на SQL и JS.
Так что ОП учит правильными вещам за что ему ещё раз большое спасибо!
Я думаю если ты будешь сюда заходить и помогать начинающим это будет лучшим спасибом.
Функция-компаратор передается для того, чтобы делать сортировку по произвольным правилам. эта функция получает на вход 2 каких-то элемента из массива и должна решить, какой из них "больше" (должен быть в конце), а какой "меньше" (должен идти в начале). Она должна вернуть 0, если элементы равны, отрицательное число если a < b (a идет раньше b) и положительное, если наоборот.
function (a, b) { return a - b; } сравнивает 2 числа. Твой пример неправльный так как у тебя строки и их нельзя вычитать (точнее нет смысла). То есть исправь код для начала.
https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Ну и ты написал sort(fn()) то есть в sort передается не функция, а undefined и соответственно идет обычная сортировка без функции-компаратора. У тебя там в каждой строчке ошибка. Надо не бездумно копировать код, или писать "по интуиции" а читать мануал и понимать что каждый символ значит.
Я бы очень хотел, чтобы тех, кто пишет "по интуиции" даже на собеседование не звали. Такие в отрасли нам не нужны.
Беда в том что необходимо включать опцию R1C1 в настройках Excel
https://i.gyazo.com/7c14ef13405d8a56a5337a72fafd630b.png
https://i.gyazo.com/30b8c8f94e101c7d04f9da59b744437e.png
Есть ли вариант сделать для совсем отсталых пользователей сохранение excel файла с уже активным данным параметром и представления столбцов в числовом виде?
Потому что клиент использует модуль импорта excel файла и он настроен так что числовой формат столбцов считывает, а с буквами - нет... В общем нужно как то настроить выгрузку без указаний лишних указаний типа - а сделайте так, а включите это...
Давай пользователям для заполнения готовый шаблон, где нужные опции уже включены. Это не поможет?
Может конечно ссылки и можно конвертировать в PHP, но это будет сложно, нужно анализировать формулы...
Я не заметил просто что скобочки указал в передаваемом аргументе-функции, я просто хотел, чтобы мне объяснили как оно работает. Просто такая функция указывается для сортировки числовых значений например. Я понимаю если бы в функции возвращался один из входящих аргументов после сравнения. Я не понимаю как возвращаемая разность может сортировать.
https://learn.javascript.ru/array-methods#сортировка-метод-sort-fn
А для полного понимания рекомендую написать пару сортировок самому. Простые - "пузырьком" и "вставками", сложные - "слиянием" и "быстрая".
>>1075214
\+7|8
Тут нужно экранировать +, так как это спецсимвол: https://regex101.com/r/1hHXt8/1
Микрофреймворк - у ОПа есть задачка для него на файлообменник. Когда с ним разберешься - тебе многое станет более ясным когда начнешь с какими-то жирными фреймворками разбираться, как раз познакомишься с psr
Спасибо огромное!
a - b возвращает:
число < 0 если a < b
0 если a = b
число > 0 если a > b
То есть a - b по сути сравнивает, какое число больше.
Функция не должна возвращать аргуименты, а должна их сравнивать и вернуть, какой из них должен идти раньше. Она возвращает не аргумент, а ноль, отрицательное или положительное число.
Мне снова повезло, и я решил проблему выполнив:
UPDATE mysql.user SET plugin='' WHERE User='root';
FLUSH PRIVILEGES;
https://zalinux.ru/?p=1135
Но что за плагин(ы) я, так бездумно, отключил?
И как бы было "правильнее" решить эту проблему?
Ого вот она как все просто оказалось! Почему-то в мануале про это не пишут. Спасибо анон! Наконец-то понятно стало.
Хотя пишут. Просто я думал это частный случай.
Добавляйтесь!
Я бы пошел, но ни опыта, ни знаний нету. Идея хорошая, но думаю нужно писать о ней за пару дней до. Удачи!
Это нормально. У меня тоже нет опыта и знаний почти нет. Но я предлагаю встретиться всем, независимо от уровня знаний. Приходи, не сегодня, так в следующий раз.
Это одна из самых больших проблем PHP, потому что язык изначально предназначался для простых задач и писали его как попало. Были предложения привести стандартные функции к единому виду, но сейчас всё глухо: https://wiki.php.net/rfc/consistent_function_names
Но проблема исправляется сторонними пакетами. Советую для простых задач использовать symfony/filesystem, который не умалчивает ошибки, а бросает исключения: https://github.com/symfony/filesystem/blob/master/Filesystem.php#L92+L110
По моему этот класс вообще не нужен, но у разработчиков PHP было на этот счет другое мнение. Зачем он нужен, лучше наверно спрашивать у них.
Одна из идей ООП в том, что у нас есть классы, представляющие разные виды сущностей. В них есть определенные поля и методы.
В stdClass нет ни полей, ни методов, и на мой взгляд, это больше похоже на массив, чем на объект. Только на неполноценный массив, так как функции вроде array_keys с ним не работают.
>Тут можно было использовать ENUM 'male', 'female', а в коде для пола прописать константы.
>Сначала так и хотел, но почитав всякие stackoverflow отчего-то передумал (точно не помню, так как начал делать очень давно, но всякие сессии, дипломы, военкоматы оторвали меня от пыхи)
>echo "<b>Искоючение:</b> ", $exception->__toString();
>Это хорошо бы отключать на продакшене - например, используя ini-параметр display_errors.
То есть тут лучше вообще эту строку убрать и сделать заголовки на ошибку сервера, помимо display_erorrs?
>Далее, ты используешь PHP7, значит используй его возможности и ставь тайп-хинты на string/int/bool, а также тайп-хинты для возвращаемых значений. Это документирует твой код и защищает от ошибок.
>По-моему, у Зандстры в начале книги было, что со скалярами так лучше не делать, только с классами, как я понимаю из-за нестрогой типизации.
>https://github.com/vadimyen/students/blob/master/app/Mapper/StudentMapper.php#L70
>Тут нет проверки переменных $field, $direction, получается SQL инъекция.
bindValue для 'order by :field :direction' не работает. У меня это проверяется в Pagere'е, хотя, согласен, странно это, лучше в контроллере валидацию делать, у тебя это справедливо замечено. С другой стороны, если пагинатор нужен на нескольких страницах, то неудобно каждый раз валидацию в контроллерах дублировать (хоть и мало кода там), а в классе самого пагинатора очень даже удобно (можно просто передать нужные моля и все-такое), но опять-таки потом обратно для маппера вытаскивать отвалидированные значения – что-то не то.
>В контейнер обычно кладут объекты без состояния, которые можно смело выдать нескольким потребителям и с которыми ничего не случится. Объект Security у тебя имеет состояние, а значит, он должен каждый раз создаваться заново через new либо при выдаче из контейнера (в Pimple такое возможно, смотри factory).
Состояние в данном случае – это имитация stateful за счет куки и объект будто бы живет на протяжении многих запросов или имеется в виду наличие важных полей?
>public function logout(Student $student)
>Справедливости ради, для разлогинивания студент в принципе не нужен
>А разве в бд не надо очищать поле с кукой. Насчет куки еще: ее не надо как-то хешировать? Просто если взломать бд, то там будет кука лежать, любую вставляй себе в браузер да используй, в отличие от ситуации с password_hash/password_verify.
>PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, Student::class, array_fill(0, 8, null)
>Ага, вот ты и понял, что PDO не очень удобен для заполнения объектов.
А какая есть альтернатива, ну кроме Doctrine и других библиотек (они же вроде тоже поверх PDO)?
>https://github.com/vadimyen/students/blob/master/app/Entity/Student.php#L24
>конструктор с таким числом аргументов неудобен: легко перепутать их порядок, и неудобно создавать объекты. Лучше либо убрать их вообще, либо предусмотреть возможность передачи массива.
Согласен (благо phpstorm помогает с параметрами), а какая альтернатива, сеттеры в отдельности? А с массивом как, передать ассоциативный массив и в конструкторе его проитерировать и присвоить каждому свойству класса значения соответствующего ключа?
>>1074718
>https://github.com/vadimyen/students/blob/master/app/View/index/index.php#L31
<?php if(isset($students)) :
>Вот это мне не нравится, что переменная может быть, а может не быть. Как тогда код писат надежно в таких условиях?
То есть тут по смыслу не подходит? Лучше !is_null? Я это писал в расчетом на то, если еще ни один студент не зарегистрировался
>Вот этот use тут - плохо. Надо хотя бы переместить его в самый верх файла.
Я исправил, но вопрос: use в шаблонах вообще никак? А то неудобно полное имя класса для экранирования (сделал статическим методом теперь, а не просто функцией), например, каждый раз писать.
>Вот опять же, isset тут плохо. Лучше создать пустой объект.
Как создать пустой объект? Убрать все тот же конструктор, ну или значение дефолтные null прописать (не особо надежно и удобно).
>Вот это странно смотрится, почему метод с названием isSubmitted выбрасывает исключение? Не лучше ли было бы сделать if (!$this->isSubmitAllowed()) ... ? Ну и редиректить молча тоже нехорошо, надо хотя бы в URL код ошибки добавить или страницу ошибки показать.
Согласен, но а если метод переименовать, ну типа checkForm. Просто я думал, что подделка формы – это исключительная ситуация, а так да по названию не подходит, с редиректом тоже согласен, то есть шлю заголовок с кодом 500?
С остальным согласен вроде без вопросов.
Спасибо большое, многое уже переделал после твоего обзора. Спрашиваю, чтобы лучше понять и больше уяснить. Зандстру пока только половину осилил, к сожалению, очень скучно идет, хоть всё и толково, в отличие от серии You Don't Know JS, даже на английском, ее тут всем рекомендую.
>Тут можно было использовать ENUM 'male', 'female', а в коде для пола прописать константы.
>Сначала так и хотел, но почитав всякие stackoverflow отчего-то передумал (точно не помню, так как начал делать очень давно, но всякие сессии, дипломы, военкоматы оторвали меня от пыхи)
>echo "<b>Искоючение:</b> ", $exception->__toString();
>Это хорошо бы отключать на продакшене - например, используя ini-параметр display_errors.
То есть тут лучше вообще эту строку убрать и сделать заголовки на ошибку сервера, помимо display_erorrs?
>Далее, ты используешь PHP7, значит используй его возможности и ставь тайп-хинты на string/int/bool, а также тайп-хинты для возвращаемых значений. Это документирует твой код и защищает от ошибок.
>По-моему, у Зандстры в начале книги было, что со скалярами так лучше не делать, только с классами, как я понимаю из-за нестрогой типизации.
>https://github.com/vadimyen/students/blob/master/app/Mapper/StudentMapper.php#L70
>Тут нет проверки переменных $field, $direction, получается SQL инъекция.
bindValue для 'order by :field :direction' не работает. У меня это проверяется в Pagere'е, хотя, согласен, странно это, лучше в контроллере валидацию делать, у тебя это справедливо замечено. С другой стороны, если пагинатор нужен на нескольких страницах, то неудобно каждый раз валидацию в контроллерах дублировать (хоть и мало кода там), а в классе самого пагинатора очень даже удобно (можно просто передать нужные моля и все-такое), но опять-таки потом обратно для маппера вытаскивать отвалидированные значения – что-то не то.
>В контейнер обычно кладут объекты без состояния, которые можно смело выдать нескольким потребителям и с которыми ничего не случится. Объект Security у тебя имеет состояние, а значит, он должен каждый раз создаваться заново через new либо при выдаче из контейнера (в Pimple такое возможно, смотри factory).
Состояние в данном случае – это имитация stateful за счет куки и объект будто бы живет на протяжении многих запросов или имеется в виду наличие важных полей?
>public function logout(Student $student)
>Справедливости ради, для разлогинивания студент в принципе не нужен
>А разве в бд не надо очищать поле с кукой. Насчет куки еще: ее не надо как-то хешировать? Просто если взломать бд, то там будет кука лежать, любую вставляй себе в браузер да используй, в отличие от ситуации с password_hash/password_verify.
>PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, Student::class, array_fill(0, 8, null)
>Ага, вот ты и понял, что PDO не очень удобен для заполнения объектов.
А какая есть альтернатива, ну кроме Doctrine и других библиотек (они же вроде тоже поверх PDO)?
>https://github.com/vadimyen/students/blob/master/app/Entity/Student.php#L24
>конструктор с таким числом аргументов неудобен: легко перепутать их порядок, и неудобно создавать объекты. Лучше либо убрать их вообще, либо предусмотреть возможность передачи массива.
Согласен (благо phpstorm помогает с параметрами), а какая альтернатива, сеттеры в отдельности? А с массивом как, передать ассоциативный массив и в конструкторе его проитерировать и присвоить каждому свойству класса значения соответствующего ключа?
>>1074718
>https://github.com/vadimyen/students/blob/master/app/View/index/index.php#L31
<?php if(isset($students)) :
>Вот это мне не нравится, что переменная может быть, а может не быть. Как тогда код писат надежно в таких условиях?
То есть тут по смыслу не подходит? Лучше !is_null? Я это писал в расчетом на то, если еще ни один студент не зарегистрировался
>Вот этот use тут - плохо. Надо хотя бы переместить его в самый верх файла.
Я исправил, но вопрос: use в шаблонах вообще никак? А то неудобно полное имя класса для экранирования (сделал статическим методом теперь, а не просто функцией), например, каждый раз писать.
>Вот опять же, isset тут плохо. Лучше создать пустой объект.
Как создать пустой объект? Убрать все тот же конструктор, ну или значение дефолтные null прописать (не особо надежно и удобно).
>Вот это странно смотрится, почему метод с названием isSubmitted выбрасывает исключение? Не лучше ли было бы сделать if (!$this->isSubmitAllowed()) ... ? Ну и редиректить молча тоже нехорошо, надо хотя бы в URL код ошибки добавить или страницу ошибки показать.
Согласен, но а если метод переименовать, ну типа checkForm. Просто я думал, что подделка формы – это исключительная ситуация, а так да по названию не подходит, с редиректом тоже согласен, то есть шлю заголовок с кодом 500?
С остальным согласен вроде без вопросов.
Спасибо большое, многое уже переделал после твоего обзора. Спрашиваю, чтобы лучше понять и больше уяснить. Зандстру пока только половину осилил, к сожалению, очень скучно идет, хоть всё и толково, в отличие от серии You Don't Know JS, даже на английском, ее тут всем рекомендую.
С разметкой облажался чуток
ОП еще тут? Что скажешь об этом треде:
>>1075881 (OP)
Пхп может как-то объективно заменить баш/питон/Windows Script Host в качестве основного языка написания сценариев автоматизации, задачек для крона по обслуживанию системы (например, синхронизации, бэкапы, рассылки, скачивание всяких обнов), задания для пакетной обработки (имейджмэджиком или ффмпегом, например)? Как у пхп с многопоточностью, распараллеливанием выполнения, обменом данными между потоками, объединением, как с интерактивом...?
Для нас существует CSS3 версия, но она на бета-тесте, хоть и многие браузеры постепенно поддерживают ее характеристики, она не идеальна для обычного использования.
Читайте вот это - https://www.w3.org/TR/CSS22/
Это версия CSS 2.2, можно сказать текущий стандарт (Т.е поддерживается она даже на IE6-9)
Однако чтобы не путаться читаем это: https://www.w3.org/TR/css-2017/ тут описана последняя принятая версия и все все все.
Это относится к новичкам, я так сказать предотвращаю заблуждения.
Тебе стоило бы еще дополнить, что формально стандарт CSS3 - это набор дополнений (модулей) к CSS2.2 (раньше было к CSS2.1). Ну например, там есть Selectors Level 3, CSS Color Level 3 и так далее.
Но CSS2 все равно остается как основа.
Также, тебе стоило бы дать ссылку на список изменений в CSS2.2 относительно CSS2.1 - https://www.w3.org/TR/CSS22/changes.html
Из нее видно, что изменения в основном косметические, а не принципиальные.
> Это версия CSS 2.2, можно сказать текущий стандарт (Т.е поддерживается она даже на IE6-9)
Ну это уже неправда. Как она может поддерживаться на ИЕ6 если он выпущен много лет назад? Не вводи людей в заблуждение, старые браузеры поддерживают CSS2.1 (точнее должны поддерживать).
Я ниже написал:
>Однако чтобы не путаться читаем это: https://www.w3.org/TR/css-2017/ тут описана последняя принятая версия и все все все.
Я думаю человек пройдя к снэпшоту (В котором с нуля написано обо всем и даются источники) все это поймет и увидит.
По идее 2.2 > 2.1 > 2 > 1 т.е спецификация включает в себя предупреждения в которых описано где этот стандарт имеет свое начало(Т.е ссылки там дают) и я думаю каждый с этим ознакомится когда дойдет дело. В модуле 2.2 есть все принятые положения с прошлых уровней, только исправленные или дополненные, либо же переформулированные положения элементов. Так же уровень 3 содержит в себе источник на 2.2. Сложно назвать CSS2 основой, т.к не зря же создается 2.2 ? Эти принципы действуют в старых версиях к которым не прикасались.
Но да с IE6 я погорячился
А да, при открытий страницы вот что происходит - This specification defines Cascading Style Sheets level 2.
Т.е как бы понятно, что 2 это 2.2, только "Revision" т.е пересмотренная версия.
Насчет версий:
CSS2.0 - это устаревшая версия, которая была актуальна еще до IE6 (то есть ранее 2000-2002 года). Она неактуальна. Если интересно, IE6 и IE7, которые должны бы были использовать CSS2.1, местами используют CSS2.0, но это уже неактуальная информация, так как никто под эти браузеры не верстает.
CSS2.1 - эта версия использовалась где-то с 2003 года.
CSS2.2 - это современная немного доработанная CSS2.1. Отличия очень небольшие и перечислены тут https://www.w3.org/TR/CSS22/changes.html .
CSS3, 4 - он сделан в виде отдельных модулей, которые работают поверх CSS2.2.
В Вики даже есть картинка: https://en.wikipedia.org/wiki/File:CSS3_taxonomy_and_status-v2.png
>CSS2.1 - эта версия использовалась где-то с 2003 года.
"Cascading Style Sheets Level 2 Revision 1 (CSS 2.1) Specification", B. Bos, T. Çelik, I. Hickson, H. W. Lie, 7 June 2011
Т.е 2.1 версия разрабатывалась давно еще с 2003 года по 2011?
В спецификации говорят, что мол, никаких 3, 4, 5, 6 уровней не существует, мол это как ты сказал модули.
В википедии написано: https://en.wikipedia.org/wiki/Cascading_Style_Sheets#CSS_2.1
> To comply with the W3C Process for standardizing technical specifications, CSS 2.1 went back and forth between Working Draft status and Candidate Recommendation status for many years. CSS 2.1 first became a Candidate Recommendation on February 25, 2004, but it was reverted to a Working Draft on June 13, 2005 for further review. It returned to Candidate Recommendation on 19 July 2007 and then updated twice in 2009. However, because changes and clarifications were made, it again went back to Last Call Working Draft on 7 December 2010.
> CSS 2.1 went to Proposed Recommendation on 12 April 2011.[40] After being reviewed by the W3C Advisory Committee, it was finally published as a W3C Recommendation on 7 June 2011
Вот так вот, ее окончательно приняли как рекомендацию уже когда начал появляться CSS3. Веб, он такой, фичи реализуют не дожидаясь стандартов.
Все же я думаю нужно отталкиваться от 2.2 держа в уме основу.
Кошмар какой! Даже подумать о таком страшно. Ты прав.
Няша, еще один вопрос, если позволишь. У тебя случайно нет урока или какого-нибудь чужого гайда под рукой по интенсивному изучению (#quick_start, #обучение_через_использование) imagemagick (imagick) и ffmpeg? Особенно в связке с PHP. Официальная документация очень большая, написана сложным техническим английским, слишком много теории, слишком мало примеров и практики, воды много, при этом ненаглядно и слишком много говна приходится гуглить, а хочется наоборот (что-то вроде howtogit только howtoimagick и howtoffmpeg ну или ffmpegtherightway, если хотите).
Занимаюсь пока выучкой CSS, ну там практикую элементы, проверяю свойства.
Кстати ОП, даже на IE6 отображается годно, не думал что форматирование так может улучшить. Но конечно же критика на тебе.
Хотел спросить зачем делать тесты - прочитал урок codedokode, и сразу все вопросы отпали.
как можно проверить чисто на компьютере мобильную верстку? Уменьшать окно браузера до нужных величин? Но метатеги сайта все равно будут знать что это компьютер, правильно? Может, есть какой-нибудь ресурс, куда урл сайта грузишь, а он тебе предлагает три кнопки: показать на таком мобильном разрешении, на таком или на айподе? Или может в браузере есть такой функционал?
>как можно проверить чисто на компьютере мобильную верстку?
В хроме и мозилле открыть Инструменты разработчика (Ctrl + Shift + I / F12) и Режим адаптивного дизайна (Ctrl + Shift + M).
>Но метатеги сайта все равно будут знать что это компьютер, правильно?
О каких метатегах ты говоришь, напомни?
>чисто на компьютере мобильную верстку?
Если прям на серьёзных щах, то только через виртуальную машину, на которой будет эмулятор этого устройства. Что-то вроде того, как мобильные разрабы свои программы для андроидов/айфонов пишут. Написали, скомпилировали - и в эмулятор и сидят ждут, пока прогрузится.
>Я говорю про что-нибудь типа viewport, ему есть разница от того, с какого устройства его запустили, или он просто с размерами окна работает, независимо от устройства?
Конкретно у viewport похоже что - да.
Сравни в режиме адаптивного дизайна примеры на w3c: https://www.w3schools.com/css/css_rwd_viewport.asp
Чтобы больше вопросов не было читай: https://www.w3.org/TR/CSS22/visuren.html
Если не умеешь в англ. то вот суть: viewport это окно агента пользователя (Браузера) и работает относительно любого типа экрана, либо того, который тип это правило определит. Ширина браузера + высота (Окна) и есть viewport.
>>1077074
>Может, есть какой-нибудь ресурс, куда урл сайта грузишь, а он тебе предлагает три кнопки: показать на таком мобильном разрешении, на таком или на айподе?
Да, есть такой сервис https://www.browserstack.com/screenshots
Только долго им не попользуешься, он становиться платным
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => false,
'rules' => [
'test' => 'site/test',
],
Проблема в том, что если я что-о добавляю в rules - всегда вылазит пикрилейтед, если не пишу то все работает. Что вообще происходит? Я так понял он какой-то файл найти не может, как пофиксить эту ошибку?
Суперглобалы это специфичное для PHP штуки, а MVC это универсальная концепция, которая не привязана к какому-то конкретному языку и его особенностям. Даже консольное приложение может быть в MVC. View отрисовывается с помощью ASCII, Controller работает с пользовательским вводом в консоль, а модель остаётся неизменной как для консольного приложения, так и для веб-приложения.
> Хелперы могут к супер глобальным переменным обращаться в MVC?
Обращение к глобальным переменным это всегда плохо: https://github.com/codedokode/pasta/blob/master/arch/di.md#Чем-плохи-глобальные-переменные/
Фреймворки предоставляют готовые абстракции для суперглобалов: https://symfony.com/doc/current/components/http_foundation.html и лучше передавать эти объекты как зависимости хелперу. Пример:
class DownloadHelper
{
public function addDownloadHeaders(Request $request): void
{
if (сервер === апач) {
выставить одни заголовки;
} else if (сервер === nginx) {
выставить другие заголовки;
}
...
}
}
>>1077140
Гугли "очереди сообщений php".
>>1077249
Он имеет в виду технически.
> Также не хотелось бы тянуть для этого большие библиотеки, типа Guzzle. Есть предустановленный curl. Но хотелось бы как можно проще и нативней.
Нативней != проще, а скорее наоборот. Проще использовать готовую абстракцию с объектным интерфейсом, умеющую бросать исключения, а не запоминать кучу флагов для curl_ функций. И ты сравнивал Guzzle и curl-функции по скорости? Я сравнивал и Guzzle не уступал голому curl'у. Ещё Guzzle следует PSR7, а это стандарт, к которому постепенно переходят все популярные фреймворки:
http://symfony.com/blog/psr-7-support-in-symfony-is-here
https://habrahabr.ru/post/304584/
Если кто заинтересован, стучите: adikalon
О себе: 27 лвл. Сейчас разбираю laravel, пытаюсь во фриланс, также знаком с JS и версткой. Если кто-то батрачит на фрилансе, хотел бы услышать советов и напутствий от бывалых
<?= Html::img('@web/images/logo.png', ['alt' => 'My logo']) ?>
В документации пишется, что должно быть <img src="http://example.com/images/logo.png" alt="My logo" />, у мня выходит <img src="images/logo.png" alt="My logo" /> - какого хуя?
У тебя алиас для @web скорее всего не задан. И я не уверен, что @web в методе img должен парситься, для получения алиаса есть специальный геттер, загугли.
Но зачем тебе вообще часть с http://example.com? Задай относительную ссылку, /images/logo.png
$this
Чтобы обращаться к полям объекта, нужно использовать this, например
$this->x = 100;
Также, у тебя не ООП, а массиво-ориентированное программирование. Чтобы был ООП, нужно сделать класс Student представляющий 1 студента с полями вроде name, lastName, и тд. А затем уже класс StudentList который хранит список объектов Student внутри.
Если что, все это описано у меня в учебнике (в ОП посте) в главе по ООП. Попробуй ее прочесть, если не читал.
И писать нужно public function, а не function.
Занят, перезвони попозже.
В кодировке. Файл с данными в одной кодировке, файл со скриптом в другой. Браузер - или куда ты там выводишь текст - неверно определяет кодировку.
>Что такое current и зачем он нужен? В мануале про какой-то "внутренний указатель" пишется.
Там пример есть. Если кратко ответить, то это текущий элемент итерации в цикле.
>>1077933
while нужен чтобы выполнять цикл, когда передаваемый аргумент истинен, а for чтобы выполнить цикл определённое количество раз. Более или менее.
Ознакомься с мануалом и сравни эти функции:
https://secure.php.net/manual/ru/control-structures.for.php
https://secure.php.net/manual/ru/control-structures.while.php
Точно, поменял кодировку в txt-шнике и все заработало, спасибо!
Кавычки убери, дебил.
1) Дан список категорий товаров в виде такого массива:
$categories = [
// id, название, parentId, кол-во товаров
[1, 'Бытовая техника', null, 0],
[2, 'Телевизоры', 1, 0],
[3, 'LCD-телевизоры', 2, 20],
[4, 'Телевизоры с газоразрядным дисплеем', 16],
[5, 'Стиральные машины', 1, 0],
[6, 'Холодильники', 1, 0],
...
];
Для каждого товара указан уникальный id категории, название, id родительской категории или null, если ее нет, количество товаров в этой категории без учета категорий-детей. Используя эти данные:
а) Напиши функцию, которая для любого переданной id категории вернет массив, содержащий id этой категории и всех ее предков, начиная от корня дерева.
Например, для категории 3 вернет массив [1, 2, 3] (Бытовая техника -> Телевизоры -> LCD-телевизоры). А для 1 - массив [1].
б) Напиши функцию, которая для любой категории вернет массив id ее потомков. Например для id = 2 функция должна вернуть массив [3, 4]
в) Напиши функцию, которая вернет массив категорий-сестер (то есть категорий, имеющих того же родителя). Для id = 2 функция должна вернуть массив [5, 6]
г) Напиши функцию, которая выведет список категорий в виде дерева "лесенкой", с указанием числа товаров с учетом дочерних категорий:
Бытовая техника (36)
- Телевизоры (36)
-- LCD-телевизоры (20)
-- Телевизоры с газоразрядным дисплеем (16)
Стиральные машины
Холодильники
2) Дан текст с разметкой, который состоит из "обычного текста" (любые символы, кроме знаков < и >) и "тегов" (конструкций вида <name> или </name>). "Тег" состоит из знака "<", необязательного символа "/", имени из латинских букв и знака ">". Тег со слешем называется "закрывающим", а без слеша - "открывающим". Каждому "открывающему" тегу должен соответствовать "закрывающий", при этом между ними может быть "обычный текст" и/или вложенные внутри пары "тегов".
Примеры пар тегов:
<x></x>
<y>Текст</y>
<a>текст<b>текст</b>текст<c>текст</c>текст</a>
Пример текста с разметкой:
<books>
<book>
<title>80 000 миль вокруг света</title>
<author>Жюль Верн</author>
</book>
<book>
<title>Базы данных на языке SQL</title>
<author>Дж. Д. Джонсон</author>
</book>
</books>
Напиши код, который принимает на вход текст с разметкой и преобразует его в дерево из элементов 2 видов:
- "текстовый блок" - соответствует тексту
- "теги". У тега есть имя. Теги внутри могут содержать блоки текста и другие теги
Если во входном тексте с разметкой есть ошибки синтаксиса (например, нет парного тега или он расположен не в том месте), разбор текста прерывается с сообщением об ошибке.
Затем напиши код, который выведет это дерево в таком виде:
- books
-- book
--- title
---- Text: 80 000 миль вокруг света
--- author
---- Text: Жюль Верн
--book
--- title
---- Text: Базы данных на языке SQL
--- author
---- Text: Дж. Д. Джонсон
Ну и бонусная часть. Предположим, что у нас есть большой текст с разметкой и мы хотим найти в нем определенные элементы. Ну например, в тексте выше мы бы хотели найти все элементы title, которые находятся внутри book, который находится внутри books. Мы бы конечно могли написать код, который это делает, но такой код будет громоздкий, требует времени на написание, в нем легко сделать ошибку. Давай вместо этого попробуем придумать универсальный язык выражений, с помощью которого можно описать путь к элементу, который нам интересен. Например, так:
/ обозначает корень дерева (не соответствует какому-то элементу)
/books - обозначает элемент с названием books в корне дерева
/books/book - обозначает элемент с названием book, родителем которого является books в корне
/books/book/title - думаю, понятно, ищет элементы title
Специальное выражение text() будет обозначать текстовый элемент
/books/book/title/text() - ищет текстовые блоки внутри элемента title
Другое выражение, звездочка * будет обозначать "любой тег" (но не текстовый блок). Например:
/* - ищет теги с любым именем в корне дерева (в примере выше найдет только books)
/*/* - ищет теги с любым именем, и затем всех их детей (в примере выше найдет все элементы book)
Нужно написать функцию, которая принимает дерево элементов и выражение для поиска, и возвращает массив элементов, которые соответствуют выражению.
Затем язык выражений можно усовершенствовать. Ну например, введем такой синтаксис, как a//b - он будет обозначать, что b является потомком элеимента a, при этом между ними может быть любое число элементов. Например:
/books//title - ищет элементы books в корне дерева, а затем ищет элементы title внутри них на любой глубине вложенности
//title - ищет элементы title в любом месте дерева
//text() - ищет все текстовые блоки в любом месте дерева
//* - ищет все теги на любой глубине (в примере выше найдет все books, book, title, author)
//*/*/* - ищет все теги, на любой глубине, у которых есть родитель и прародитель (в примере выше найдет все title и author)
Если ты изучил ООП, стоит его тут использовать для упрощения кода. Если нет - можно писать на массивах и функциях. Не пиши длинные стены кода, разбивай код на отдельные действия-функции, это сильно упростит и написание, и понимание кода.
(да, конечно, "текст с разметкой" это упрощенная версия XML, а выражение для поиска - упрощенная версия XPath).
1) Дан список категорий товаров в виде такого массива:
$categories = [
// id, название, parentId, кол-во товаров
[1, 'Бытовая техника', null, 0],
[2, 'Телевизоры', 1, 0],
[3, 'LCD-телевизоры', 2, 20],
[4, 'Телевизоры с газоразрядным дисплеем', 16],
[5, 'Стиральные машины', 1, 0],
[6, 'Холодильники', 1, 0],
...
];
Для каждого товара указан уникальный id категории, название, id родительской категории или null, если ее нет, количество товаров в этой категории без учета категорий-детей. Используя эти данные:
а) Напиши функцию, которая для любого переданной id категории вернет массив, содержащий id этой категории и всех ее предков, начиная от корня дерева.
Например, для категории 3 вернет массив [1, 2, 3] (Бытовая техника -> Телевизоры -> LCD-телевизоры). А для 1 - массив [1].
б) Напиши функцию, которая для любой категории вернет массив id ее потомков. Например для id = 2 функция должна вернуть массив [3, 4]
в) Напиши функцию, которая вернет массив категорий-сестер (то есть категорий, имеющих того же родителя). Для id = 2 функция должна вернуть массив [5, 6]
г) Напиши функцию, которая выведет список категорий в виде дерева "лесенкой", с указанием числа товаров с учетом дочерних категорий:
Бытовая техника (36)
- Телевизоры (36)
-- LCD-телевизоры (20)
-- Телевизоры с газоразрядным дисплеем (16)
Стиральные машины
Холодильники
2) Дан текст с разметкой, который состоит из "обычного текста" (любые символы, кроме знаков < и >) и "тегов" (конструкций вида <name> или </name>). "Тег" состоит из знака "<", необязательного символа "/", имени из латинских букв и знака ">". Тег со слешем называется "закрывающим", а без слеша - "открывающим". Каждому "открывающему" тегу должен соответствовать "закрывающий", при этом между ними может быть "обычный текст" и/или вложенные внутри пары "тегов".
Примеры пар тегов:
<x></x>
<y>Текст</y>
<a>текст<b>текст</b>текст<c>текст</c>текст</a>
Пример текста с разметкой:
<books>
<book>
<title>80 000 миль вокруг света</title>
<author>Жюль Верн</author>
</book>
<book>
<title>Базы данных на языке SQL</title>
<author>Дж. Д. Джонсон</author>
</book>
</books>
Напиши код, который принимает на вход текст с разметкой и преобразует его в дерево из элементов 2 видов:
- "текстовый блок" - соответствует тексту
- "теги". У тега есть имя. Теги внутри могут содержать блоки текста и другие теги
Если во входном тексте с разметкой есть ошибки синтаксиса (например, нет парного тега или он расположен не в том месте), разбор текста прерывается с сообщением об ошибке.
Затем напиши код, который выведет это дерево в таком виде:
- books
-- book
--- title
---- Text: 80 000 миль вокруг света
--- author
---- Text: Жюль Верн
--book
--- title
---- Text: Базы данных на языке SQL
--- author
---- Text: Дж. Д. Джонсон
Ну и бонусная часть. Предположим, что у нас есть большой текст с разметкой и мы хотим найти в нем определенные элементы. Ну например, в тексте выше мы бы хотели найти все элементы title, которые находятся внутри book, который находится внутри books. Мы бы конечно могли написать код, который это делает, но такой код будет громоздкий, требует времени на написание, в нем легко сделать ошибку. Давай вместо этого попробуем придумать универсальный язык выражений, с помощью которого можно описать путь к элементу, который нам интересен. Например, так:
/ обозначает корень дерева (не соответствует какому-то элементу)
/books - обозначает элемент с названием books в корне дерева
/books/book - обозначает элемент с названием book, родителем которого является books в корне
/books/book/title - думаю, понятно, ищет элементы title
Специальное выражение text() будет обозначать текстовый элемент
/books/book/title/text() - ищет текстовые блоки внутри элемента title
Другое выражение, звездочка * будет обозначать "любой тег" (но не текстовый блок). Например:
/* - ищет теги с любым именем в корне дерева (в примере выше найдет только books)
/*/* - ищет теги с любым именем, и затем всех их детей (в примере выше найдет все элементы book)
Нужно написать функцию, которая принимает дерево элементов и выражение для поиска, и возвращает массив элементов, которые соответствуют выражению.
Затем язык выражений можно усовершенствовать. Ну например, введем такой синтаксис, как a//b - он будет обозначать, что b является потомком элеимента a, при этом между ними может быть любое число элементов. Например:
/books//title - ищет элементы books в корне дерева, а затем ищет элементы title внутри них на любой глубине вложенности
//title - ищет элементы title в любом месте дерева
//text() - ищет все текстовые блоки в любом месте дерева
//* - ищет все теги на любой глубине (в примере выше найдет все books, book, title, author)
//*/*/* - ищет все теги, на любой глубине, у которых есть родитель и прародитель (в примере выше найдет все title и author)
Если ты изучил ООП, стоит его тут использовать для упрощения кода. Если нет - можно писать на массивах и функциях. Не пиши длинные стены кода, разбивай код на отдельные действия-функции, это сильно упростит и написание, и понимание кода.
(да, конечно, "текст с разметкой" это упрощенная версия XML, а выражение для поиска - упрощенная версия XPath).
В массиве есть "внутрненний указатель", который изначально указывает на первый элемент массива, и который можно перемещать к следующему/преддущему элеименту. Ну например, когда ты выполняешь цикл foreach по массиву, он ставит этот указатель на первый элемент, а потом на каждом шаге переставляет на слеюущий, пока не дойдет до конца.
Указателю неважно, какие ключи у элементов (числовые или текстовые) - он ориентируется только на порядок, в котором элементы добавлялись в массив. То есть тот элемент, который был добавлен раньше всех, будет "первым", а тот, который позже всех - "последним". На всякий случай напомню, что в PHP массивы не сортируются по умолчанию и хранят элементы в том порядке, в котором они добавлялись. Например:
$a = [];
$a[10] = 100;
$a[9] = 20;
Здесь в массиве первый элемент имеет ключ 10, а второй - 9, то есть сохраняется порядок, в котором элементы были добавлены.
Ты можешь двигать этот указатель вручную, там есть функции для этого:
reset - ставит указатель на первый элемент и возвращает его значение
next/prev - перемещает указатель на следующий/предыдущий элемент
end - пермещает указатель на последний элемент и возвращает его значение
key - возвращает ключ текущего элемента
current - возвращает значение текущего элемента
Подробности в мануале.
Многие операции с массивами неявно сбраывают или передвигают указатель, например, цикл foreach.
Так, они почти никогда не нужны. Иногда они помогают быстро получить первый/последний элемент, не зная его индекса.
В адаптивной версии в шапке гигансткий текст. Ну то есть лозунг про "digital branding agency" занимает целый экран. Зачем он такой там нужен? Я тебе в третий раз уже наверно напоминаю, что надо подойти к адаптивной версии творчески. То есть, сам лозунг конечно стоит оставить, но уменьшить его до адекватного размера. Также, можно убрать центирование лозунга, оно хорошо смотрится на широком экране, но глупо выглядит на маленькой ширине.
Также, логотип тоже в мобильной версии смотрится сиротливо, занимая целую строку.
Шапку в адаптивной версии надо бы переработать целиком. Продумать, как сделать, чтобы пространство экрана использовалось эффективно. Но без фанатизма - пункты меню не должны быть крошечными, их должно быть удобно нажимать. Я тут попробовал нарисовать вариант, который оптимизирован под маленький экран - получилось конечно тесновато и страшновато, так что хорошо бы, если бы ты сделал что-то среднее между тем что я нарисовал, и тем что сейчас есть. Ну если ты вообще не можешь ничего придумать, то попробуй хотя бы размер текста в лозунге поменять и например сделать логотип частью меню, чтобы он не занимал отдельную строку.
Далее, надо проверить твой HTML валидатором: https://html5.validator.nu/?doc=https://theknacker.github.io/Webpaint/webpaint.html&showimagereport=yes
Нужно посмотреть, что он там пишет и если есть ошибки, исправить их.
Далее, тут:
> <div class="service_item">
> <img src="images/Computer_iMac.png" width="62px" height="59px"/>
В атрибутах width/height разве можно писать px?
> <title>WebPaint</title>
> <meta charset="utf-8">
Это ошибка, кодировка должна идти ДО любых текстов.
> <a href="https://orss.ru/rss_1.html" target="_blank"><img src="images/rss.svg" width="30" height="30" alt="rss"/></a>
Зачем тут img? Разве нельзя сделать иконку просто фоновой картинкой к ссылке?
Далее, что касается обычного текста. Попробуй убрать из body содержимое и вставить обычный текст - он оказывается отцентрирован и смотрится плохо. Надо центрировать только те места, где это требуется, а не весь текст на всей странице по умолчанию. Иначе замучаешься потом отменять это центрирование.
Также, в CSS неправильно залдан шрифт. Если вставить на страницу текст, то абзацы (p) в нем используют один шрифт, а список (ul/li) использует другой шрифт. Это потому, что у тебя неправильно задан шрифт:
> p {
> font: 14px latoregular, serif;
Текст не обязательно заключен в тег <p>. Я уже писал в прошлый раз, что нужно задавать стандартный для страницы шрифт на html или body, а не на отдельных элементах.
Тут еще нашел странное место:
> table {
> max-width: 500px;
Не очень понятно, почему никакая таблица на всем сайте не может быть шире 500px. Зачем поставлено такое ограничение? Если ты хотел ограничить ширину какой-то одной таблицы, то надо было сделать для нее отдельный класс.
Тут ошибка:
> .logo {
> float: left;
> display: inline-block;
при включенном float значение display приравнивается к block. Это какой-то хак для отдельных браузеров?
> .transite, .featured a img, .social img, nav a, .button {
> transition: all 200ms linear;
Почему тут all?
> <a href="tel:0247 541 65 87" class="tel"><div>0247 541 65 87</div></a>
Зачем тут лишний div внутри a? И почему div, а не span? И почему без имени класса?
Сделай отдельную страницу, на которой в body находится только обычный текст с разными стандартными тегами (p, strong, a, em, h1-h6, ul, ol, li, table, img, blockquote), и подключи к ней тот же CSS файл (style.css). Убедись, что все отоображается нормально. Если этого не сделать, то когда на сайт будут добавлять новые страницы, все эти косяки повылезают и придется целиком переделывать верстку.
Дальше я пока проверять не буду, давай ты пока исправишь эти замечания и тогда можно будет двигаться дальше.
Если ты хотел еще подучить CSS, то в моих задачах на HTML есть последние задачи (про переключатель и про вкладки), они вроде относительно сложные.
В адаптивной версии в шапке гигансткий текст. Ну то есть лозунг про "digital branding agency" занимает целый экран. Зачем он такой там нужен? Я тебе в третий раз уже наверно напоминаю, что надо подойти к адаптивной версии творчески. То есть, сам лозунг конечно стоит оставить, но уменьшить его до адекватного размера. Также, можно убрать центирование лозунга, оно хорошо смотрится на широком экране, но глупо выглядит на маленькой ширине.
Также, логотип тоже в мобильной версии смотрится сиротливо, занимая целую строку.
Шапку в адаптивной версии надо бы переработать целиком. Продумать, как сделать, чтобы пространство экрана использовалось эффективно. Но без фанатизма - пункты меню не должны быть крошечными, их должно быть удобно нажимать. Я тут попробовал нарисовать вариант, который оптимизирован под маленький экран - получилось конечно тесновато и страшновато, так что хорошо бы, если бы ты сделал что-то среднее между тем что я нарисовал, и тем что сейчас есть. Ну если ты вообще не можешь ничего придумать, то попробуй хотя бы размер текста в лозунге поменять и например сделать логотип частью меню, чтобы он не занимал отдельную строку.
Далее, надо проверить твой HTML валидатором: https://html5.validator.nu/?doc=https://theknacker.github.io/Webpaint/webpaint.html&showimagereport=yes
Нужно посмотреть, что он там пишет и если есть ошибки, исправить их.
Далее, тут:
> <div class="service_item">
> <img src="images/Computer_iMac.png" width="62px" height="59px"/>
В атрибутах width/height разве можно писать px?
> <title>WebPaint</title>
> <meta charset="utf-8">
Это ошибка, кодировка должна идти ДО любых текстов.
> <a href="https://orss.ru/rss_1.html" target="_blank"><img src="images/rss.svg" width="30" height="30" alt="rss"/></a>
Зачем тут img? Разве нельзя сделать иконку просто фоновой картинкой к ссылке?
Далее, что касается обычного текста. Попробуй убрать из body содержимое и вставить обычный текст - он оказывается отцентрирован и смотрится плохо. Надо центрировать только те места, где это требуется, а не весь текст на всей странице по умолчанию. Иначе замучаешься потом отменять это центрирование.
Также, в CSS неправильно залдан шрифт. Если вставить на страницу текст, то абзацы (p) в нем используют один шрифт, а список (ul/li) использует другой шрифт. Это потому, что у тебя неправильно задан шрифт:
> p {
> font: 14px latoregular, serif;
Текст не обязательно заключен в тег <p>. Я уже писал в прошлый раз, что нужно задавать стандартный для страницы шрифт на html или body, а не на отдельных элементах.
Тут еще нашел странное место:
> table {
> max-width: 500px;
Не очень понятно, почему никакая таблица на всем сайте не может быть шире 500px. Зачем поставлено такое ограничение? Если ты хотел ограничить ширину какой-то одной таблицы, то надо было сделать для нее отдельный класс.
Тут ошибка:
> .logo {
> float: left;
> display: inline-block;
при включенном float значение display приравнивается к block. Это какой-то хак для отдельных браузеров?
> .transite, .featured a img, .social img, nav a, .button {
> transition: all 200ms linear;
Почему тут all?
> <a href="tel:0247 541 65 87" class="tel"><div>0247 541 65 87</div></a>
Зачем тут лишний div внутри a? И почему div, а не span? И почему без имени класса?
Сделай отдельную страницу, на которой в body находится только обычный текст с разными стандартными тегами (p, strong, a, em, h1-h6, ul, ol, li, table, img, blockquote), и подключи к ней тот же CSS файл (style.css). Убедись, что все отоображается нормально. Если этого не сделать, то когда на сайт будут добавлять новые страницы, все эти косяки повылезают и придется целиком переделывать верстку.
Дальше я пока проверять не буду, давай ты пока исправишь эти замечания и тогда можно будет двигаться дальше.
Если ты хотел еще подучить CSS, то в моих задачах на HTML есть последние задачи (про переключатель и про вкладки), они вроде относительно сложные.
Если ты хочешь лучше научиться делать адаптивные версии, то посмотри (с помощью инструментов разработчика в браузере например) как выглядят мобильные версии других сайтов, сравни их с полной версией, например тут:
- booking.com (хотя на мой взгляд, у него довольно перегруженный дизайн, но мобильная версия относительно адекватная)
- geektimes.com
- meduza.io
- reddit.com (но мне не нравится, как он на каждой странице навязывает свое приложение, так делать не надо. И еще мне не нравится прелоадер)
Ты бы посмотрел в документации или в коде, что такое @web и откуда он берется. И тогда может быть будет понятно, куда смотреть дальше.
>>1077140
Ну вообще, можно запустить новый процесс через exec (а лучше Symfony Process) с указанием, что команду надо выполнить в фоне. Разумеется, для этого надо знать основы линукса и bash.
Но такой бесконтрольный запуск процессов это почти всегда плохо, например, нет гарантии что ты не запустишь 2 процесса, которые что-то будут одновременной делать с одиим файлом, нет таймаута и подвисшие процессы могут накапливаться, не логгируются ошибки. Это тупиковый путь.
Лучше использовать системы вроде gearman для выполнения тяжелых задач в фоне. Или крон-таски.
Ну и если тебе результат не важен, так можно наверно вообще ничего не делать, верно?
>>1077196
Посмотри на код Юи. Там стоит @, который должен подавлять ошибку при отсутствии файла. Но у тебя она не подавляется и привыодит к выбросу исключения. Почему? Есть разные версии:
- ты написал свой обработчик ошибок, который игнорирует @
- ты поменял что-то в конфиге PHP, например, включил опцию scream http://php.net/manual/ru/book.scream.php
- ты включил какую-то опцию в Юи, которая включает scream
- ты поставил нестабильную версию Юи, в которой присутствует баг
Я бы начал с изучения документации Юи про обработчик ошибок и про конфигурацию. Мне суть проблемы очевидна с одного взгляда на скриншот, почему ты не попробовал посмотреть на то, что там написано?
>>1077257
Кеш Хрома вообще тут не при чем.
>>1077209
Смотря для чего. Если у тебя метод называется "получить значение куки как целое число" и ты обращаешься к COOKIE, то в принципе можно (хотя конечно красивее было бы передавать объект с куками явно), а если у тебя функция называется "получить рейтинг пользователя", а ты по-тихому лезешь в суперглобальные переменные - то конечно плохо.
Главная проблема - что могут появляться побочные эффекты (вот тут это описано у меня: https://github.com/codedokode/pasta/blob/master/good-code.md#Избегай-побочных-эффектов )
>>1077250
Ты приводишь в пример Симфони и тут же пишешь функцию, которая "выставляет заголовки" в обход объекта Response. С точки зрения удобства использования, нелогично разделять операции "выставление заголовков" и "отдача файла", а логично обьъединить их в функцию, которая принимает на вход например имя файла, а отдает на выходе полноценный сформированный Response:
function createDownloadFileResponse(string $fileName, ParameterBag $server): Response
function createDownloadFileResponse(\SplFileObject $file, ParameterBag $server): Response
(я передаю параметры $_SERVER как ParameterBag, не помню точный тип).
Ты бы посмотрел в документации или в коде, что такое @web и откуда он берется. И тогда может быть будет понятно, куда смотреть дальше.
>>1077140
Ну вообще, можно запустить новый процесс через exec (а лучше Symfony Process) с указанием, что команду надо выполнить в фоне. Разумеется, для этого надо знать основы линукса и bash.
Но такой бесконтрольный запуск процессов это почти всегда плохо, например, нет гарантии что ты не запустишь 2 процесса, которые что-то будут одновременной делать с одиим файлом, нет таймаута и подвисшие процессы могут накапливаться, не логгируются ошибки. Это тупиковый путь.
Лучше использовать системы вроде gearman для выполнения тяжелых задач в фоне. Или крон-таски.
Ну и если тебе результат не важен, так можно наверно вообще ничего не делать, верно?
>>1077196
Посмотри на код Юи. Там стоит @, который должен подавлять ошибку при отсутствии файла. Но у тебя она не подавляется и привыодит к выбросу исключения. Почему? Есть разные версии:
- ты написал свой обработчик ошибок, который игнорирует @
- ты поменял что-то в конфиге PHP, например, включил опцию scream http://php.net/manual/ru/book.scream.php
- ты включил какую-то опцию в Юи, которая включает scream
- ты поставил нестабильную версию Юи, в которой присутствует баг
Я бы начал с изучения документации Юи про обработчик ошибок и про конфигурацию. Мне суть проблемы очевидна с одного взгляда на скриншот, почему ты не попробовал посмотреть на то, что там написано?
>>1077257
Кеш Хрома вообще тут не при чем.
>>1077209
Смотря для чего. Если у тебя метод называется "получить значение куки как целое число" и ты обращаешься к COOKIE, то в принципе можно (хотя конечно красивее было бы передавать объект с куками явно), а если у тебя функция называется "получить рейтинг пользователя", а ты по-тихому лезешь в суперглобальные переменные - то конечно плохо.
Главная проблема - что могут появляться побочные эффекты (вот тут это описано у меня: https://github.com/codedokode/pasta/blob/master/good-code.md#Избегай-побочных-эффектов )
>>1077250
Ты приводишь в пример Симфони и тут же пишешь функцию, которая "выставляет заголовки" в обход объекта Response. С точки зрения удобства использования, нелогично разделять операции "выставление заголовков" и "отдача файла", а логично обьъединить их в функцию, которая принимает на вход например имя файла, а отдает на выходе полноценный сформированный Response:
function createDownloadFileResponse(string $fileName, ParameterBag $server): Response
function createDownloadFileResponse(\SplFileObject $file, ParameterBag $server): Response
(я передаю параметры $_SERVER как ParameterBag, не помню точный тип).
Есть бесплатная версия скриншотов на сайте modern.ie, не требующая регистрации (за счет Майкрософта).
Есть бесплатный, но не идеальный, сервис http://browsershots.org/ - но там нет маков, мобильных устройств, и только Хромы с Фаерфоксами.
Используя оба этих варианта, можно в итоге получить что-то приемлемое.
Кстати, вы бы могли помочь проекту Browsershots, улучшив их Screenshot Factory для других браузеров (как я понимаю, тут можно было бы попробовать интегрировать Selenium, который позволяет управлять не только Хромами и Фаерфоксами), а также написав Screenshot Factory для мобильных устройств.
>>1077066
Что касается верстки, то в инструментах разработчика в браузере есть кнопка для тестирования мобильной верстки. Она делает такие вещи:
- меняет размер окна
- имитирует поведение моб. браузера, например, в отношении тега meta viewport, умеет отображать страницу в уменьшенном масштабе например, позволяет прокручивать страницу перетаскиванием
- выставляет мобильный User-Agent при отправке запросов на сервер
- в Хроме еще есть возможность имитировать медленный интернет
Уменьшение размеров окна вручную, впрочем, позволяет проверить, как верстка ведет себя на небольшой ширине страницы. Но в этом случае например не учитывается значение тега meta viewport.
> Но метатеги сайта все равно будут знать что это компьютер, правильно?
Какие метатеги? Если ты про заголовки, то режим отладки вертски будет их подменять на мобильные.
>>1077072
Ты про метатег meta viewport? Он игнорируется десктопными браузерами при нормальной работе, но в режиме тестирования адаптивной верстки он учитывается.
Есть бесплатная версия скриншотов на сайте modern.ie, не требующая регистрации (за счет Майкрософта).
Есть бесплатный, но не идеальный, сервис http://browsershots.org/ - но там нет маков, мобильных устройств, и только Хромы с Фаерфоксами.
Используя оба этих варианта, можно в итоге получить что-то приемлемое.
Кстати, вы бы могли помочь проекту Browsershots, улучшив их Screenshot Factory для других браузеров (как я понимаю, тут можно было бы попробовать интегрировать Selenium, который позволяет управлять не только Хромами и Фаерфоксами), а также написав Screenshot Factory для мобильных устройств.
>>1077066
Что касается верстки, то в инструментах разработчика в браузере есть кнопка для тестирования мобильной верстки. Она делает такие вещи:
- меняет размер окна
- имитирует поведение моб. браузера, например, в отношении тега meta viewport, умеет отображать страницу в уменьшенном масштабе например, позволяет прокручивать страницу перетаскиванием
- выставляет мобильный User-Agent при отправке запросов на сервер
- в Хроме еще есть возможность имитировать медленный интернет
Уменьшение размеров окна вручную, впрочем, позволяет проверить, как верстка ведет себя на небольшой ширине страницы. Но в этом случае например не учитывается значение тега meta viewport.
> Но метатеги сайта все равно будут знать что это компьютер, правильно?
Какие метатеги? Если ты про заголовки, то режим отладки вертски будет их подменять на мобильные.
>>1077072
Ты про метатег meta viewport? Он игнорируется десктопными браузерами при нормальной работе, но в режиме тестирования адаптивной верстки он учитывается.
я другой анон, спасибо за разъяснение. А поясните, надо ли после форича его обратно на первый ставить? Это критично вообще?
спасибо
Сайт на wordpress, тема tesseract, если важно.
@sslrinc
Зачем ты так все переусложнил и что тебе мешает добавить параметры поиска в URL?
/catalog?model=sony&price=1000&page=2
Просто их очень много. Товаров сотни тысяч, параметров десятки и сотни. И всю вот эту бороду в URL видеть совсем не хочется.
Все равно плохо. С куками во-первых, во всех вкладках будут одни и те же параметры поиска, во-вторых, нельзя сохранить ссылку в закладки, переслать и итд. Никто не делает поиск через POST, его делают через GET.
Я бы советовал посмотреть как в Яндекс-Маркете сделано например и сделать так же. У них тоже параметров много и все работает.
А может ты и прав. Я пожалуй в понедельник на свежую голову подумаю над этим.
Ни кода, ну хуя не показал...
При каждом запросе сохраняй сессию заново и все.
Создай класс-обьект формы поиска.
Например на псевдокоде
class SearchParam
-- searchString: string
-- searchCheckBox: array
На основе него будешь генерировать форму.
При отправке формы у тебя обработчик запроса будет заполнять SearchParam, а ты в свою очередь сохраняй его в сессию.
Потом при следующем запросе просто делай проверку на сущесвование SearchParam в сессии, если нету создавай новый пустой SearchParam и заполняй его из формы.
Так же незабуть сделать кнопку "очистить фильты", которая чистит форму и сессию.
>Зачем тут img? Разве нельзя сделать иконку просто фоновой картинкой к ссылке?
В многих браузерах слетает я заметил, раньше там спрайты стояли, но в мозиле и старых ИЕ все слетает напрочь. А так все остается в порядке.
>В атрибутах width/height разве можно писать px?
Не знал, что автоматически пиксели как единица стоят.
>при включенном float значение display приравнивается к block. Это какой-то хак для отдельных браузеров?
Нет тут скорее всего случайно оставленное значение, я экспериментировал и забыл убрать.
>Не очень понятно, почему никакая таблица на всем сайте не может быть шире 500px.
Это временное значение поставлено, я его позже уберу. Смотрел поведение таблиц просто с текстом.
>Зачем тут лишний div внутри a? И почему div, а не span? И почему без имени класса?
Потому что я забыл про существование span. С этим значение была какая то временная проблема (В связи с кривой версткой) о которой я забыл. Но я его удалю.
>>1078653
Спасибо ОП.
Сейчас я пока читаю это: https://www.w3.org/TR/CSS22/
веришь или нет ОП я сначала изучал CSS3, а не ранние стандарты, и только недавно осознал, что проще чем выучить стандарт нет ничего и что я больше времени потерял. После 22 перейду на модули. В планах сейчас уже хорошо бы и правильно забить в голову стандарты и исправить ошибки в дальнейшем. Т.е пока попробую значения все, а параллельно буду скидывать работу по сайту.
Да кстати круто сделали.
>reddit.com
>но мне не нравится, как он на каждой странице навязывает свое приложение, так делать не надо. И еще мне не нравится прелоадер
А этот div.side с поиском, логином с рекламой и паролем как тебе?
Не знаю, сайдбар как сайдбар, на многих сайтах используется. Кстати, обнаружил интересную штуку: в Хроме в средствах разработчика на вкладке Element можно нажать Ctrl + F, ввести .side (как CSS селектор) и он подсветит соответствующий элемент.
>>1079129
> В многих браузерах слетает я заметил, раньше там спрайты стояли, но в мозиле и старых ИЕ все слетает напрочь
Привел бы кусочек CSS кода. Ты картинку добавлял как content: ''; position: absolute; width: x; height: y; background-image: z; или как content: url(...)? Первое разве что в ИЕ6-7 может не работать, а так, это CSS2.1 и он должен работать везде (в случае обычного PNG).
> проще чем выучить стандарт нет ничего
В общем-то да, чтение стандарта полезно тем, что видна общая логика, как в CSS те или иные вещи сделаны, там все подробно расписано. Но целиком по моему его учить не обязательно. Подробно стоит читать в первую очередь разделы вроде такого https://www.w3.org/TR/CSS22/visuren.html (про позиционирование и его тонкости), а какие-то простые вещи вроде color или font-size можно и по диагонали пролистывать.
Ну и есть еще другие вещи, про которые в стандарте тебе не напишут. Это например, стиль и организация кода так, чтобы в дальнейшем его было удобно поддерживать и дорабатывать (это то, что в БЭМ упоминается).
Также, полезно понимать, как давно и где поддерживается та или иная фича из CSS3/4 или HTML5. Если ты будешь это знать, ты сможешь сразу верстать так, чтобы страница отображалась во всех требуемых браузерах, и тебе не придется многкратно тестировать и исправлять проблемы. Эта информация есть на сайте caniuse.com.
Не хочешь какие-то дополнительные задачки на CSS? У меня тут есть парочка под рукой:
1) Чат. Нужно сверстать интерфейс для чата. Он состоит из 2 частей: верхняя, где выводятся сообщения и нижняя, где есть поля и кнопки для создания нового сообщения. В верхней части выводятся сообщения, если их мало, то они должны быть прижаты вниз (так что сверху над ними пустое место), если их много, должна появляться линейка прокрутки. Нижняя часть содержит, допустим, поле ввода сообщения и кнопку отправки.
Тут есть 2 варианта задачи, попроще и посложнее:
а) допустим, высота нижней части фиксированна и известна (например нижняя часть занимает по высоте 40px, верхняя - все оставшееся в окне место)
б) допустим, высота нижней части неизвестна и должна определяться высотой содержимого, а верхняя часть занимает оставшееся место. Такая ситуация может возникнуть, если у нас в нижней части кроме поля ввода и кнопки могут динамически добавляться какие-то другие элементы.
2) Центрирование картинок
На сайте есть окошко под картинку, неизвестной заранее ширины и неизвестной, но фиксированной высоты (например, высота 100px, ширина = ширине окна или ширина = ширине родителя, высота = 50% ширины). Размеры неизвестны, так как мы не знаем, в окне какого размера будет отображаться страница и хотим сделать верстку максимально адаптивной.
В этом окошке надо отобразить картинку также неизвестного размера и пропорций. Если картинка больше, чем окошко по ширине или высоте, то ее надо уменьшить с сохранением пропорций, чтобы она в него помещалась, после чего отцентрировать внутри окошка горизонтально или вертикально. Если она меньше, ее надо центрировать внутри окошка, не увеличивая.
Пропорции картинки должны сохраняться в любом случае. Картинку можно только уменьшать, но не увеличивать.
Нужно придумать HTML/CSS-верстку для решения этой задачи. Есть несколько способов, каждый со воими плюсами и минусами. Проверить, в каких браузерах это будет работать и насколько плохо будет выглядеть результат в неподдерживаемых браузерах.
Также, есть усложненная версия задачи. В ней высота окошка не задается фиксированно, а может меняться от a до b (например: от 100px до 200px). Соответственно, если картинка высокая, то окошко может растягиваться по высоте, если картинка широкая, то окошко ужимается по высоте. Это позволяет в большинстве случаев отобразить картинку без полей, так, что ее пропорции соответствуют пропорции окошка.
Усложненная 2 раза версия: сделать, чтобы это все работало совместо с атрибутом srcset, которое позволяет задать несколько картинок для разных разрешений.
3) Вывод адаптивных SVG-картинок
Есть окошко неизвестной заранее ширины, нужно в нем отобразить SVG-картинку с сохранением пропорций (картинка должна занять всю ширину окошка). Высота окошка не задана и определяется пропорциями SVG-картинки.
Можешь порешать, если захочешь попрактиковаться. Тут может быть несколько решений, каждое со своими недостатками. Первая задача в варианте б, вполне возможно, не решается без флексбокса, но я не уверен.
Не знаю, сайдбар как сайдбар, на многих сайтах используется. Кстати, обнаружил интересную штуку: в Хроме в средствах разработчика на вкладке Element можно нажать Ctrl + F, ввести .side (как CSS селектор) и он подсветит соответствующий элемент.
>>1079129
> В многих браузерах слетает я заметил, раньше там спрайты стояли, но в мозиле и старых ИЕ все слетает напрочь
Привел бы кусочек CSS кода. Ты картинку добавлял как content: ''; position: absolute; width: x; height: y; background-image: z; или как content: url(...)? Первое разве что в ИЕ6-7 может не работать, а так, это CSS2.1 и он должен работать везде (в случае обычного PNG).
> проще чем выучить стандарт нет ничего
В общем-то да, чтение стандарта полезно тем, что видна общая логика, как в CSS те или иные вещи сделаны, там все подробно расписано. Но целиком по моему его учить не обязательно. Подробно стоит читать в первую очередь разделы вроде такого https://www.w3.org/TR/CSS22/visuren.html (про позиционирование и его тонкости), а какие-то простые вещи вроде color или font-size можно и по диагонали пролистывать.
Ну и есть еще другие вещи, про которые в стандарте тебе не напишут. Это например, стиль и организация кода так, чтобы в дальнейшем его было удобно поддерживать и дорабатывать (это то, что в БЭМ упоминается).
Также, полезно понимать, как давно и где поддерживается та или иная фича из CSS3/4 или HTML5. Если ты будешь это знать, ты сможешь сразу верстать так, чтобы страница отображалась во всех требуемых браузерах, и тебе не придется многкратно тестировать и исправлять проблемы. Эта информация есть на сайте caniuse.com.
Не хочешь какие-то дополнительные задачки на CSS? У меня тут есть парочка под рукой:
1) Чат. Нужно сверстать интерфейс для чата. Он состоит из 2 частей: верхняя, где выводятся сообщения и нижняя, где есть поля и кнопки для создания нового сообщения. В верхней части выводятся сообщения, если их мало, то они должны быть прижаты вниз (так что сверху над ними пустое место), если их много, должна появляться линейка прокрутки. Нижняя часть содержит, допустим, поле ввода сообщения и кнопку отправки.
Тут есть 2 варианта задачи, попроще и посложнее:
а) допустим, высота нижней части фиксированна и известна (например нижняя часть занимает по высоте 40px, верхняя - все оставшееся в окне место)
б) допустим, высота нижней части неизвестна и должна определяться высотой содержимого, а верхняя часть занимает оставшееся место. Такая ситуация может возникнуть, если у нас в нижней части кроме поля ввода и кнопки могут динамически добавляться какие-то другие элементы.
2) Центрирование картинок
На сайте есть окошко под картинку, неизвестной заранее ширины и неизвестной, но фиксированной высоты (например, высота 100px, ширина = ширине окна или ширина = ширине родителя, высота = 50% ширины). Размеры неизвестны, так как мы не знаем, в окне какого размера будет отображаться страница и хотим сделать верстку максимально адаптивной.
В этом окошке надо отобразить картинку также неизвестного размера и пропорций. Если картинка больше, чем окошко по ширине или высоте, то ее надо уменьшить с сохранением пропорций, чтобы она в него помещалась, после чего отцентрировать внутри окошка горизонтально или вертикально. Если она меньше, ее надо центрировать внутри окошка, не увеличивая.
Пропорции картинки должны сохраняться в любом случае. Картинку можно только уменьшать, но не увеличивать.
Нужно придумать HTML/CSS-верстку для решения этой задачи. Есть несколько способов, каждый со воими плюсами и минусами. Проверить, в каких браузерах это будет работать и насколько плохо будет выглядеть результат в неподдерживаемых браузерах.
Также, есть усложненная версия задачи. В ней высота окошка не задается фиксированно, а может меняться от a до b (например: от 100px до 200px). Соответственно, если картинка высокая, то окошко может растягиваться по высоте, если картинка широкая, то окошко ужимается по высоте. Это позволяет в большинстве случаев отобразить картинку без полей, так, что ее пропорции соответствуют пропорции окошка.
Усложненная 2 раза версия: сделать, чтобы это все работало совместо с атрибутом srcset, которое позволяет задать несколько картинок для разных разрешений.
3) Вывод адаптивных SVG-картинок
Есть окошко неизвестной заранее ширины, нужно в нем отобразить SVG-картинку с сохранением пропорций (картинка должна занять всю ширину окошка). Высота окошка не задана и определяется пропорциями SVG-картинки.
Можешь порешать, если захочешь попрактиковаться. Тут может быть несколько решений, каждое со своими недостатками. Первая задача в варианте б, вполне возможно, не решается без флексбокса, но я не уверен.
Спасибо, как раз буду практиковаться пока буду читать, скину результаты через недельку.
http://prntscr.com/h04mn5
1. Сюда я не понимаю что и как написать.
2. Тут, как я понимаю, пишутся функции для взаимодействия с выбраной таблицей.
И еще вопрос где прописывается соединение с таблицей и как включается в класс.
class StudentsTableDataGateway
{
public function __construct(\pdo $pdo)
{ / .... / }
public function getStudent(int $id)
{ / .... / }
public function save(student $student)
{ / .... / }
// etc
}
Допустим он установлен на 3-х разных доменах (универ, колледж при универе и лицей при универе. Живой пример). И вот для универа нам нужно показывать средний бал поступивших. Как нам расширять функционал TDG все не сломав? Варианты, которые пришли мне в голову:
1.Просто написать запрос в контроллере, не касаясь TDG вообще. Понятно, что это совсем плохо и убивает все преимущества паттерна.
2.Добавить в изначальный TDG функцию выполняющую любой запрос к таблице. Мне показалось, что это почти пункт 1 только нагажено в другом месте.
3.Наследоваться от нашего TDG с добавлением новой функции getAverageTestScore(). Это мой текущий вариант действий.
4.Изначально делать все через интерфейсы. Это мне посоветовали на просторах интернета. Я понимаю как это поможет в случае если у нас разные БД и соответственно разные TDG, но как это решает вышеописанную задачу?
ОП помогай, у меня уже мозг закипает.
Спасибо, всё работает, я вот только не понял момент про паблик метод. Насколько я понимаю, если не уточнять область видимости, то метод будет видим как паблик или что-то около того. А вот переменную класса я не могу оставить с дефолтным ключевым словом, мне компилятор ошибку выбивает. И еще этот $this-> оче напрягает писать к каждой переменной в методах класса, чому оно само не в курсе какая переменная локальная, а какая классовая?
Ты можешь выбирать что показывать во Вью.(класс который у тебя выводит все)
В регулярке слишком много повторений. Хинт: можно взять часть выражения в скобки и добавить квантификатор, например:
(не)?честный = соответствует словам "нечестный" и "честный"
(ab?){2,4} = соответствует словам aa, aba, abab, ababaa
В регулярке нужно использовать флаг u, иначе он может считать кириллицу не буквами, а 2 странными символами.
Твоя регулярка допускает номера, начинающиеся с 7 без плюса, а также с +8
Нужно улучшать код.
>>1079305
Тут конечно напрашивается наследование - сделать базовый TDG и унаследовать от него усовершенствованный TDG. Но я думаю, что это переусложнение и лучше сделать единственный TDG со всеми нужными методами, просто не вызывать их на тех доменах, где они не нужны. Это если у тебя везде одинаковая БД.
Если же БД разная (то есть таблицы похожи, но немного различаются), то придется выбирать одно из двух - либо наследование, либо параметр в конструкторе, который говорит TDG, с какой таблицей он работает. Ну либо может даже будет выгоднее сделать несколько независимых TDG, чтобы не усложнять код слишком сильно.
> Добавить в изначальный TDG функцию выполняющую любой запрос к таблице.
Это уже будет не TDG, у тебя будут SQL запросы раскиданы по всему коду.
> Изначально делать все через интерфейсы
Тут наверно это не подойдет.
TDG - это класс, содержащий в себе все операции с одной таблицей (то есть на каждую таблицу свой класс TDG, хотя в очень простых проектах можно сделать один TDG на все таблицы).
> Сюда я не понимаю что и как написать.
Почитай урок про DI: https://github.com/codedokode/pasta/blob/master/arch/di.md
Если кратко, то это не задача TDG - знать, как соединиться с базой данных. Лучше просто передавать ему уже готовый объект соединения (объект PDO), через который он может делать запросы.
PDO - это встроенный в PHP класс для соединения и выполнения запросов к разным видам БД: http://php.net/manual/ru/book.pdo.php В интернете много статей про него, в том числе на русском.
То есть мы как бы разделяем работу с БД на слои:
- нижний слой - PDO - знает, как соединиться с БД и как выполнять SQL запросы, но не знает ничего про таблицы, колонки, итд
- верхний слой - TDG - знает, какие есть таблицы, какие в них колонки, но не знает, как соединятьяся БД, а использует для этого объект PDO
- остальной код не знает ничего ни про БД, ни про таблицы, а вызывает методы TDG, чтобы что-то получить или изменить в БД
Такое разделение тебе будет еще часто встречаться.
> Тут, как я понимаю, пишутся функции для взаимодействия с выбраной таблицей.
Верно. Они выглядят примерно так:
public function getNewsCount()
{
$result = $this->pdo->query("SELECT COUNT(*) FROM news");
$count = $result->fetchColumn();
return $count;
}
> где прописывается соединение с таблицей и как включается в класс.
Ты создаешь объект PDO, ему передаешь параметры соединения и передаешь этот объект при создании объекта TDG. Изучи PDO для начала.
TDG - это класс, содержащий в себе все операции с одной таблицей (то есть на каждую таблицу свой класс TDG, хотя в очень простых проектах можно сделать один TDG на все таблицы).
> Сюда я не понимаю что и как написать.
Почитай урок про DI: https://github.com/codedokode/pasta/blob/master/arch/di.md
Если кратко, то это не задача TDG - знать, как соединиться с базой данных. Лучше просто передавать ему уже готовый объект соединения (объект PDO), через который он может делать запросы.
PDO - это встроенный в PHP класс для соединения и выполнения запросов к разным видам БД: http://php.net/manual/ru/book.pdo.php В интернете много статей про него, в том числе на русском.
То есть мы как бы разделяем работу с БД на слои:
- нижний слой - PDO - знает, как соединиться с БД и как выполнять SQL запросы, но не знает ничего про таблицы, колонки, итд
- верхний слой - TDG - знает, какие есть таблицы, какие в них колонки, но не знает, как соединятьяся БД, а использует для этого объект PDO
- остальной код не знает ничего ни про БД, ни про таблицы, а вызывает методы TDG, чтобы что-то получить или изменить в БД
Такое разделение тебе будет еще часто встречаться.
> Тут, как я понимаю, пишутся функции для взаимодействия с выбраной таблицей.
Верно. Они выглядят примерно так:
public function getNewsCount()
{
$result = $this->pdo->query("SELECT COUNT(*) FROM news");
$count = $result->fetchColumn();
return $count;
}
> где прописывается соединение с таблицей и как включается в класс.
Ты создаешь объект PDO, ему передаешь параметры соединения и передаешь этот объект при создании объекта TDG. Изучи PDO для начала.
Самую новую.
>>1079116
Он писался во времена PHP5.4, но суть та же, думаю, должен быть актуальным.
>>1079105
Погоди немного, через несколько дней перекатим.
>>1079425
> А вот переменную класса я не могу оставить с дефолтным ключевым словом, мне компилятор ошибку выбивает.
С каким? Нужно писать public $x; или private $x; И перед методами, кстати, тоже в PSR рекомендуется всегда писать явно public/private.
> И еще этот $this-> оче напрягает писать к каждой переменной в методах класса, чому оно само не в курсе какая переменная локальная, а какая классовая?
Оно может определять, но тогда при чтении кода это будет непонятно. Вот например в Яве можно не писать this, и в итоге они перед полями класса начинают префиксы приписывать, чтобы отличить их от переменных. Вот кусочек кода из Андроида: https://android.googlesource.com/platform/packages/apps/IM/+/master/src/com/android/im/app/AddContactActivity.java#66
Там видно, что перед именами полей пишут букву m, чтобы отличать их от переменных:
> private Spinner mListSpinner;
...
> mListSpinner = (Spinner) findViewById(R.id.choose_list);
Хотя конечно код получается короче в итоге. Ну и неудобно, если у тебя и переменная и поле имеют одинаковое имя:
public function setName(name) {
$this->name = name;
}
Самую новую.
>>1079116
Он писался во времена PHP5.4, но суть та же, думаю, должен быть актуальным.
>>1079105
Погоди немного, через несколько дней перекатим.
>>1079425
> А вот переменную класса я не могу оставить с дефолтным ключевым словом, мне компилятор ошибку выбивает.
С каким? Нужно писать public $x; или private $x; И перед методами, кстати, тоже в PSR рекомендуется всегда писать явно public/private.
> И еще этот $this-> оче напрягает писать к каждой переменной в методах класса, чому оно само не в курсе какая переменная локальная, а какая классовая?
Оно может определять, но тогда при чтении кода это будет непонятно. Вот например в Яве можно не писать this, и в итоге они перед полями класса начинают префиксы приписывать, чтобы отличить их от переменных. Вот кусочек кода из Андроида: https://android.googlesource.com/platform/packages/apps/IM/+/master/src/com/android/im/app/AddContactActivity.java#66
Там видно, что перед именами полей пишут букву m, чтобы отличать их от переменных:
> private Spinner mListSpinner;
...
> mListSpinner = (Spinner) findViewById(R.id.choose_list);
Хотя конечно код получается короче в итоге. Ну и неудобно, если у тебя и переменная и поле имеют одинаковое имя:
public function setName(name) {
$this->name = name;
}
Спасибо ОП.
Решено верно.
>>1068087
Ты скорее всего неправильно настроил robots.txt, проверь в браузере, открывается ли он вообще и корректный ли синтаксис (я думаю, на яндексе или на гугле есть проверяльщик синтаксиса).
>>1068108
Я по коду хотел замечание сделать, ты зря делаешь 2 разных переменных с одним именем тут:
> decrypted.then(function(decrypted) {
Это создает путаницу, лучше назвать первую переменную decryptedPromise.
Также, у тебя нет обработки ошибок, а промисы по умолчанию "съедают" ошибки, и ты о них может быть не узнаешь (точнее, узнаешь, если поставишь обработчик unhandledPromise или как-то так).
Что касается промисов. Промис - это объект, представляющий значение, которое будет получено когда-то в будущем. Ты можешь преобразовать обещание вернуть значение A (Promise<A>) в обещание вернуть значение B (Promise<B>) c помощью метода then, в который передается функция, преобразующая A в B.
Соответственно расшифровка - это и есть преобразование (Array<encrypted> -> Array<decrypted>). На входе мы получим массив зашифрованных сообщение encrypted, на выходе мы должны вернуть массив расшифрованных сообщений decrypted. Расшифровка тоже асинхронная, но это не проблема так как функция-преобразователь A -> B может вернуть Promise<B> вместо самого значения B.
Пишем код:
function decryptMessageAsync(message) {
// отправляет сообщение на расшифровку и возвращает промис
}
var encryptedPromise = getMessages();
var decryptedMessagesPromise = encryptedPromise.then(function (encryptedMessages) {
// Получаем массив промизов расшифрованных сообщений
var decryptedPromises = encryptedMessages.map(decryptMessageAsync);
// получаем из массива промизов один промиз с массивом расшифрованных сообщений
return Promise.all(decryptedPromises);
});
В decryptedMessagesPromise мы имеем промиз, который вернет массив расшифрованных сообщений. Мы можем например передать его во view:
decryptedMessagesPromise.then(function (messages) {
view.showMessages(messages);
});
Другой вариант - добавить сообщения в локальное хранилище, изменение которого вызовет обновление view:
decryptedMessagesPromise.then(function (messages) {
messageStore.append(messages);
});
(в данном случае хранилище должно быть "умным" и знать, куда именно нужно добавить эти сообщения. Ведь в асинхронном мире никто не гарантирует, что операции завершатся в том же порядке, в котором запускались).
У меня тут нет кода обработки ошибок - ошибок получения сообщений и ошибок расшифровки. Это уже ты должен смотреть по логике приложения, как ошибки должны обрабатываться.
Также, тут есть недостаток. Расшифровка сообщений - асинхронная, но тут мы ждем, пока они не расшифруются все. Можно написать более продвинутую версию кода:
var encryptedPromise = getMessages();
// Promise<Array<Promise<decrypted>>>
var decryptedMessagesPromise = encryptedPromise.then(function (encryptedMessages) {
// Получаем массив промизов расшифрованных сообщений
var decryptedPromises = encryptedMessages.map(decryptMessageAsync);
return decryptedPromises;
});
decryptedMessagesPromise.then(function (decryptedPromiseArray) {
decryptedPromiseArray.each(function (decryptedPromise) {
decryptedPromise.done(function (decrypted) {
messagesView.displayMessage(decrypted);
});
})
});
Здесь мы видим громоздкую тяжелочитаемую конструкцию, а это верный признак проблемы, которая решается "добавлением еще одной абстракции". Попробуем применить тут реактивное программирование. Я напомню, что там есть объект Observable, который представляет собой поток каких-то событий. У нас будет 2 потока: поток, в который прибывают зашифрованные сообщения, и поток, в который приходя расшифрованные сообщения.
// Promise<encrypted[]>
var encryptedArrayPromise = getMessages();
// Поток массивов зашифрованных сообщений
var messageArrayStream = Rx.Observable.fromPromise(encryptedArrayPromise);
// Поток отдельных зашифрованных сообщений
var encryptedStream = messageArrayStream.flatMap((encryptedArray) => encryptedArray);
// Поток расшифрованных сообщений
var decryptedStream = encryptedStream.map(decryptMessageAsync);
decryptedStream.subscribe(function (decrypted) {
view.addOneMessage(decrypted);
});
Я должен тут предупредить, что я не писал ничего на Reactive и код отражает только общую идею. Не факт, что он работает.
Решено верно.
>>1068087
Ты скорее всего неправильно настроил robots.txt, проверь в браузере, открывается ли он вообще и корректный ли синтаксис (я думаю, на яндексе или на гугле есть проверяльщик синтаксиса).
>>1068108
Я по коду хотел замечание сделать, ты зря делаешь 2 разных переменных с одним именем тут:
> decrypted.then(function(decrypted) {
Это создает путаницу, лучше назвать первую переменную decryptedPromise.
Также, у тебя нет обработки ошибок, а промисы по умолчанию "съедают" ошибки, и ты о них может быть не узнаешь (точнее, узнаешь, если поставишь обработчик unhandledPromise или как-то так).
Что касается промисов. Промис - это объект, представляющий значение, которое будет получено когда-то в будущем. Ты можешь преобразовать обещание вернуть значение A (Promise<A>) в обещание вернуть значение B (Promise<B>) c помощью метода then, в который передается функция, преобразующая A в B.
Соответственно расшифровка - это и есть преобразование (Array<encrypted> -> Array<decrypted>). На входе мы получим массив зашифрованных сообщение encrypted, на выходе мы должны вернуть массив расшифрованных сообщений decrypted. Расшифровка тоже асинхронная, но это не проблема так как функция-преобразователь A -> B может вернуть Promise<B> вместо самого значения B.
Пишем код:
function decryptMessageAsync(message) {
// отправляет сообщение на расшифровку и возвращает промис
}
var encryptedPromise = getMessages();
var decryptedMessagesPromise = encryptedPromise.then(function (encryptedMessages) {
// Получаем массив промизов расшифрованных сообщений
var decryptedPromises = encryptedMessages.map(decryptMessageAsync);
// получаем из массива промизов один промиз с массивом расшифрованных сообщений
return Promise.all(decryptedPromises);
});
В decryptedMessagesPromise мы имеем промиз, который вернет массив расшифрованных сообщений. Мы можем например передать его во view:
decryptedMessagesPromise.then(function (messages) {
view.showMessages(messages);
});
Другой вариант - добавить сообщения в локальное хранилище, изменение которого вызовет обновление view:
decryptedMessagesPromise.then(function (messages) {
messageStore.append(messages);
});
(в данном случае хранилище должно быть "умным" и знать, куда именно нужно добавить эти сообщения. Ведь в асинхронном мире никто не гарантирует, что операции завершатся в том же порядке, в котором запускались).
У меня тут нет кода обработки ошибок - ошибок получения сообщений и ошибок расшифровки. Это уже ты должен смотреть по логике приложения, как ошибки должны обрабатываться.
Также, тут есть недостаток. Расшифровка сообщений - асинхронная, но тут мы ждем, пока они не расшифруются все. Можно написать более продвинутую версию кода:
var encryptedPromise = getMessages();
// Promise<Array<Promise<decrypted>>>
var decryptedMessagesPromise = encryptedPromise.then(function (encryptedMessages) {
// Получаем массив промизов расшифрованных сообщений
var decryptedPromises = encryptedMessages.map(decryptMessageAsync);
return decryptedPromises;
});
decryptedMessagesPromise.then(function (decryptedPromiseArray) {
decryptedPromiseArray.each(function (decryptedPromise) {
decryptedPromise.done(function (decrypted) {
messagesView.displayMessage(decrypted);
});
})
});
Здесь мы видим громоздкую тяжелочитаемую конструкцию, а это верный признак проблемы, которая решается "добавлением еще одной абстракции". Попробуем применить тут реактивное программирование. Я напомню, что там есть объект Observable, который представляет собой поток каких-то событий. У нас будет 2 потока: поток, в который прибывают зашифрованные сообщения, и поток, в который приходя расшифрованные сообщения.
// Promise<encrypted[]>
var encryptedArrayPromise = getMessages();
// Поток массивов зашифрованных сообщений
var messageArrayStream = Rx.Observable.fromPromise(encryptedArrayPromise);
// Поток отдельных зашифрованных сообщений
var encryptedStream = messageArrayStream.flatMap((encryptedArray) => encryptedArray);
// Поток расшифрованных сообщений
var decryptedStream = encryptedStream.map(decryptMessageAsync);
decryptedStream.subscribe(function (decrypted) {
view.addOneMessage(decrypted);
});
Я должен тут предупредить, что я не писал ничего на Reactive и код отражает только общую идею. Не факт, что он работает.
Я еще должен предупредить, что в моем коде в обоих примерах мы отправляем все сообщения на расшифровку одновременно. Это может быть не очень эффективно, если расшифровка будет идти параллельно и процессор постоянно будет переключаться между потоками. Но с другой стороны, если ядер несколько, мы бы могли так задействовать их все. В общем, надо смотреть по ситуации.
никак не могу сделать так, чтобы включить возможный отступ между знаком плюс и цифрой 7
пытался написать [+]\\s*7 но что-то ничего не получалось
Уже не надо
Прошу оценить мою регулярку теперь: https://ideone.com/ZBnB38
Вот старая:>>1079755
Стало лучше?
> Но в теле, при гет запросе, не советуется.
У GET запросов нет тела
> Т.к. при хттпс запросе, строка с адресом не кодируется
Неверно. При HTTPS шифруется весь запрос целиком. Однако атакующий все равно видит IP адрес сайта, с которым идет соединение, его сертификат (где указан домен), а также специальное дополнение к SSL позволяет указать домен сайта в открытом виде при установке соединения. То есть атакующий видит только домен и IP/порт, с которым идет соединение.
>>1068397
Поле date не нужно, метод createRandomDate нужно сделать статическим, и чтобы он возвращал сразу объект DateTime. Также твой генератор никак не проверяет например что дата получается реалистичная и что у тебя не получится 31 февраля. Нужно генераторерировать не месяц/день по отдельности, а номер дня в году (в еще лучше - вообще номер дня начиная с 1 янв 1970) и из него уже получать дату. Изучи unix timestamp.
>>1068676
Используй встроенный в PHP шаблонизатор: https://github.com/codedokode/pasta/blob/master/php/templates.md
>>1069103
Используй инструменты разработчика в барузере (Ctrl + Shift + I), чтобы проверить, нет ли ошибок в твоем скрипте.
> каким размером делать превью для картинок?
Чтобы хорошо смотрелось в выбранном дизайне. Если ты никак не можешь решить сам, я могу наугад взять цифру с потолка - высота и ширина превью должны быть не более 300 пикс., если картинка в одном из измерений превышает эту цифру, то она уменьшается с сохранением пропорций. Если картинка меньше, то с ней ничего не делается.
> Нужно ли перекодировать видео для превью?
Вообще, было бы здорово. С видео такая ситуация: существует огромное число видеоформатов, но браузеры поддерживают всего несколько (причем какие именно - зависит от модели браузера, версии, и даже иногда от установленных в ОС кодеков). Соответственно если взять случайное видео, то с большой вероятностью оно не будет воспроизводиться почти нигде. Следовательно, нужно перекодирование.
Могу предложить такой вариант:
Анализируем информацию о поддержке форматов видео/аудио:
- https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
- https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery
- http://caniuse.com/#search=video
и внимательно читаем все примечания
- выбираем 2-3 формата, охватывающих максимальное число браузеров. Учитываем примечания и особенности форматов.
- выбираем желаемый размер, битрейт и параметры качества видео
- пишем конвертор на основе ffmpeg (открытая программа-перекодировщик видео) и gearman (система выполнения фоновых задач в PHP). Заодно делаем картинки-превьюшки к видео, а при желании - анимированные превьюшки, как на ютубе.
- пытаемся понять, есть у нас право использовать патентованные кодеки вроде H.264 или нет (в итоге решаем, что раз это поддерживается в ffmpeg, то наверно есть)
- не забываем, что процесс перекодировки может зависнуть, отвалиться с ошибкой, предусматриваем обработку таких ситуаций. Запускать сторонний процесс удобно с помощью библиотеки symfony process
- при загрузке страницы с видео добавляем тег video с несколькими source и тестируем во всех доступных браузерах
Это сложно, предупреждаю честно, но даст тебе очень ценный опыт.
Не забудь про мобильные платформы.
Совсем древние браузеры могут играть видео только через flash, но не факт, что он в них будет установлен. Вроде как HTML5 video уже давно поддерживается.
Вообще, по моему опыту, с поддержкой разных форматов все плохо. Например, свободный браузер Хромиум не вопроизводит видео в Twitter, Dailymotion, и других сервисах. Chrome воспроизводит, но за счет закрытых компонентов от Гугла. Свободный фаерфокс тоже имеет проблемы с вопроизведением.
Без перекодировки получается такой вариант:
- определяем тип видео
- выводим тег video с source и указанием типа и надеемся, что браузер его вопроизведет (скорее всего нет)
> каким размером делать превью для картинок?
Чтобы хорошо смотрелось в выбранном дизайне. Если ты никак не можешь решить сам, я могу наугад взять цифру с потолка - высота и ширина превью должны быть не более 300 пикс., если картинка в одном из измерений превышает эту цифру, то она уменьшается с сохранением пропорций. Если картинка меньше, то с ней ничего не делается.
> Нужно ли перекодировать видео для превью?
Вообще, было бы здорово. С видео такая ситуация: существует огромное число видеоформатов, но браузеры поддерживают всего несколько (причем какие именно - зависит от модели браузера, версии, и даже иногда от установленных в ОС кодеков). Соответственно если взять случайное видео, то с большой вероятностью оно не будет воспроизводиться почти нигде. Следовательно, нужно перекодирование.
Могу предложить такой вариант:
Анализируем информацию о поддержке форматов видео/аудио:
- https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
- https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery
- http://caniuse.com/#search=video
и внимательно читаем все примечания
- выбираем 2-3 формата, охватывающих максимальное число браузеров. Учитываем примечания и особенности форматов.
- выбираем желаемый размер, битрейт и параметры качества видео
- пишем конвертор на основе ffmpeg (открытая программа-перекодировщик видео) и gearman (система выполнения фоновых задач в PHP). Заодно делаем картинки-превьюшки к видео, а при желании - анимированные превьюшки, как на ютубе.
- пытаемся понять, есть у нас право использовать патентованные кодеки вроде H.264 или нет (в итоге решаем, что раз это поддерживается в ffmpeg, то наверно есть)
- не забываем, что процесс перекодировки может зависнуть, отвалиться с ошибкой, предусматриваем обработку таких ситуаций. Запускать сторонний процесс удобно с помощью библиотеки symfony process
- при загрузке страницы с видео добавляем тег video с несколькими source и тестируем во всех доступных браузерах
Это сложно, предупреждаю честно, но даст тебе очень ценный опыт.
Не забудь про мобильные платформы.
Совсем древние браузеры могут играть видео только через flash, но не факт, что он в них будет установлен. Вроде как HTML5 video уже давно поддерживается.
Вообще, по моему опыту, с поддержкой разных форматов все плохо. Например, свободный браузер Хромиум не вопроизводит видео в Twitter, Dailymotion, и других сервисах. Chrome воспроизводит, но за счет закрытых компонентов от Гугла. Свободный фаерфокс тоже имеет проблемы с вопроизведением.
Без перекодировки получается такой вариант:
- определяем тип видео
- выводим тег video с source и указанием типа и надеемся, что браузер его вопроизведет (скорее всего нет)
Тогда выведи на страницу.
>>1069453
Может быть ты его прописал в автозапуск или в сервисы.
>>1069585
Скорее всего да. Также, значения атрибутов надо брать в кавычки.
>>1069614
По гит: это система управления версиями. Как минимум уметь делать add/commit, pull/push, а лучше еще знать git log, ветки, как узнать, кто сделал то или иное изменение и зачем.
По верстке: код jquery никто не правит (потому что это сторонняя библиотека), но почитать его из любопытства может быть полезно. Он ведь на JS, который ты хорошо знаешь, так? Ну и документацию полистать не помешает.
>>1069620
В документации этого нет?
https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB
> Everything you do in IndexedDB always happens in the context of a transaction. The IndexedDB API provides lots of objects that represent indexes, tables, cursors, and so on, but each of these is tied to a particular transaction. Thus, you cannot execute commands or open cursors outside of a transaction.
> Но что если я просто сделаю
>>DB.objectStore("hui").add({cocol:"semen"});
А где ты возьмешь объект DB? И есть ли у него метод objectStore? Если ты изучишь документацию, ты увидешь, что до objectStore можно добраться только через транзакцию.
Ты зря негативно относишься к транзакциям. Они нужны, например, для того, чтобы делать изменения атомарно - либо все внесенные изменения сохраняются, либо ни одного. Также, они нужны для блокировок - чтобы когда одна вкладка меняет что-то в БД, другая не прочитала бы смесь старых и новых данных.
Изучи, что такое транзакции, прежде чем критиковать.
Если тебе тяжело работать напрямую с транзакциями, ты всегда можешь сделать фукнцию-обертку, которая будет создавать временную транзакцию, делать операцию с БД и закрывать транзакцию.
Тогда выведи на страницу.
>>1069453
Может быть ты его прописал в автозапуск или в сервисы.
>>1069585
Скорее всего да. Также, значения атрибутов надо брать в кавычки.
>>1069614
По гит: это система управления версиями. Как минимум уметь делать add/commit, pull/push, а лучше еще знать git log, ветки, как узнать, кто сделал то или иное изменение и зачем.
По верстке: код jquery никто не правит (потому что это сторонняя библиотека), но почитать его из любопытства может быть полезно. Он ведь на JS, который ты хорошо знаешь, так? Ну и документацию полистать не помешает.
>>1069620
В документации этого нет?
https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Basic_Concepts_Behind_IndexedDB
> Everything you do in IndexedDB always happens in the context of a transaction. The IndexedDB API provides lots of objects that represent indexes, tables, cursors, and so on, but each of these is tied to a particular transaction. Thus, you cannot execute commands or open cursors outside of a transaction.
> Но что если я просто сделаю
>>DB.objectStore("hui").add({cocol:"semen"});
А где ты возьмешь объект DB? И есть ли у него метод objectStore? Если ты изучишь документацию, ты увидешь, что до objectStore можно добраться только через транзакцию.
Ты зря негативно относишься к транзакциям. Они нужны, например, для того, чтобы делать изменения атомарно - либо все внесенные изменения сохраняются, либо ни одного. Также, они нужны для блокировок - чтобы когда одна вкладка меняет что-то в БД, другая не прочитала бы смесь старых и новых данных.
Изучи, что такое транзакции, прежде чем критиковать.
Если тебе тяжело работать напрямую с транзакциями, ты всегда можешь сделать фукнцию-обертку, которая будет создавать временную транзакцию, делать операцию с БД и закрывать транзакцию.
> $homoCreditTotal = credit($percent = 1.04, $servicePay = 500,
нужно писать просто $homoCreditTotal = credit(1.04, 500, ... , а то ты создаешь лишние бесполезные переменные.
Код довольно кривой и содержит много лишних действий, запутывающих его понимание.
Когда остается менее 5000, ты не начисляешь проценты и комиссию, а сразу все выплачиваешь, то есть твой код занижает выплату.
$startpay добавляется каждый месяц к сумме долга.
$monthlypay у тебя всегда равна 5000.
Попробуй написать код так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
>>1069955
Да, удаление должно отправлять POST запрос. Можно на ту же самую страницу, можно на отдельную.
> Или нужно делать две разных модели?
Модель представляет какую-то сущность (например, пользователя), а не операцию над ним.
>>1069977
> так вот нельзя выбирать рандомное слово из массива:
> $word1[rand(1, count($word1))]
Можно, но лучше использовать mt_rand, так как оно дает более "случайные" числа, а также, индексы в массиве считаются с 0, а не с 1.
> $homoCreditTotal = credit($percent = 1.04, $servicePay = 500,
нужно писать просто $homoCreditTotal = credit(1.04, 500, ... , а то ты создаешь лишние бесполезные переменные.
Код довольно кривой и содержит много лишних действий, запутывающих его понимание.
Когда остается менее 5000, ты не начисляешь проценты и комиссию, а сразу все выплачиваешь, то есть твой код занижает выплату.
$startpay добавляется каждый месяц к сумме долга.
$monthlypay у тебя всегда равна 5000.
Попробуй написать код так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
>>1069955
Да, удаление должно отправлять POST запрос. Можно на ту же самую страницу, можно на отдельную.
> Или нужно делать две разных модели?
Модель представляет какую-то сущность (например, пользователя), а не операцию над ним.
>>1069977
> так вот нельзя выбирать рандомное слово из массива:
> $word1[rand(1, count($word1))]
Можно, но лучше использовать mt_rand, так как оно дает более "случайные" числа, а также, индексы в массиве считаются с 0, а не с 1.
Добавить проверку авторизации в контроллер-предок. Также, можно посомтреть: нет ли в Юи события вроде "beforeRequest" или фронт-контроллера.
Ну и наконец неожиданное решение: закрыть сайт авторизацией может быть проще и надежнее через конфиг веб-сервера.
>>1070026
Попробуй открыть картинку напрямую (то есть полную абсолютную ссылку на картинку из консоли вставить в адресную строку), а потом посмотреть в логе веб-сервера, какой именно файл не найден.
>>1070079
Если освоить 8 способов поизиционирования, то фреймворк не понадобится: https://github.com/codedokode/pasta/blob/master/html/positioning.md
Как твой фреймворк учтет то, что размер содержимого элементов может меняться, размер страницы может меняться и тд? В CSS принято задавать общие правила позиционирования элементов, а не прибивать элемент к определенной точке экрана.
>>1070261
Тут наверно не стоит записывать расшифрованные сообщения обратно в messages, а стоит использовать новый массив. Ну и стоит подумать над кешированием расшифрованных сообщений, а то если их каждый раз заново расшифровывать, медленно все работать будет. Хотя, если слишком много кешировать, то памяти будет много потребляться.
В твоем случае проще отдельных echo натыкать, не создавая массив:
echo первое слово;
echo второе слово;
итд.
>>1074425
Я бы просто пролистал по диагонали всю документацию, и по пути отметил вещи, которые пригодятся для выполнения задания. Ну и дальше уже в них можно более подробно разбираться.
Контроллеры, модели, валидация, формы - наверно это 100% стоит изучать.
>>1074464
Есть сайты с обзором хостингов, с рейтингами, отзывами, таблицами сравнений и тд. Погугли.
>>1074474
Мы надеемся, что ты научишься сам решать простые проблемы и тем самым сэкономишь наше время.
>>1074513
У куки есть такой параметр как Path (погугли). Возможно, твои авторизационные куки доступны не на всех страницах сайта.
Алсо как всегда прорекламирую свой урок по HTTP где мельком упоминаются куки: https://github.com/codedokode/pasta/blob/master/network/http.md
В твоем случае проще отдельных echo натыкать, не создавая массив:
echo первое слово;
echo второе слово;
итд.
>>1074425
Я бы просто пролистал по диагонали всю документацию, и по пути отметил вещи, которые пригодятся для выполнения задания. Ну и дальше уже в них можно более подробно разбираться.
Контроллеры, модели, валидация, формы - наверно это 100% стоит изучать.
>>1074464
Есть сайты с обзором хостингов, с рейтингами, отзывами, таблицами сравнений и тд. Погугли.
>>1074474
Мы надеемся, что ты научишься сам решать простые проблемы и тем самым сэкономишь наше время.
>>1074513
У куки есть такой параметр как Path (погугли). Возможно, твои авторизационные куки доступны не на всех страницах сайта.
Алсо как всегда прорекламирую свой урок по HTTP где мельком упоминаются куки: https://github.com/codedokode/pasta/blob/master/network/http.md
В Оп посте есть минимум 3 задачи возрастающей сложности: список студентов, файлообменник, TestHub. С подробными комментариями. Также, если у тебя есть какая-то своя идея, какой сайт тебе хотелось бы сделать, можно попробовать ее реализовать. Разумеется с соблюдением всех лучших практик.
>>1075151
нужна привязка к краям строки (^ и $)
Также, ты написал (0-9) что значит цифра 0, за ней идет минус, за ним цифра 9. Ты перепутал круглые скобки (группируют буквы в одно выражение) и квадратные (символьный класс).
Можешь почитать мануал http://php.net/manual/ru/pcre.pattern.php
>>1075232
Приятно это читать. И обратите внимание, аноны, я же много раз говорил, что надо учить ООП, MVC, тесты, сразу будешь на голову выше других кандидатов, которые учатся по видеокурсам с торрентов.
>>1075611
Думаю, речь об этих плагинах, хотя не уверен: https://dev.mysql.com/doc/refman/5.7/en/authentication-plugins.html
Тут еще есть ответ по теме: https://stackoverflow.com/questions/33991228/what-is-the-default-root-pasword-for-mysql-5-7/33991229#33991229
Раньше, как я помню, mysql шла с пустым паролем рута, что делало ее уязвимой в случае, если администратор не менял этот пароль и пускал других пользователей на сервер (или ставил phpMyAdmin доступный из интернета).
Вообще, в линуксе обычно программы исопльзуют системную таблицу пользователей, а не свою (как mysql). Ну например, постгрес по умолчанию логинится под текущим пользователем ОС.
"правильнее" наверно было бы разобраться, как это работает.
Если ты используешь phpMyAdmin, проверь, что он не доступен снаружи. Были раньше случаи, когда там находили дыры, и я бы не стал его выставлять в интернет вообще. Ну или хотя бы закрыл HTTP авторизацией, доверия к его коду у меня нету. И защиты от подбора паролей там по моему тоже нет.
В Оп посте есть минимум 3 задачи возрастающей сложности: список студентов, файлообменник, TestHub. С подробными комментариями. Также, если у тебя есть какая-то своя идея, какой сайт тебе хотелось бы сделать, можно попробовать ее реализовать. Разумеется с соблюдением всех лучших практик.
>>1075151
нужна привязка к краям строки (^ и $)
Также, ты написал (0-9) что значит цифра 0, за ней идет минус, за ним цифра 9. Ты перепутал круглые скобки (группируют буквы в одно выражение) и квадратные (символьный класс).
Можешь почитать мануал http://php.net/manual/ru/pcre.pattern.php
>>1075232
Приятно это читать. И обратите внимание, аноны, я же много раз говорил, что надо учить ООП, MVC, тесты, сразу будешь на голову выше других кандидатов, которые учатся по видеокурсам с торрентов.
>>1075611
Думаю, речь об этих плагинах, хотя не уверен: https://dev.mysql.com/doc/refman/5.7/en/authentication-plugins.html
Тут еще есть ответ по теме: https://stackoverflow.com/questions/33991228/what-is-the-default-root-pasword-for-mysql-5-7/33991229#33991229
Раньше, как я помню, mysql шла с пустым паролем рута, что делало ее уязвимой в случае, если администратор не менял этот пароль и пускал других пользователей на сервер (или ставил phpMyAdmin доступный из интернета).
Вообще, в линуксе обычно программы исопльзуют системную таблицу пользователей, а не свою (как mysql). Ну например, постгрес по умолчанию логинится под текущим пользователем ОС.
"правильнее" наверно было бы разобраться, как это работает.
Если ты используешь phpMyAdmin, проверь, что он не доступен снаружи. Были раньше случаи, когда там находили дыры, и я бы не стал его выставлять в интернет вообще. Ну или хотя бы закрыл HTTP авторизацией, доверия к его коду у меня нету. И защиты от подбора паролей там по моему тоже нет.
> То есть тут лучше вообще эту строку убрать и сделать заголовки на ошибку сервера, помимо display_erorrs?
Можно выводить подробности ошибки если включен display_errors в конфиге PHP. То есть на dev сервере.
Заголовки (HTTP код 5xx) нужны в любом случае.
> По-моему, у Зандстры в начале книги было, что со скалярами так лучше не делать, только с классами, как я понимаю из-за нестрогой типизации.
Книга написана во времена PHP5, когда этой фичи в PHP не было.
> bindValue для 'order by :field :direction' не работает. У меня это проверяется в Pagere'е, хотя, согласен, странно это, лучше в контроллере валидацию делать, у тебя это справедливо замечено.
Я не об этом. Имена полей надо подставлять напрямую в запрос, но перед этим надо в той же самой функции их проверить. Иначе как понять, есть инъекция или нет? Лазать по всему коду? Даже это не гарантирует, что завтра кто-то где-то эту функцию не вызовет без филььтрации параметров от пользователя.
Нужно проверить что имя поля соответствует разрешенному списку, а не является например куском SQL кода.
> а в классе самого пагинатора очень даже удобно (можно просто передать нужные моля и все-такое),
Это не задача пагинатора, проверять параметры сортировки. В маппере сделать функцию вполне логично, так как он связан с таблицей и "знает", как ее можно сортировать.
> Состояние в данном случае – это имитация stateful за счет куки и объект будто бы живет на протяжении многих запросов или имеется в виду наличие важных полей?
Имеется в виду наличие полей и возможности их менять. Ну то есть представь, ты в одном месте получил объект из контейнера, поменял что-то в нем, а потом в другом месте получаешь уже изменнный объект. Получается такая неявная передача данных, которую очень трудно увидеть и учесть побочные эффекты от нее. Баги могут быть, проще говоря.
> Насчет куки еще: ее не надо как-то хешировать? Просто если взломать бд, то там будет кука лежать, любую вставляй себе в браузер да используй, в отличие от ситуации с password_hash/password_verify.
Интересная точка зрения. Сгенерировать токен, сохранить в куку, а в БД записать только хеш. Тогда после удаления куки повторно восстановить ее будет невозможно. Можно и так сделать, я не против.
Но если злоумышленник имеет доступ к базе, он там может напрямую поменять что угодно. Ему наверно и кука не нужна.
Это для паролей так делают, чтобы при воровстве базы нельзя было быстро получить пароль пользователя и проверить его на дргуих сайтах (то есть пароль хакерр подберет рано или поздно перебором, но за это время пользователь, может, успеет его поменять).
> А какая есть альтернатива, ну кроме Doctrine и других библиотек (они же вроде тоже поверх PDO)?
Получать массив из БД и написать свою функцию, которая на основе массива создает объект. У тебя одна таблица, это не так и сложно. В больших приложениях, конечно, нужен ORM.
> а какая альтернатива, сеттеры в отдельности?
А почему нет?
> А с массивом как, передать ассоциативный массив и в конструкторе его проитерировать и присвоить каждому свойству класса значения соответствующего ключа?
Сделать метод updateAttributes(array $attrs) - так будет универсальнее всего.
> То есть тут по смыслу не подходит? Лучше !is_null?
Да, когда ты пишешь is_null то видно что ты проверяешь на null, а когда isset - непонятно, может это значит что переменная может не существовать. Запутывает.
> Я исправил, но вопрос: use в шаблонах вообще никак?
Правил на этот счет нет, есть только в PSR упоминание, что use должен идти в самом верху файла до других команд.
> Как создать пустой объект? Убрать все тот же конструктор, ну или значение дефолтные null прописать (не особо надежно и удобно).
$s = new Student();
Так наверно логичнее всего.
> Согласен, но а если метод переименовать, ну типа checkForm
Можно переименовать.
> с редиректом тоже согласен, то есть шлю заголовок с кодом 500?
Редирект это код 3xx. Или я что-то не понял?
> Спрашиваю, чтобы лучше понять и больше уяснить.]
Спрашивай еще, если что.
> То есть тут лучше вообще эту строку убрать и сделать заголовки на ошибку сервера, помимо display_erorrs?
Можно выводить подробности ошибки если включен display_errors в конфиге PHP. То есть на dev сервере.
Заголовки (HTTP код 5xx) нужны в любом случае.
> По-моему, у Зандстры в начале книги было, что со скалярами так лучше не делать, только с классами, как я понимаю из-за нестрогой типизации.
Книга написана во времена PHP5, когда этой фичи в PHP не было.
> bindValue для 'order by :field :direction' не работает. У меня это проверяется в Pagere'е, хотя, согласен, странно это, лучше в контроллере валидацию делать, у тебя это справедливо замечено.
Я не об этом. Имена полей надо подставлять напрямую в запрос, но перед этим надо в той же самой функции их проверить. Иначе как понять, есть инъекция или нет? Лазать по всему коду? Даже это не гарантирует, что завтра кто-то где-то эту функцию не вызовет без филььтрации параметров от пользователя.
Нужно проверить что имя поля соответствует разрешенному списку, а не является например куском SQL кода.
> а в классе самого пагинатора очень даже удобно (можно просто передать нужные моля и все-такое),
Это не задача пагинатора, проверять параметры сортировки. В маппере сделать функцию вполне логично, так как он связан с таблицей и "знает", как ее можно сортировать.
> Состояние в данном случае – это имитация stateful за счет куки и объект будто бы живет на протяжении многих запросов или имеется в виду наличие важных полей?
Имеется в виду наличие полей и возможности их менять. Ну то есть представь, ты в одном месте получил объект из контейнера, поменял что-то в нем, а потом в другом месте получаешь уже изменнный объект. Получается такая неявная передача данных, которую очень трудно увидеть и учесть побочные эффекты от нее. Баги могут быть, проще говоря.
> Насчет куки еще: ее не надо как-то хешировать? Просто если взломать бд, то там будет кука лежать, любую вставляй себе в браузер да используй, в отличие от ситуации с password_hash/password_verify.
Интересная точка зрения. Сгенерировать токен, сохранить в куку, а в БД записать только хеш. Тогда после удаления куки повторно восстановить ее будет невозможно. Можно и так сделать, я не против.
Но если злоумышленник имеет доступ к базе, он там может напрямую поменять что угодно. Ему наверно и кука не нужна.
Это для паролей так делают, чтобы при воровстве базы нельзя было быстро получить пароль пользователя и проверить его на дргуих сайтах (то есть пароль хакерр подберет рано или поздно перебором, но за это время пользователь, может, успеет его поменять).
> А какая есть альтернатива, ну кроме Doctrine и других библиотек (они же вроде тоже поверх PDO)?
Получать массив из БД и написать свою функцию, которая на основе массива создает объект. У тебя одна таблица, это не так и сложно. В больших приложениях, конечно, нужен ORM.
> а какая альтернатива, сеттеры в отдельности?
А почему нет?
> А с массивом как, передать ассоциативный массив и в конструкторе его проитерировать и присвоить каждому свойству класса значения соответствующего ключа?
Сделать метод updateAttributes(array $attrs) - так будет универсальнее всего.
> То есть тут по смыслу не подходит? Лучше !is_null?
Да, когда ты пишешь is_null то видно что ты проверяешь на null, а когда isset - непонятно, может это значит что переменная может не существовать. Запутывает.
> Я исправил, но вопрос: use в шаблонах вообще никак?
Правил на этот счет нет, есть только в PSR упоминание, что use должен идти в самом верху файла до других команд.
> Как создать пустой объект? Убрать все тот же конструктор, ну или значение дефолтные null прописать (не особо надежно и удобно).
$s = new Student();
Так наверно логичнее всего.
> Согласен, но а если метод переименовать, ну типа checkForm
Можно переименовать.
> с редиректом тоже согласен, то есть шлю заголовок с кодом 500?
Редирект это код 3xx. Или я что-то не понял?
> Спрашиваю, чтобы лучше понять и больше уяснить.]
Спрашивай еще, если что.
PHP не очень годится как замена bash скриптам, но при желании может использоваться. Только обычно все же для этого используют Питон.
> Как у пхп с многопоточностью,
Сложно, но в линуксах обычно используют многопроцессность, а не многопоточность. У Питона с потоками вообще по моему никак, и ничего, пользуются.
Я думаю, тебе надо погуглить библиотеки для работы с потоками в PHP. Может что и есть.
>>1077020
Придется разбирать документацию. В случае с ffmpeg еще надо бы изучить что такое контейнеры, кодеки, YUV, интерлейс, битрейт и прочие технические подробности.
Можно погуглить статьи, но потом все равно стоит прочесть в документации про использованные опции.
>>1080092
> (([+]\\s*7)|8)
Можно просто ([+]\\s*7|8)
> \W
Может быть тут лучше указать конкретные символы, а не вообще любые? А то выражение 8 + 1 + 2 + 3 + 4 ... он тоже за номер телефона примет.
А так, в общем, верно.
Спасибо большое за проверку
https://stackoverflow.com/questions/39641671/doctrine-entity-validation-at-construct
https://ocramius.github.io/doctrine-best-practices/#/1
https://stackoverflow.com/questions/9744265/validate-a-domain-entity-upon-setting-each-property-or-all-at-once-later
https://stackoverflow.com/questions/9829312/how-to-handle-domain-entity-validation-before-its-persisted
https://stackoverflow.com/questions/9747865/is-it-okay-to-store-a-domain-entitys-mutable-properties-as-a-value-object
https://lostechies.com/jimmybogard/2016/04/29/validation-inside-or-outside-entities/
Еще вопрос: делаю файлообменник, и все вроде замечательно, но почему-то не переписываются дефолтные параметры php.ini на nginx, хотя пишу в конфиге: fastcgi_paramPHP_VALUE"memory_limit = 500M; post_max_size = 400M; upload_max_filesize = 300M"; и client_max_body_size 400m; в блоке http не забыл, однако все равно остается по дефолту, сервер и php-сgi перезапускал, хотя не уверен, что последнее нуждается в этом, запутался уже. Когда меняю глобальный php.ini, все работает, значит проблема в конфиге, причем в phpinfo() есть такое: $_SERVER['PHP_VALUE']memory_limit = 500M; post_max_size = 400M; upload_max_filesize = 300M, а сами параметры не меняются, ошибка заголовка content-length с указанием стандартных 8М. Глобально ставить не хочу, так как желаю разобраться и удобно это на любой location ставить любые параметры, только можно ли отдельный php.ini создать и указать в конфиге nginx или php-cgi, ну в любом случае можно хотя бы через php_value менять (а сами значения в другом файле хранить для читабельности и импортировать)
У тебя за nginx стоит php-fpm или Аапч? Почему не пишешь?
Тут http://php.net/manual/ru/install.fpm.configuration.php в примере настройки разделяются символом \n, а не точкой с запятой.
> только можно ли отдельный php.ini создать и указать в конфиге nginx или php-cgi,
Если ты используешь php-fpm, то в его конфиге можно менять настройки PHP: http://php.net/manual/ru/install.fpm.configuration.php
> php-cgi,
я надеюсь, ты не используешь PHP в режиме CGI?
> удобно это на любой location ставить любые параметры,
В ридми не забудь это описать только.
> (а сами значения в другом файле хранить для читабельности и импортировать)
Конфиг нгинкса позволяет инклюды, не знаю как насчет php-fpm.
> А как и где лучше всего делать валидацию?
На мой взгляд удобно, когда валидацией занимается отдельный сервис и ты всегда ее можешь вызвать явно:
$result = $validator->validate($something);
Часто валидация используется вместе с сохранением/обновлением (и вообще, отдельно не нужна), в этом случае удобно может быть совместить эти операции, тем самым исключая возможность сохранить невалидную сущность:
// валидирует и сохраняет
$result = $service->saveIfValid($entity);
> Например, если есть сторонняя библиотека, то нужно создавать класс, унаследованный от класса либы
Лучше бы не использовать наследование, а делегацию. То есть держать объект стороннего валидатора внутри твоего класса. А вообще, сформулируй вопрос более ясно, зачем ты там решил что-то наследовать.
> Кто-то в самой сущности предлагает это делать.
Так делают в Active Record обычно (в Юи например). В случае Data mapper это непрактично, так как у сущности например нет доступа к БД, который может понадобиться при валидации. Так можно делать только какие-то простые валидации.
По моему опыту, вполне удобно, когда сущность просто хранит данные, а операции над ней делают другие классы. Иначе сущности становятся громоздкими и начинают напоминать God object. Но конечно возможны и другие точки зрения.
> Где должна быть валидация
По моему опыту, валидацию удобнее всего реализовывать на этапе сохранения данных в БД. Но конечно возможны и иные точки зрения.
> Валидация в конструкторе
Почему в конструкторе? Что делать с результатом валидации? Что делать, если валидация не проходит? Что делать, если мы поменяли какое-то свойство сущности?
> ENTITIES SHOULD ALWAYS BE VALID
Весьма спорная точка зрения. Как это проверять? дергать валидатор после любого изменения? А что, если я меняю несколько свойств, и в процессе изменения сущность временно становится невалидной? по моему, валидацию проще делать на каком-то определенном этапе, например, вставке в БД или вызывать явно из контроллера.
> INVALID STATE SHOULD BE IN A DIFFERENT OBJECT
> (You may need a DTO)
Выглядит как усложнение, если честно
И что самое интересное, презентация не предлангает никакого решения. Зато там надо промотать 20 картинок в начале + какое-то видео.
А вообще, если есть разные подходы, нужно сравнивать преимущества и недостатки и выбирать более подходящий. Редко бывает так, что одно решение работает дял всех случаев.
У тебя за nginx стоит php-fpm или Аапч? Почему не пишешь?
Тут http://php.net/manual/ru/install.fpm.configuration.php в примере настройки разделяются символом \n, а не точкой с запятой.
> только можно ли отдельный php.ini создать и указать в конфиге nginx или php-cgi,
Если ты используешь php-fpm, то в его конфиге можно менять настройки PHP: http://php.net/manual/ru/install.fpm.configuration.php
> php-cgi,
я надеюсь, ты не используешь PHP в режиме CGI?
> удобно это на любой location ставить любые параметры,
В ридми не забудь это описать только.
> (а сами значения в другом файле хранить для читабельности и импортировать)
Конфиг нгинкса позволяет инклюды, не знаю как насчет php-fpm.
> А как и где лучше всего делать валидацию?
На мой взгляд удобно, когда валидацией занимается отдельный сервис и ты всегда ее можешь вызвать явно:
$result = $validator->validate($something);
Часто валидация используется вместе с сохранением/обновлением (и вообще, отдельно не нужна), в этом случае удобно может быть совместить эти операции, тем самым исключая возможность сохранить невалидную сущность:
// валидирует и сохраняет
$result = $service->saveIfValid($entity);
> Например, если есть сторонняя библиотека, то нужно создавать класс, унаследованный от класса либы
Лучше бы не использовать наследование, а делегацию. То есть держать объект стороннего валидатора внутри твоего класса. А вообще, сформулируй вопрос более ясно, зачем ты там решил что-то наследовать.
> Кто-то в самой сущности предлагает это делать.
Так делают в Active Record обычно (в Юи например). В случае Data mapper это непрактично, так как у сущности например нет доступа к БД, который может понадобиться при валидации. Так можно делать только какие-то простые валидации.
По моему опыту, вполне удобно, когда сущность просто хранит данные, а операции над ней делают другие классы. Иначе сущности становятся громоздкими и начинают напоминать God object. Но конечно возможны и другие точки зрения.
> Где должна быть валидация
По моему опыту, валидацию удобнее всего реализовывать на этапе сохранения данных в БД. Но конечно возможны и иные точки зрения.
> Валидация в конструкторе
Почему в конструкторе? Что делать с результатом валидации? Что делать, если валидация не проходит? Что делать, если мы поменяли какое-то свойство сущности?
> ENTITIES SHOULD ALWAYS BE VALID
Весьма спорная точка зрения. Как это проверять? дергать валидатор после любого изменения? А что, если я меняю несколько свойств, и в процессе изменения сущность временно становится невалидной? по моему, валидацию проще делать на каком-то определенном этапе, например, вставке в БД или вызывать явно из контроллера.
> INVALID STATE SHOULD BE IN A DIFFERENT OBJECT
> (You may need a DTO)
Выглядит как усложнение, если честно
И что самое интересное, презентация не предлангает никакого решения. Зато там надо промотать 20 картинок в начале + какое-то видео.
А вообще, если есть разные подходы, нужно сравнивать преимущества и недостатки и выбирать более подходящий. Редко бывает так, что одно решение работает дял всех случаев.
>> (You may need a DTO)
> Выглядит как усложнение, если честно
Сложности - это постоянно гадать в каком состоянии сущность, есть ли в ней одни поля и обнулены ли другие, из-за чего в коде гораздо больше assert'ов и проверок вида if (!$entity->property) throw new \LogicException()
Рекомендую всё-таки посмотреть оригинальное видео: https://www.youtube.com/watch?v=WW2qPKukoZY
И есть ещё одно на ту же тему (достаточно одного аудио): https://youtu.be/lfdAwl3-X_c?t=34s
Мне кажется, что $customer->order($product) и $user->like($video) выглядят гораздо читабельнее и естественнее, чем
$likeService->addLike($user, $video) // Читается как "добавить лайк пользователю, видео"
Недавно наткнулся на интересный пример: https://gist.github.com/fesor/dda6c4c37a17509f18c2c9486323d997
Проблема с обновлением нескольких свойств решается с помощью Embeddable доктрины.
Wordpress подойдет? Или посоветуйте какая из CMS платформ надежнее для использования, даже если сложна для изучения, все равно только этим и занимаюсь.
Сам подобного сделать не смогу, но чтобы пока функционировал сайт пока основной магазин постепенно встает на ноги, просто хочу чтобы сразу люди как то набирались пока я учусь. Физическая версия магазина уже есть и там если правильно выражаюсь имеется "Клиентская база" района в котором он находится(Делу 4 года уже), сейчас появился второй магазин и он находится в городе, и пока он становится на ноги я хочу создать сайт и потихоньку его совершенствовать, а позднее перекинуть его с движка на свои наработки из головы. Подчеркну: Нет я не свалю с треда как только сделаю то, что мне нужно, не ради этого я изучаю и C, мне нравится эта деятельность
Понятное дело, что все я освоить смогу только лет через пять, но как бы не представиться за этот срок.
>У куки есть такой параметр как Path (погугли). Возможно, твои авторизационные куки доступны не на всех страницах сайта.
Не, я уже нашёл проблему. В модели User, в findIdentity($id) было return static::findOne($username); вместо return static::findOne(['id' => $id]);
И еще как лучше реализовать недавно просмотренные товары: куках или на localStorage? Есть ли нормальные библиотеки для этого, хотя вроде и так несложно.
И как реализуется поиск с множеством фильтров: диапозон цены, материал, размер? QueryBuilder'ом? Еще про ElasticSearch слышал, но не уверен, что именно он мне нужен.
И стоит ли общие для всех товаров характеристики в отдельном от jsonb поле держать (varchar, например)? Типа производитель, или туда вct характеристики одном поле jsonb, ко всем вместе?
Вордпресс не бери, из бесплатных можешь взять Opencart. Только заранее посмотри какие плагины тебе нужны, т.к. для первого опенкарта их больше.
>- ты поменял что-то в конфиге PHP, например, включил опцию scream http://php.net/manual/ru/book.scream.php
Спасибо, оп. Это у меня xdebug при установке его включил оказывается. Заодно вообще узнал что за скрим такой.
Вот Yii. Я его пытаюсь освоить. И по каждому вопросу читаю, чего умного пишут - и нихрена не понимаю. Значит нужно откатиться в самые основы. Окей. Но и в основах я тоже много чего не понимаю. Значит нужно откатиться к общей теории MVC и ООП. Окей. Но и там много непонятного. Значит нужно откатиться к кондовому php и учить его, начиная с самых основ, не пренебрегая базовыми аргоритмами, типа красно-чёрного древа, сортировки пузырьком и прочего.
Возникает вопрос: программировать-то когда? Как по мне, выучить всё это я не смогу. Просто потому, что без практики теория мертва и быстро забывается. У меня есть в мозгах некий объём памяти, но его явно не хватает. И возникает вопрос: я неправильно вкатываюсь, или просто тупой для программирования? Как бы это понять? Потому что если реально тупой, то и ну его нахрен. Смысл пытаться прыгнуть выше головы? А если не тупой, то значит нужно будет пнять, что делаю неправильно.
Да, добавлю. Я полтора года уже "вкатываюсь". Начинал с базового html/css/js/php и постепенне усложненял задачи и методы их решения. Есть три проектика, которые даже работают (хоть и кривые). А с Yii такое ощущение, что достиг потолка.
мб я не прав. но смысл по каждому вопросу что то читать. делай проект и пытаясь реализовать там какую то фишку. про неё читай. как раз будет и теория и практика.
https://jsfiddle.net/ezr3z202/
Написано же, что при копировании передает по ссылке:
https://www.google.ru/search?q=передача+массива+по+ссылке+js&oq=передача+массива+по+ссылке+js
2 вопроса:
1) Почему все хуесосят пыху и восхваляют пайтон? Может все-таки ну его? Цель стоит - как можно быстрее найти работу на 300-400 бачей джуном-макакой-петухом, как вы их там называете.
2) Дошел до урока про циклы, запилил таблицу умножения(без подглядываний!), первый раз пошевелил мозгами за последние года два при этом. Вот линк: https://ideone.com/eiRdA4 . Как её можно было накодить рациональнее и проще?
Атакую дальше.
Вообще-то нет.
Всё тот же нововкатившийся-недокатившийся.
3 часа ебал мозг как написать строчку в цикле, которая считает +10% ко вкладу каждый год(задача про 16 летнего пиздюка и 10к рублей под 10%). Вот что получилось: https://ideone.com/kfeCSZ . С ответами мануала результаты расходятся, если кто ткнет носом где я проебался в расчетах - буду признателен.
Million budet na vklade cherez 49 let.
Vkladchiku ispolnitsja 65 let.
Dojivet.
У тебя там 1000 вместо 10000
И то правда, спасибо.
Надругался над задачей про школьника и айфон в кредит: https://ideone.com/00mo1t.
У анона-гуру-опа в примере по-другому она решена, так как я - считается правильным?
П.С. Пока что самое сложное - чисто писать код, чтобы было как у анона все красиво и структурировано, у меня такое чувство, что я хаотично леплю из говна что-то. Всем похуй, но все-таки.
И еще немного добавлю. Вот есть код, который я взял с хабрахабра https://ideone.com/39V8kL
ссылка на статью: https://habrahabr.ru/post/259991/
Немного редактирую его: https://ideone.com/DvFJM2
и ломаю, но почему-то ничего не изменяется, все также значения равны true
https://ideone.com/PL3Hdm
Анонимные функции называются так, потому что, в отличие от обычных функций, у них нет имени. Анонимная функция создается, сохраняется в переменную и вызывается через эту переменную.
Создание и вызов обычной функции:
function someFunc($x) { ... }
someFunc(1000);
Создание и вызов анонимной функции:
$someFunc = function ($x) { ... };
$someFunc(1000);
Главные особенности анонимных функций:
- анонимные функции можно сохранять в переменные, складывать в массивы, передавать в функции, возвращать из функций. Например, можно сделать функцию, которая создает и возвращает анонимную функцию
- так как у них нет имени, то одну и ту же функцию можно создать в любом числе экземпляров (а 2 обычные функции с одним и тем же именем создать нельзя)
- способность при создании анонимной функции сохранить значения переменных снаружи функции с помощью слова use и позже использовать их в ней (функция вместе с сохраненными значениями внешних переменных называется замыкание - closure)
- при создании анонимной функции внутри объекта, она сохраняет значение $this, и к нему можно позже обращаться изнутри функции
Есть еще информация тут: https://habrahabr.ru/post/259991/
Зачем они нужны? Разберем пример.
Представь, что у тебя есть склад. На складе лежат товары, у каждого товара есть вес (в кг), цена и название.
Склад можно описать с помощью массива товаров (попробуй). У меня получилось так:
$warehouse = [
['name' => 'картошка', 'weight' => 100, 'price' => 100500],
['name' => 'морковка', 'weight' => 50, 'price' => 5000],
...
];
Если ты знаешь ООП, то можно представить товары в виде объектов.
Допустим, что у нас есть массив, который соответствует содержимому склада и мы хотим сделать функцию поиска товаров на складе. Если мы допустим хотим найти все товары с определенным названием, мы можем сделать такую функцию:
function findByName($warehouse, $name) { ... }
Ей передается содержимое склада и название, и она возвращает товары с таким названием (попробуй дописать).
Но эта функция умеет искать товары только по названию.
А что, если мы хотим сделать функцию, которая ищет товары на складе не только по имени, а по любым произвольным критериям? Например:
- товары с названием на букву "А"
- товары легче 100 кг
- товары, у которых цена за килограмм меньше 10
Как представить в коде и как передать в функцию эти критерии поиска? Как передать условие "вес менее 100 кг"? Тут-то и приходят на помощь анонимные функции. Мы можем выразить критерий поиска в виде анонимной функции, которая получает на вход товар и возвращает true или false в зависимости от того, соответствует товар условию поиска или нет.
Вот пример функции, которая получает на вход товар (массив с информацией об одном товаре) и проверяет, что он весит меньше 100 кг:
$checkWeightIsLessThan100 = function ($item) {
return $item['weight'] < 100;
};
Соответственно, после того как мы записали критерий поиска в виде функции-проверяльщика условия, мы можем его передать в функцию поиска:
$items = findItems($warehouse, $checkWeightLessThan100);
Задание:
1) допиши код findItems, чтобы все это работало
2) прочитай в мануале про array_map и array_filter
3) прочитай в мануале про usort. Эта функция позволяет отсортировать (упорядочить) элементы массива по произвольному критерию. Напиши функцию, которая с помощью usort отсортирует товары на складе, чтобы они шли в таком порядке:
а) сначала группа товаров с ценой менее 1000
б) за ними группа товаров с ценой менее 5000
в) за ними оставшиеся товары
Внутри групп а, б, в товары сортируются по названию (по алфавиту).
4) Напиши функцию, которая создает функции-счетчики. Наверно понять, что имеется в виду, сложно, потому дам пример кода. createCounter - это функция, которую ты и должен написать:
function createCounter($start) { ... }
$c1 = createCounter(1); // создаем первый счетчик, который начинает отсчет с 1. В $c1 должна записаться анонимная функция, которая при каждом вызове будет возвращать числа, начиная с 1
echo $с1(); // выводит 1
echo $c1(); // выводит 2
echo $c1(); // выводит 3
$c2 = createCounter(0); // создаем вторую независимую функцию-счетчик, считающую с нуля
echo $c2(); // 0
echo $c2(); // 1
// при этом первая функция-счетчик тоже работает:
echo $c1(); // 4
echo $c1(); // 5
Думаю, этого хватит, чтобы получить общее представление об анонимных функциях. Спрашивай, если что-то непонятно.
Анонимные функции называются так, потому что, в отличие от обычных функций, у них нет имени. Анонимная функция создается, сохраняется в переменную и вызывается через эту переменную.
Создание и вызов обычной функции:
function someFunc($x) { ... }
someFunc(1000);
Создание и вызов анонимной функции:
$someFunc = function ($x) { ... };
$someFunc(1000);
Главные особенности анонимных функций:
- анонимные функции можно сохранять в переменные, складывать в массивы, передавать в функции, возвращать из функций. Например, можно сделать функцию, которая создает и возвращает анонимную функцию
- так как у них нет имени, то одну и ту же функцию можно создать в любом числе экземпляров (а 2 обычные функции с одним и тем же именем создать нельзя)
- способность при создании анонимной функции сохранить значения переменных снаружи функции с помощью слова use и позже использовать их в ней (функция вместе с сохраненными значениями внешних переменных называется замыкание - closure)
- при создании анонимной функции внутри объекта, она сохраняет значение $this, и к нему можно позже обращаться изнутри функции
Есть еще информация тут: https://habrahabr.ru/post/259991/
Зачем они нужны? Разберем пример.
Представь, что у тебя есть склад. На складе лежат товары, у каждого товара есть вес (в кг), цена и название.
Склад можно описать с помощью массива товаров (попробуй). У меня получилось так:
$warehouse = [
['name' => 'картошка', 'weight' => 100, 'price' => 100500],
['name' => 'морковка', 'weight' => 50, 'price' => 5000],
...
];
Если ты знаешь ООП, то можно представить товары в виде объектов.
Допустим, что у нас есть массив, который соответствует содержимому склада и мы хотим сделать функцию поиска товаров на складе. Если мы допустим хотим найти все товары с определенным названием, мы можем сделать такую функцию:
function findByName($warehouse, $name) { ... }
Ей передается содержимое склада и название, и она возвращает товары с таким названием (попробуй дописать).
Но эта функция умеет искать товары только по названию.
А что, если мы хотим сделать функцию, которая ищет товары на складе не только по имени, а по любым произвольным критериям? Например:
- товары с названием на букву "А"
- товары легче 100 кг
- товары, у которых цена за килограмм меньше 10
Как представить в коде и как передать в функцию эти критерии поиска? Как передать условие "вес менее 100 кг"? Тут-то и приходят на помощь анонимные функции. Мы можем выразить критерий поиска в виде анонимной функции, которая получает на вход товар и возвращает true или false в зависимости от того, соответствует товар условию поиска или нет.
Вот пример функции, которая получает на вход товар (массив с информацией об одном товаре) и проверяет, что он весит меньше 100 кг:
$checkWeightIsLessThan100 = function ($item) {
return $item['weight'] < 100;
};
Соответственно, после того как мы записали критерий поиска в виде функции-проверяльщика условия, мы можем его передать в функцию поиска:
$items = findItems($warehouse, $checkWeightLessThan100);
Задание:
1) допиши код findItems, чтобы все это работало
2) прочитай в мануале про array_map и array_filter
3) прочитай в мануале про usort. Эта функция позволяет отсортировать (упорядочить) элементы массива по произвольному критерию. Напиши функцию, которая с помощью usort отсортирует товары на складе, чтобы они шли в таком порядке:
а) сначала группа товаров с ценой менее 1000
б) за ними группа товаров с ценой менее 5000
в) за ними оставшиеся товары
Внутри групп а, б, в товары сортируются по названию (по алфавиту).
4) Напиши функцию, которая создает функции-счетчики. Наверно понять, что имеется в виду, сложно, потому дам пример кода. createCounter - это функция, которую ты и должен написать:
function createCounter($start) { ... }
$c1 = createCounter(1); // создаем первый счетчик, который начинает отсчет с 1. В $c1 должна записаться анонимная функция, которая при каждом вызове будет возвращать числа, начиная с 1
echo $с1(); // выводит 1
echo $c1(); // выводит 2
echo $c1(); // выводит 3
$c2 = createCounter(0); // создаем вторую независимую функцию-счетчик, считающую с нуля
echo $c2(); // 0
echo $c2(); // 1
// при этом первая функция-счетчик тоже работает:
echo $c1(); // 4
echo $c1(); // 5
Думаю, этого хватит, чтобы получить общее представление об анонимных функциях. Спрашивай, если что-то непонятно.
Во-первых, лучше использовать var_dump или print_r, так как echo выводит только строки или числа, и не может вывести значения true/false.
Во-вторых, надо убрать assert: https://ideone.com/RClA8x
И все начнет работать верно.
Я не знаю почему так, но assert там всегда возвращает true. Ты сделал ошибку в том, что пытаешься вывести это значение (true) через echo вместо того, чтобы вывести результат самой проверки.
В самой статье echo assert нету, так что это ты сам придумал такую странную конструкцию.
Лучше не использовать транслит, а писать названия переменных по-английски (Google Translate в помощь, если забыл английский). Смотрится ужасно, читать тяжело (а вообще, PHP позволяет писать переменные кирилицей, но не надо так делать).
> for ($teloKredita;$teloKredita > 0;$n++) {
В первой части пишется действие, которое выполняется перед началом цикла. У тебя это $teloKredita - бессмысленная команда, которая ничего не делает и которую ты поставил наугад, не понимая, что она значит. Так не годится.
В твоем случае там надо либо написать $teloKredita = 40000; (а еще лучше так: $teloKredita = 40000, $n = 0; - тогда будет логичнее) либо ничего не писать вообще.
> $teloKredita=($teloKredita*1.03)+1000-$viplata;
Комиссию (1000) и процент лучше было вынести в переменные, чтобы их легко было поменять и чтобы при чтении не возникало вопроса: а что это за 1000?
Число 40000 у тебя вписано 2 раза в код, неудобно его менять.
Также, у тебя есть довольно бессмысленные вычисления:
> $sdacha=$viplata -($viplata+$teloKredita);
Достаточно вспомнить математику и увидим, что $viplata вычитается сама из себя, и остается просто
> $sdacha= -$teloKredita;
Это мы можем объединить со следующей строчкой ($vsego=$zaplatil-$sdacha;) и получится просто $vsego = $zaplatil + $teloKredita;
То есть ты переусложнил код.
Ну и сам алгоритм, вместо ухода в минус, лучше было сделать так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
> У анона-гуру-опа в примере по-другому она решена,
А там специально дан неправильный код, чтобы сбить с толку.
>>1080925
> for ($money; $money < 1000000; $n++ ) {
Тут бессмысленная первая команда $money, которая ничего не делает с переменной (увы, PHP разрешает такие бессмысленные команды). Логичнее тут сделать присвоение начальных значений переменным, которые используются в цикле (money и n).
Код выровнен неправильно, пропусти его через phpformatter.com
> echo "Million budet na vklade
Используй тут кирилицу, не пиши транслитом. У тебя где-то не работает кирилица, зачем ты тут используешь транслит? Читать ведь неудобно. Ну или пиши тогда по-английски.
Сам алгоритм верный. Но оформление кода страшноватое.
>>1080850
Если кому-то не нравится PHP, то причины надо спрашивать у них. Я тебе сэкономлю время и дам сразу готовый список: https://habrahabr.ru/post/315152/
А вообще, если ты будешь изучать PHP и потом другие языки, то сам сможешь сравнить.
Также, программа переусложнена. Мы хотим сделать таблицу умножения всех чисел от 1 до 10 на числа от 1 до 10. В таких случаях используют вложенные друг в друга циклы:
for ($i меняется от 1 до 10) {
for ($j меняется от 1 до 10) {
выводим произведение $i и $j;
}
}
Твой код работает аналогично, но записан в менее понятной форме, у меня-то сразу видно что 2 вложенных цикла, а у тебя цикл один, но он ведет себя как 2 цикла. То есть то же самое, но в более запутанном виде.
Также, ты используешь числа 1 и 11, но лучше писать 1 и 10, чтобы было понятнее.
> $x++ && $n=0;
ЧТо это за конструкция? Как она должна работать? Тут надо использовать if, а не пытаться записать код запутанным способом. && - это оператор, который выполняет код справа только если слева получилось истинное значение ( мануал http://php.net/manual/ru/language.operators.logical.php ) , и твой код эквивалентен этому:
$x++;
if ($x != 0) {
$n = 0;
}
И я не очень понимаю, зачем так сделано. Ты явно что-то перепутал тут.
Ты должен понимать каждую строчку и каждый символ в своем коде. Не надо писать код наугад. Если что-то непонятно, то задавай вопросы.
И кстати, можешь сделать вывод таблицы умножения квадратом, а не длинным списком? Я вижу, что ты хорошо соображаешь, так что, думаю, справишься. Вот тебе в помощь функция, которая выводит строку, добивая ее пробелами до определенной длины:
printf("%6s", 100); // выводит 100 + 3 пробела
printf("%6s %6s", 100, 20); // выводит 100, 3 пробела, 20, 4 пробела
printf("%4d", 10); // выводит 2 пробела, за ними 10
%6s значит, что надо вывести строку, добив ее справа пробелами минимум до 6 символов
%6d значит, что надо вывести число, добив его слева пробелами до 6 символов
Мануал: http://php.net/manual/ru/function.printf.php (что значат проценты, описано в мануале по sprintf http://php.net/manual/ru/function.sprintf.php )
Предупреждение: printf корректно добивает пробелами только цифры и латиницу, но не кирилицу (но для этой задачи этого хватит), объяснение: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Лучше не использовать транслит, а писать названия переменных по-английски (Google Translate в помощь, если забыл английский). Смотрится ужасно, читать тяжело (а вообще, PHP позволяет писать переменные кирилицей, но не надо так делать).
> for ($teloKredita;$teloKredita > 0;$n++) {
В первой части пишется действие, которое выполняется перед началом цикла. У тебя это $teloKredita - бессмысленная команда, которая ничего не делает и которую ты поставил наугад, не понимая, что она значит. Так не годится.
В твоем случае там надо либо написать $teloKredita = 40000; (а еще лучше так: $teloKredita = 40000, $n = 0; - тогда будет логичнее) либо ничего не писать вообще.
> $teloKredita=($teloKredita*1.03)+1000-$viplata;
Комиссию (1000) и процент лучше было вынести в переменные, чтобы их легко было поменять и чтобы при чтении не возникало вопроса: а что это за 1000?
Число 40000 у тебя вписано 2 раза в код, неудобно его менять.
Также, у тебя есть довольно бессмысленные вычисления:
> $sdacha=$viplata -($viplata+$teloKredita);
Достаточно вспомнить математику и увидим, что $viplata вычитается сама из себя, и остается просто
> $sdacha= -$teloKredita;
Это мы можем объединить со следующей строчкой ($vsego=$zaplatil-$sdacha;) и получится просто $vsego = $zaplatil + $teloKredita;
То есть ты переусложнил код.
Ну и сам алгоритм, вместо ухода в минус, лучше было сделать так:
- прибавляем проценты и комиссию к остатку долга (!не вычитаем ничего пока!)
- если остаток маленький, выплачиваем сколько осталось и уходим
- иначе платим 5000
> У анона-гуру-опа в примере по-другому она решена,
А там специально дан неправильный код, чтобы сбить с толку.
>>1080925
> for ($money; $money < 1000000; $n++ ) {
Тут бессмысленная первая команда $money, которая ничего не делает с переменной (увы, PHP разрешает такие бессмысленные команды). Логичнее тут сделать присвоение начальных значений переменным, которые используются в цикле (money и n).
Код выровнен неправильно, пропусти его через phpformatter.com
> echo "Million budet na vklade
Используй тут кирилицу, не пиши транслитом. У тебя где-то не работает кирилица, зачем ты тут используешь транслит? Читать ведь неудобно. Ну или пиши тогда по-английски.
Сам алгоритм верный. Но оформление кода страшноватое.
>>1080850
Если кому-то не нравится PHP, то причины надо спрашивать у них. Я тебе сэкономлю время и дам сразу готовый список: https://habrahabr.ru/post/315152/
А вообще, если ты будешь изучать PHP и потом другие языки, то сам сможешь сравнить.
Также, программа переусложнена. Мы хотим сделать таблицу умножения всех чисел от 1 до 10 на числа от 1 до 10. В таких случаях используют вложенные друг в друга циклы:
for ($i меняется от 1 до 10) {
for ($j меняется от 1 до 10) {
выводим произведение $i и $j;
}
}
Твой код работает аналогично, но записан в менее понятной форме, у меня-то сразу видно что 2 вложенных цикла, а у тебя цикл один, но он ведет себя как 2 цикла. То есть то же самое, но в более запутанном виде.
Также, ты используешь числа 1 и 11, но лучше писать 1 и 10, чтобы было понятнее.
> $x++ && $n=0;
ЧТо это за конструкция? Как она должна работать? Тут надо использовать if, а не пытаться записать код запутанным способом. && - это оператор, который выполняет код справа только если слева получилось истинное значение ( мануал http://php.net/manual/ru/language.operators.logical.php ) , и твой код эквивалентен этому:
$x++;
if ($x != 0) {
$n = 0;
}
И я не очень понимаю, зачем так сделано. Ты явно что-то перепутал тут.
Ты должен понимать каждую строчку и каждый символ в своем коде. Не надо писать код наугад. Если что-то непонятно, то задавай вопросы.
И кстати, можешь сделать вывод таблицы умножения квадратом, а не длинным списком? Я вижу, что ты хорошо соображаешь, так что, думаю, справишься. Вот тебе в помощь функция, которая выводит строку, добивая ее пробелами до определенной длины:
printf("%6s", 100); // выводит 100 + 3 пробела
printf("%6s %6s", 100, 20); // выводит 100, 3 пробела, 20, 4 пробела
printf("%4d", 10); // выводит 2 пробела, за ними 10
%6s значит, что надо вывести строку, добив ее справа пробелами минимум до 6 символов
%6d значит, что надо вывести число, добив его слева пробелами до 6 символов
Мануал: http://php.net/manual/ru/function.printf.php (что значат проценты, описано в мануале по sprintf http://php.net/manual/ru/function.sprintf.php )
Предупреждение: printf корректно добивает пробелами только цифры и латиницу, но не кирилицу (но для этой задачи этого хватит), объяснение: https://github.com/codedokode/pasta/blob/master/php/strings-utf8.md
Странный код тут:
> name : ["Hooves"]
Почему имя сделано массивом? Может быть несколько имен? Тогда должно быть не name, а names - логичнее ведь?
> document.getElementById("old").textContent = Derpy.surname;
Соответственно, еще ошибка тут. В textContent нужно записывать строку, но ты передаешь массив. Это нелогично и работает только из-за того что яваскрипт как-то неявно преобразует массив в строку. Так писать не надо.
По поводу вопроса. Начнем с теории. Примитивные значения (строки, числа, true, false, null, undefined) всегда копируются и передаются по значению. Объекты (включая массивы, функции, регулярные выражения) всегда передаются по ссылке. Пример:
// Создает в памяти новый массив и записывает ссылку (указатель на массив, идентификатор массива, номер массива) на него в a
var a = [];
// Копирует ссылку на тот же самый массив (а не сам массив) в переменную b
var b = a;
// Добавляет в массив элемент
a.push('test');
console.log(b); // ['test']
Теперь про твой код, я его чуть перепишу. Он у тебя переусложнен, и это затрудняет понимание:
var Family = {};
var Derpy = {};
// создает где-то в памяти массив №1 и записывает ссылку на него в Family.name
Family.name = ['Hooves'];
// копирует ссылку на массив №1 в Derpy.surname
Derpy.surname = Family.name;
// Изменяет фамилию в массиве №1
Family.name[0] = "Whooves";
// Создает массив №2 и записывает ссылку на него в Family.name
Family.name = ["Whooves"];
// При этом в Derpy.surname по-прежнему остается ссылка на массив №1
То есть конструкция [..] создает новый объект-массив, а оператор '=' копирует ссылку на него в переменную слева.
Странный код тут:
> name : ["Hooves"]
Почему имя сделано массивом? Может быть несколько имен? Тогда должно быть не name, а names - логичнее ведь?
> document.getElementById("old").textContent = Derpy.surname;
Соответственно, еще ошибка тут. В textContent нужно записывать строку, но ты передаешь массив. Это нелогично и работает только из-за того что яваскрипт как-то неявно преобразует массив в строку. Так писать не надо.
По поводу вопроса. Начнем с теории. Примитивные значения (строки, числа, true, false, null, undefined) всегда копируются и передаются по значению. Объекты (включая массивы, функции, регулярные выражения) всегда передаются по ссылке. Пример:
// Создает в памяти новый массив и записывает ссылку (указатель на массив, идентификатор массива, номер массива) на него в a
var a = [];
// Копирует ссылку на тот же самый массив (а не сам массив) в переменную b
var b = a;
// Добавляет в массив элемент
a.push('test');
console.log(b); // ['test']
Теперь про твой код, я его чуть перепишу. Он у тебя переусложнен, и это затрудняет понимание:
var Family = {};
var Derpy = {};
// создает где-то в памяти массив №1 и записывает ссылку на него в Family.name
Family.name = ['Hooves'];
// копирует ссылку на массив №1 в Derpy.surname
Derpy.surname = Family.name;
// Изменяет фамилию в массиве №1
Family.name[0] = "Whooves";
// Создает массив №2 и записывает ссылку на него в Family.name
Family.name = ["Whooves"];
// При этом в Derpy.surname по-прежнему остается ссылка на массив №1
То есть конструкция [..] создает новый объект-массив, а оператор '=' копирует ссылку на него в переменную слева.
Вообще, мне не нравится, что в первом уроке там есть пункт "ReactJS talks to your API". А ты знаком с ReactJs, с реализацией MVC на клиенте, с SPA? Это требует предварительного изучения темы и какого-то опыта. Я уверен, что этот пункт туда включен только ради популярного ключевого слова, которое часто встречается в вакансиях.
Далее, в этом уроке идет речь про сервисы: https://knpuniversity.com/screencast/symfony-fundamentals
Я сразу предупрежу, что если ты не изучал DI преварительно (бесстыдно прорекламирую свой урок по теме DI https://github.com/codedokode/pasta/blob/master/arch/di.md ), ну и MVC ( https://github.com/codedokode/pasta/blob/master/arch/mvc.md ) то ты плохо вообдще поймешь, зачем нужны сервисы, значем нужен контейнер и это будет выглядеть для тебя как бессмысленное усложнение.
То есть чтобы хорошо понять то, о чем говорится в курсе, необходимо иметь предварительные знания. У них курс по Симфони, а не по написанию веб-приложений вообще и не любой его сможет нормально осилить. У нас в треде люди например переходят к Симфони после решения более простых задач на студентов/файлообменник, где они знакомтся с упомянутыми MVC и DI, и сама Симфони изучается после этого проще.
Далее идет урок про Доктрину. Опять же, перед ее изучением очень полезно было бы прочитать про паттерны работы с БД, Active Record, Data Mapper ( https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md ), ну и конечно за 40 минут с Доктриной можно только познакомиться, но не изучить ее. Чтобы изучить Доктрину, придется прочесть большую часть официального мануала по ней, не надо строить иллюзий.
То есть меня беспокоит, что курсы у них какие-то маленькие, и теорию за это время нормально точно не изложить. Нужно иметь предварительные знания об ООП и MVC. Также, за такое короткое время можно дать только познакомить Симфони, а полноценно ее изучать придется по мануалам.
То есть ты можешь попробовать пройти этот курс, там тебе покажут, что можно делать с Симфони, но читать документацию на сайте Симфони придется все равно. У нас есть задачка в ОП-посте на Симфони про TestHub (посложнее) и про файлообменнник (попроще). Ты мог бы попробовать сделать одну из них, чтобы получить практический опыт, познакомиться с тем, какие сложности возникают при исопльзовании Симфони. Задача на TestHub довольно близка к реальным задачам.
Вообще, мне не нравится, что в первом уроке там есть пункт "ReactJS talks to your API". А ты знаком с ReactJs, с реализацией MVC на клиенте, с SPA? Это требует предварительного изучения темы и какого-то опыта. Я уверен, что этот пункт туда включен только ради популярного ключевого слова, которое часто встречается в вакансиях.
Далее, в этом уроке идет речь про сервисы: https://knpuniversity.com/screencast/symfony-fundamentals
Я сразу предупрежу, что если ты не изучал DI преварительно (бесстыдно прорекламирую свой урок по теме DI https://github.com/codedokode/pasta/blob/master/arch/di.md ), ну и MVC ( https://github.com/codedokode/pasta/blob/master/arch/mvc.md ) то ты плохо вообдще поймешь, зачем нужны сервисы, значем нужен контейнер и это будет выглядеть для тебя как бессмысленное усложнение.
То есть чтобы хорошо понять то, о чем говорится в курсе, необходимо иметь предварительные знания. У них курс по Симфони, а не по написанию веб-приложений вообще и не любой его сможет нормально осилить. У нас в треде люди например переходят к Симфони после решения более простых задач на студентов/файлообменник, где они знакомтся с упомянутыми MVC и DI, и сама Симфони изучается после этого проще.
Далее идет урок про Доктрину. Опять же, перед ее изучением очень полезно было бы прочитать про паттерны работы с БД, Active Record, Data Mapper ( https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md ), ну и конечно за 40 минут с Доктриной можно только познакомиться, но не изучить ее. Чтобы изучить Доктрину, придется прочесть большую часть официального мануала по ней, не надо строить иллюзий.
То есть меня беспокоит, что курсы у них какие-то маленькие, и теорию за это время нормально точно не изложить. Нужно иметь предварительные знания об ООП и MVC. Также, за такое короткое время можно дать только познакомить Симфони, а полноценно ее изучать придется по мануалам.
То есть ты можешь попробовать пройти этот курс, там тебе покажут, что можно делать с Симфони, но читать документацию на сайте Симфони придется все равно. У нас есть задачка в ОП-посте на Симфони про TestHub (посложнее) и про файлообменнник (попроще). Ты мог бы попробовать сделать одну из них, чтобы получить практический опыт, познакомиться с тем, какие сложности возникают при исопльзовании Симфони. Задача на TestHub довольно близка к реальным задачам.
Делай задачу на студентов из ОП поста тогда. Можно на том же самом Юи. Если с ООП сложности, то в ОП посте есть учебник и в нем глава по ООП с довольно понятным объяснением. Посмотри ее, если тебе все на 100% понятно, то можно конечно и не изучать.
Красно-черные деревья тебе не понадобятся. пока не захочешь понять, как устроены индексы в БД. Полезное знание, но не для твоего нынешнего уровня наверно.
> и весь товар в одной таблице, с характеристиками в jsonb от Postgres.
Это значит, чтобы получить просто название товара, например, постгресу надо будет излекать JSON и в нем искать это имя. Плюс, нет гарантий что имя вообще там есть.
Обязательные поля лучше сделать колонками. Поля, которые часто нужны (название или цена), может быть лучше тоже сделать колонками.
Поиск оптимизируется индексами. Постгрес в этом плане очень мощная и позволяет делать индексы по JSON, в том числе по отдельным полям JSON, но в твоем случае на каждую характеристику нужен свой индекс, а большое число индексов снижает производительность вставки/обновления/удаления и требует много места на диске.
Проблема с индексами решается использованием паттерна EAV. Но будет ли это работать быстро - сказать трудно, надо делать тестовую таблицу и экспериментировать.
Если производительности будет не хватать (если у тебя больше нескольких тысяч товаров), тебе понадобится внешний поисковый демон вроде sphinx или Lucene или аналогичный (ElasticSearch).
> зато БД не меняется
В случае EAV тоже.
> как лучше реализовать недавно просмотренные товары: куках или на localStorage?
Куки так как localStorage не передается на сервер, а значит придется все переусложнять и делать лишние запросы. Ты ведь надеюсь не думал засовывать HTML вертску в localStorage, а только id товаров?
Проблемы начнутся, когда ты захочешь выводить цифры в фильтрах, как в Яндекс Маркете. Мне кажется, это даже sphinx не умеет и нужно искать что-то другое.
> И как реализуется поиск с множеством фильтров
Я советую сделать объект, представляющий условия поиска (с полями, соответствующими критериям поиска). Это сильно улучшит твой код.
>>1080399
Наверняка есть сайты с обзорами и рейтингами CMS, посмотри на них.
>>1080317
> Сложности - это постоянно гадать в каком состоянии сущность, есть ли в ней одни поля и обнулены ли другие
Ну это уже вопрос, какой подход выбрать, может ли сущность быть временно невалидной или нет. Я понимаю, эта идея красиво выглядит, что все поля определены, но на практике оно плохо реализуется.
> и проверок вида if (!$entity->property) throw new \LogicException()
Это проверки все равно ведь будут, только в самой сущности например.
> Недавно наткнулся на интересный пример: https://gist.github.com/fesor/dda6c4c37a17509f18c2c9486323d997
И в этом примере мы видим, сколько тут усложнений:
- не используется присвоение id базой данных, так как поле id не может быть пустым
- используются статические методы (то есть глобальное состояние): EventStore::remember(...) - мы пишем данные непонятно куда. Что будет с ними дальше? Где гарантия что эти изменения будут сохранены и не потеряются? Из кода этого не видно. Мне это напоминает Active Record, где сущность сохраняет сама себя, только тут это делается в классе EventStore. Почему они не используют DI? наверно потому что конструктор тогда будет выглядеть некрасиво и создавать сущности неудобно.
- мы видим некий объект MetaInformation $meta - а это случайно не та самая анемичная модель?
- в конструкторе может быть много аргументов. Тут используются простые сущности, но в реальных проектах у тебя может быть до 40-50 полей у сущности (можно дробить ее на более мелкие сущности, но тут вопрос: ради чего мы это делаем? Чтобы уложиться в используемый подход?).
- тут используется listener. Искренне ненавижу паттерн Observer в серверном коде, так как он усложняет его понимание. Мне лично нравится, когда в коде идет просто последовательность команд.
Тут еще используются ревизии и, как я понимаю, подход, когда мы только вставляем новые ревизии в БД, но ничего не обновляем и не удаляем. Это навернро к анемичности модели не имеет отношения.
> Мне кажется, что $customer->order($product) и $user->like($video) выглядят гораздо читабельнее и естественнее, чем
> $likeService->addLike($user, $video) // Читается как "добавить лайк пользователю, видео"
Только тут есть один недостаток: твои классы при таком подходе будут неограниченно разрастаться. То есть там, где есть анемичная модель и 5 сервисов, работающих с ней, у тебя будет один монстр-класс.
Вот смотри, с теми же лайками у нас есть как минимум такое АПИ:
- addLike(user, object): ?Error - надо учесть, что метод может вернуть ошибку, и должен проверить разные условия (например, имеет ли право пользователь ставить лайки? не превысил ли дневной лимит лайков? можно ли ставить лайки к этой сущности? не лайкал ли он ее раньше?)
- removeLike(user, object): ?Error
- isLiked(user, object):bool или canAddLike(user, object):bool - чтобы заблокировать кнопку лайка в интерфейсе
- getLikedObjects(user): Likeable[]
- getLikeCount(object): int
- getLikers(object): User[]
Я могу сказать, что лайки относительно простое АПИ. Но даже оно потребует строк 300-400 кода, и ты предлагаешь, видимо, все это АПИ засунуть в класс User? Как минимум getLikers() туда не подойдет по смыслу. Получается, надо разбить его на части и раскидать по разным классам.
Ты упомнянул выше $customer->order($product). Ну во-первых, там будет не $product, а $cart. Даже в самом простом магизине без дисконтных программ и аналитики этот метод делает многое: проверяет пользователя и товары в корзине, резервирует товары, рассылает уведомления. Логика может быть реально сложной и ты всю ее хочешь засунуть в один класс. Ну вот тебе код реальной CMS для интернет магазинов, я думаю, там даже есть примеры описанного тобой подхода, посмотри: https://github.com/magento/magento2
Мне кажется, что удобнее иметь LikeService, который может использовать DI, который предоставляет это АПИ и который знает все о лайках, правилах их установки итд. И в нем иметь простой, понятный код, который легко изучить и поддерживать, без всяких observer. И как следствие, анемичную модель. Мне нравится идея,что слой сервисов реализует определенное внутреннее АПИ, которым пользуются вышележащие слои, например, контроллеры.
И это только одно маленькое АПИ - в реальном приложении этих АПИ будет много, будут постоянно добавляться новые. Например: комментирование, профиль пользователя, загрузка фото к товарам, поиск товаров. Плюс куча методов для вывода данных с форматированием (вроде вывода цены). Выдержит ли схема масштабирование?
Если хочешь поэкспериментировать, в ОП посте есть задача на testHub и ты можешь попробовать спроектировать объектную модель для нее. Ну и посмотри код Magento. Незачем верить мне или кому-то еще на слово, попробуй использовать предлагаемый подход на практике.
Но ты вообще правильно делаешь, что изучаешь разные подходы и мнения.
> Рекомендую всё-таки посмотреть оригинальное видео
Не буду обещать, так как не люблю смотреть видео, презентацию или статью или код готов полистать, а на видео времени обычно нету.
Ну и я тут еще кое-что вспомнил. Часто поля по логике могут быть пустыми. Ну например, автор комментария может оставить его от имени пользователя, а может оставить анонимно - и тогда поле author будет
пусто. Или пользователь может заполнить часть полей в форме, сохранить ее, а остальные заполнить позже.
>>1080399
Наверняка есть сайты с обзорами и рейтингами CMS, посмотри на них.
>>1080317
> Сложности - это постоянно гадать в каком состоянии сущность, есть ли в ней одни поля и обнулены ли другие
Ну это уже вопрос, какой подход выбрать, может ли сущность быть временно невалидной или нет. Я понимаю, эта идея красиво выглядит, что все поля определены, но на практике оно плохо реализуется.
> и проверок вида if (!$entity->property) throw new \LogicException()
Это проверки все равно ведь будут, только в самой сущности например.
> Недавно наткнулся на интересный пример: https://gist.github.com/fesor/dda6c4c37a17509f18c2c9486323d997
И в этом примере мы видим, сколько тут усложнений:
- не используется присвоение id базой данных, так как поле id не может быть пустым
- используются статические методы (то есть глобальное состояние): EventStore::remember(...) - мы пишем данные непонятно куда. Что будет с ними дальше? Где гарантия что эти изменения будут сохранены и не потеряются? Из кода этого не видно. Мне это напоминает Active Record, где сущность сохраняет сама себя, только тут это делается в классе EventStore. Почему они не используют DI? наверно потому что конструктор тогда будет выглядеть некрасиво и создавать сущности неудобно.
- мы видим некий объект MetaInformation $meta - а это случайно не та самая анемичная модель?
- в конструкторе может быть много аргументов. Тут используются простые сущности, но в реальных проектах у тебя может быть до 40-50 полей у сущности (можно дробить ее на более мелкие сущности, но тут вопрос: ради чего мы это делаем? Чтобы уложиться в используемый подход?).
- тут используется listener. Искренне ненавижу паттерн Observer в серверном коде, так как он усложняет его понимание. Мне лично нравится, когда в коде идет просто последовательность команд.
Тут еще используются ревизии и, как я понимаю, подход, когда мы только вставляем новые ревизии в БД, но ничего не обновляем и не удаляем. Это навернро к анемичности модели не имеет отношения.
> Мне кажется, что $customer->order($product) и $user->like($video) выглядят гораздо читабельнее и естественнее, чем
> $likeService->addLike($user, $video) // Читается как "добавить лайк пользователю, видео"
Только тут есть один недостаток: твои классы при таком подходе будут неограниченно разрастаться. То есть там, где есть анемичная модель и 5 сервисов, работающих с ней, у тебя будет один монстр-класс.
Вот смотри, с теми же лайками у нас есть как минимум такое АПИ:
- addLike(user, object): ?Error - надо учесть, что метод может вернуть ошибку, и должен проверить разные условия (например, имеет ли право пользователь ставить лайки? не превысил ли дневной лимит лайков? можно ли ставить лайки к этой сущности? не лайкал ли он ее раньше?)
- removeLike(user, object): ?Error
- isLiked(user, object):bool или canAddLike(user, object):bool - чтобы заблокировать кнопку лайка в интерфейсе
- getLikedObjects(user): Likeable[]
- getLikeCount(object): int
- getLikers(object): User[]
Я могу сказать, что лайки относительно простое АПИ. Но даже оно потребует строк 300-400 кода, и ты предлагаешь, видимо, все это АПИ засунуть в класс User? Как минимум getLikers() туда не подойдет по смыслу. Получается, надо разбить его на части и раскидать по разным классам.
Ты упомнянул выше $customer->order($product). Ну во-первых, там будет не $product, а $cart. Даже в самом простом магизине без дисконтных программ и аналитики этот метод делает многое: проверяет пользователя и товары в корзине, резервирует товары, рассылает уведомления. Логика может быть реально сложной и ты всю ее хочешь засунуть в один класс. Ну вот тебе код реальной CMS для интернет магазинов, я думаю, там даже есть примеры описанного тобой подхода, посмотри: https://github.com/magento/magento2
Мне кажется, что удобнее иметь LikeService, который может использовать DI, который предоставляет это АПИ и который знает все о лайках, правилах их установки итд. И в нем иметь простой, понятный код, который легко изучить и поддерживать, без всяких observer. И как следствие, анемичную модель. Мне нравится идея,что слой сервисов реализует определенное внутреннее АПИ, которым пользуются вышележащие слои, например, контроллеры.
И это только одно маленькое АПИ - в реальном приложении этих АПИ будет много, будут постоянно добавляться новые. Например: комментирование, профиль пользователя, загрузка фото к товарам, поиск товаров. Плюс куча методов для вывода данных с форматированием (вроде вывода цены). Выдержит ли схема масштабирование?
Если хочешь поэкспериментировать, в ОП посте есть задача на testHub и ты можешь попробовать спроектировать объектную модель для нее. Ну и посмотри код Magento. Незачем верить мне или кому-то еще на слово, попробуй использовать предлагаемый подход на практике.
Но ты вообще правильно делаешь, что изучаешь разные подходы и мнения.
> Рекомендую всё-таки посмотреть оригинальное видео
Не буду обещать, так как не люблю смотреть видео, презентацию или статью или код готов полистать, а на видео времени обычно нету.
Ну и я тут еще кое-что вспомнил. Часто поля по логике могут быть пустыми. Ну например, автор комментария может оставить его от имени пользователя, а может оставить анонимно - и тогда поле author будет
пусто. Или пользователь может заполнить часть полей в форме, сохранить ее, а остальные заполнить позже.
>не люблю смотреть видео
Я тоже почему то не люблю смотреть конференции и видео всякие, они отнимают времени больше, чем если бы ты у первоисточника все брал.
>И возникает вопрос: я неправильно вкатываюсь, или просто тупой для программирования?
> полтора года уже "вкатываюсь". Начинал с базового html/css/js/php и постепенне усложненял задачи и методы их решения. Есть три проектика, которые даже работают (хоть и кривые).
Хуй знает в чем у тебя проблема. Я такой же ньюфаг, только у меня наоборот было - я нихуя не понимала до того как начала решать задачки типа студентов ОПа, и мне кстати Юи зашел на отлично. Но проблема в том, что ООП и MVC как правило очень хуево объясняют. По части MVC - ну смотри. Главная фишка - отделение логики от ее представление пользователю. Это надо для того, что у тебя не было лапши в коде, и пхпшный код, и верства шаблонов(т.е. страниц сайта) было легко поддерживать - изменять, дополнять и проч.
Модели - это собственно твои данные. Именно в них производятся основные вычисления - работа с БД, всякие там алгоритмы для бизнеса. Тут главное понимать, что они только принимают какие-то данные - как правило параметры для вычислений, и возвращают результат этих вычислений - например выборку из БД, но не отображают их пользователю. Например в том же ЮИ рассказ про модели начинаются с формочек - вот к пример делаешь ты формочку для регистрации нового юзера, вот тебе сразу же модель юзера - там и валидация к примеру. Потом ты берешь эту модель и делаешь еще одну, наследованную от ActiveRecord, только она уже нужна для записи в базу, и так далее.
Вью(представление) - это просто модуль, который рисует html страничку с версткой, которая отображается пользователю. Там должно быть минимум пхпшного кода, только условия и цикли, ну и в зависимости от платформы на которой ты пишешь еще всякие там виджеты могут вставляться напрямую, но никаких вычислений.
Контроллер - это просто кусок приложения, который первым принимает запрос от пользователя(в данном случае это то что он адресную строку напишет) и на его основании решает что делать дальше. В общем виде это выглядит так: 1) Контроллер получает запрос от пользователя и разбирает его; 2) На основании полученных данных он запускает нужные вычисления в моделях 3) Получает готовые данные из моделей 4) Передает их в модуль отображения этих данных, которые потом уже рисуют вывод(html страничку).
На самом деле это все не так уж и сложно, главное базовые правила понять.
>И возникает вопрос: я неправильно вкатываюсь, или просто тупой для программирования?
> полтора года уже "вкатываюсь". Начинал с базового html/css/js/php и постепенне усложненял задачи и методы их решения. Есть три проектика, которые даже работают (хоть и кривые).
Хуй знает в чем у тебя проблема. Я такой же ньюфаг, только у меня наоборот было - я нихуя не понимала до того как начала решать задачки типа студентов ОПа, и мне кстати Юи зашел на отлично. Но проблема в том, что ООП и MVC как правило очень хуево объясняют. По части MVC - ну смотри. Главная фишка - отделение логики от ее представление пользователю. Это надо для того, что у тебя не было лапши в коде, и пхпшный код, и верства шаблонов(т.е. страниц сайта) было легко поддерживать - изменять, дополнять и проч.
Модели - это собственно твои данные. Именно в них производятся основные вычисления - работа с БД, всякие там алгоритмы для бизнеса. Тут главное понимать, что они только принимают какие-то данные - как правило параметры для вычислений, и возвращают результат этих вычислений - например выборку из БД, но не отображают их пользователю. Например в том же ЮИ рассказ про модели начинаются с формочек - вот к пример делаешь ты формочку для регистрации нового юзера, вот тебе сразу же модель юзера - там и валидация к примеру. Потом ты берешь эту модель и делаешь еще одну, наследованную от ActiveRecord, только она уже нужна для записи в базу, и так далее.
Вью(представление) - это просто модуль, который рисует html страничку с версткой, которая отображается пользователю. Там должно быть минимум пхпшного кода, только условия и цикли, ну и в зависимости от платформы на которой ты пишешь еще всякие там виджеты могут вставляться напрямую, но никаких вычислений.
Контроллер - это просто кусок приложения, который первым принимает запрос от пользователя(в данном случае это то что он адресную строку напишет) и на его основании решает что делать дальше. В общем виде это выглядит так: 1) Контроллер получает запрос от пользователя и разбирает его; 2) На основании полученных данных он запускает нужные вычисления в моделях 3) Получает готовые данные из моделей 4) Передает их в модуль отображения этих данных, которые потом уже рисуют вывод(html страничку).
На самом деле это все не так уж и сложно, главное базовые правила понять.
Вот я об этом и спрашиваю: если бы я передал во второй объект строку, значение бы не обновилось, всё по мануалу. Но я передаю массив, и значение обновляется, всё по мануалу! Но почему в 15 строке происходит также присваивание массива, но значение не обновляется? Вообще не могу понять, и я подозреваю, что это настолько важно — разобраться, что у меня просто всё зудит.
DOM (то есть обращение к textContent) тут вообще не при чем. Посмотри внимательно на ту часть кода, что я выписал в своем посте (в ней строка 15 раскомментирована). Ты можешь заменить запись в DOM на console.log - это ничего не поменяет.
То, что ты пишешь - это понятно, с этим проблм нет. Проблемы начинаются, когда нужно сделать, например, разграничение доступа по ролям. Чтобы гостю только главная страница, пользователю ве, а товарищу модератору ещё и редактирование всего. Гугл много чего по этой теме выдаёт, но я не осиливаю. Максимум на что меня хватает - это на копипасту примеров, с рулеткой; заработает/не заработает.
Нужно читать документацию по авторизации, ну и может быть код самого Юи конечно. Нужно остановиться и попробовать в чем-то разобраться от начал и до конца, а не прыгать по верхушкам.
Мне кажется, проблема в том, что ты ищешь какой-нибудь урок, повторяешь то, что там делают, но так ты всерьез не разберешься. Как минимум надо разбирать документацию, а в идеале еще и код.
>>1081164
Предлагают настроить какой-то кластер. Кластер - это когда несколько машин с БД, и они синхронизируются друг с другом.
а зачем и как завершать скрипт? мы же все равно выше редирект делаем.
>Нужно остановиться и попробовать в чем-то разобраться от начал и до конца
Дык вот на это-то у меня мозгов и не хватает. Когда пытаюсь разобраться, погружаюсь в какую-то жопу какого-нибудь метода в потрохах фреймврка и вообще не понимаю, что и почему.
Дорогой анон, огромное спасибо за отзывчивость!
Переделал задачу по кредиту следующим образом: https://ideone.com/W7VVDc
2 вопроса:
1) Мне не нравится, что нужно создавать отдельную переменную под 40000, чтобы потом посчитать переплату(так как переменная $bodyLoan(тело кредита) меняется на протяжении всего цикла и я не могу её использовать). Есть какое-то "правильное" решение?
2) Чтобы корректно обозначить месяцы вынужден присваивать n=1;, что тоже кажется костыльным и нелогичным, но ничего лучше не придумал.
Пойду пока траить остальные задачи.
Всё тот же анон, не могущий в таблицу умножения.
Таблицу сделал: https://ideone.com/SvBfDo , но вот как столбики расположить с помощью printf - так и не докумекал. Тёмный лес. Пару часов ломал голову - по нулям. Начиная с того, что понятия не имею как вложить "$i x $j = $result" в аргумент функции printf n printf("%6s", n);. И заканчивая чтением мануала, который любезно линканул ОП - голова вообще не воспринимает, что там написано.
Понял.
Студентов и файлообменник я уже делал. Тестхаб тоже начинал. Но это было где то весной, хочу заново освежить знания по симфони.
Ну в общем ответ на свой вопрос я получил. Пройду курсы. Получу общее представление обо всём, а потом к тестхабу приступлю и уже углублюсь
Очень годная подсказка, спасибо!
Но мои лыжи всё равно не едут.
Понятно как сдвинуть столбик влево или вправо, но как его "поднять", чтобы он был на одном уровне с соседним столбиком?
Я тоже постоянно открываю гугл, когда пишу код. Если ты поставишь мощную IDE вроде Netbeans или PhpStorm, то там встроен список функций и работает автодополнение по ним, и есть подсказки.
В Sublime Text тоже есть автодополнение по стандартным функциям.
Опять я. Почему implode() не хочет принимать второй параметр $yobamassiv[n]?
И почему, даже если я придумываю йоба-костыль, типа: $randomNota = [$noti[$rng]]; , то цикл срабатывает всего один раз и на выходе добавляется лишь одна нота.
https://ideone.com/PU31m0
>Почему implode() не хочет принимать второй параметр $yobamassiv[n]?
Потому что она хочет весь массив, а не его элемент. Внимательней смотри мануал.
>цикл срабатывает всего один раз и на выходе добавляется лишь одна нота.
Цикл срабатывает сколько нужно. Просто, переменная каждый раз перезаписывается.
Трудно судить о логической ошибке, по результату работы цикла. Легче, по результату каждой итерации:
https://ideone.com/9Wf5bR
Два чая, лучше помучаться над базой, изучить ее и пройти с закреплением, а потом уже не нужно будет к ней возвращаться, ну лишь в крайних случаях, и то когда вернешься все вспомнишь и не будешь тратить время.
>sqlfiddle
Нет. Sql-ex это именно задания по запросам. Задания хорошие, но интрефейс вырвиглазный.
Решил вопрос. На сайте можно скачать sql скрипты которые сами тебе все установят, а там уже можно в любой удобной среде писать запросы, я MySQL workbench юзаю. Короче рекомендую эти задачки для ньюфагов.
>На сайте можно скачать sql скрипты которые сами тебе все установят
Анон, скинь ссылку. В упор не вижу, где у них дамп скачать.
Есть таблица на 111 гб (5 млн записей), весит так много из-за того, что в каждой записи есть колонка с огромным json-ом вида {{item_id: 1, item_name: '', item_id: 4, item_name: ''}, ...}
Нужно раз в неделю обходить всю эту таблицу и пересчитывать как часто встречается каждый item, то есть на выходе будет что-то вроде
item_id | popularity
1 | 400
2 | 222
...
И вписать эти данные в таблицу Items. Как можно быстрее решить такую задачу? У меня пока только решение в лоб:
1 - достаём из БД данные частями по 5-10 тысяч (только это занимает полторы минуты каждый раз)
2 - на стороне PHP разбираем JSON, обновляем popularity для всех Items в json-е с помощью UPDATE item SET popularity = popularity + 1 WHERE id IN (...)
Есть ещё идея скрипт по определению popularity выполнить один раз и на каждое изменение json-массива триггерить пересчёт popularity только для нескольких item.
http://www.sql-ex.ru/db_script_download.php держи. Только там перед use 'computers' надо два тире удалить, тогда нормально запрос отработает. Хз что это такое.
array_map проходится по массиву, применяя функцию к каждому элементу, на выходе у array_map новый массив, старый останется нетронутым.
Допустим у тебя есть функция, которая прибавляет к аргументу число 2:
function plus2($arg) {
return $arg + 2;
};
plus2(10); // выдаст 12
Можно применить эту функцию к массиву, если ты хочешь, чтобы все его элементы увеличились на 2:
$arr = [1,2,3];
var_dump(array_map('plus2', $arr)); // выдаст [3,4,5]
var_dump($arr); // выдаст [1,2,3]
array_walk принимает аргументы по ссылке, модифицируя старый массив, то есть такая функция не является чистой, приводит к побочным эффектам и как следствие трудноуловимым ошибкам.
>>1081903
Нельзя там группировкой, я же пишу, что данные в JSON и разбирать их нужно только на стороне PHP. Используется старая версия MySQL без поддержки JSON Data Type.
Как они сделали такой выбор размера-цены? На уровне БД это как может выглядеть? Как вообще в БД делаются такие вещи, когда есть много размеров (цветов) и разные цены соответственно?
> достаём из БД данные частями по 5-10 тысяч (только это занимает полторы минуты каждый раз)
Это такой большой объем данных или же выборка сделана неэффективно? Если вы там в таблицу запихиваете многомегабайтный JSON, я конечно, помочь не смогу, а если дело в выборке, то вполне.
Выборки вида SELECT ... FROM table LIMIT 1000 OFFSET 100000 довольно неэффективны, так как надо пропускать много записей. Гораздо эффективнее использовать выборку по индексированному полю (например, id или времени вставки):
Первый раз делаем SELECT ... FROM table LIMIT 1000 и запоминаем id последней записи
Второй раз делаем SELECT ... FROM table WHERE id > :lastId LIMIT 1000 и снова берем id последней записи
И так далее.
Статьи
http://use-the-index-luke.com/no-offset
https://habrahabr.ru/post/217521/
https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
https://ruhighload.com/post/Paging+using+MySQL
Далее, обновление тоже можно оптимизировать. Запрос на обновление создает неявную транзакцию и коммитить транзакцию на каждую строчку может быть неэффективно. выгоднее может быть открыть транзакцию, обновить N (N ~ 1000, подбирается опытным путем) строчек и закоммитить (гугли optimise bulk updat mysql).
Ну и разумеется, неэффективно обновлять одну и ту же строчку несколько раз. Надо на стороне PHP группировать данные и делать UPDATE ... SET x = x + N вместо нескольких запросов.
Вообще, если разных item_id не очень много то можно вообще сначала пройтись по всей исходной таблице, накопить в массиве количества, а только потом обновить.
И еще конечно остаются очевидные варианты в виде денормализации данных, вынесению из JSON во внешние таблицы.
Я работал с таблицами такого объема и конечно неколько минут на выборку (если там не сложный запрос) это конечно перебор. У тебя ведь просто выборка через SELECT ... FROM table без хитрых джойнов и условий?
> достаём из БД данные частями по 5-10 тысяч (только это занимает полторы минуты каждый раз)
Это такой большой объем данных или же выборка сделана неэффективно? Если вы там в таблицу запихиваете многомегабайтный JSON, я конечно, помочь не смогу, а если дело в выборке, то вполне.
Выборки вида SELECT ... FROM table LIMIT 1000 OFFSET 100000 довольно неэффективны, так как надо пропускать много записей. Гораздо эффективнее использовать выборку по индексированному полю (например, id или времени вставки):
Первый раз делаем SELECT ... FROM table LIMIT 1000 и запоминаем id последней записи
Второй раз делаем SELECT ... FROM table WHERE id > :lastId LIMIT 1000 и снова берем id последней записи
И так далее.
Статьи
http://use-the-index-luke.com/no-offset
https://habrahabr.ru/post/217521/
https://dev.mysql.com/doc/refman/5.7/en/limit-optimization.html
https://ruhighload.com/post/Paging+using+MySQL
Далее, обновление тоже можно оптимизировать. Запрос на обновление создает неявную транзакцию и коммитить транзакцию на каждую строчку может быть неэффективно. выгоднее может быть открыть транзакцию, обновить N (N ~ 1000, подбирается опытным путем) строчек и закоммитить (гугли optimise bulk updat mysql).
Ну и разумеется, неэффективно обновлять одну и ту же строчку несколько раз. Надо на стороне PHP группировать данные и делать UPDATE ... SET x = x + N вместо нескольких запросов.
Вообще, если разных item_id не очень много то можно вообще сначала пройтись по всей исходной таблице, накопить в массиве количества, а только потом обновить.
И еще конечно остаются очевидные варианты в виде денормализации данных, вынесению из JSON во внешние таблицы.
Я работал с таблицами такого объема и конечно неколько минут на выборку (если там не сложный запрос) это конечно перебор. У тебя ведь просто выборка через SELECT ... FROM table без хитрых джойнов и условий?
Либо там есть таблица цен-размеров, где хранятся строки вида:
id товара | id размера (или сам размер) | цена
Либо там цена как-то считается просто по формуле.
А что сложного-то?
Кстати, могу поделиться еще одной хитростью. Если у тебя есть сфинкс (sphinx search), то он выполняет группировки в несколько раз (иногда раз в 10-20) быстрее mysql. То есть если есть большая таблица (как у тебя) и надо например посчитать, сколько раз там встречается то или иное значение:
SELECT x, COUNT(*) FROM t GROUP BY x;
То сфинкс может оказаться быстрее. Хотя по идее и mysql и сфинксу нужно сделать полный обход таблицы, но у сфинкса это получается быстрее , может он как-то данные эффективнее в памяти хранит, не знаю, но разница может быть приличной, раз в 10-20. Мне кажется, это связано с тем, что в сфинксе просто меньше данных, которые надо обойти.
Через preg_split просто вырезает кусок из текста.
текст под регулярку*
задание из темы повторим.
Но я чет передумал, не отвечайте мне.
Хочу додуматься сам
Я так и думал, но вопрос: как такие промежуточные таблицы в ORM мапятся, но то есть на одну сущность или на две?
Задачка ОПА про стихосложение, например:
https://ideone.com/bFOly8
Ебал ей голову себе пол дня, в итоге сами видите че. Я безнадежен? Как вылечить тротлинг мозга?
Я правда хочу осилить хотя бы рублёвое пиэйчпи, готов ебашить сутки напролет, благо времени куча. Как расшевелить мозги? Может логические задачки какие порешать, или книги про алгоритмы почитать?
Наверно зависит от ORM. В Доктрине одна таблица это одна сущность, значит на таблицу цен нужен отдельный класс.
Не понимаю, в чем тут сложность. В принципе, никто не запрещает добавить метод получения всех цен в класс товара так, что про дополнительную таблицу даже знать не надо.
Вряд ли. Для них есть отдельные треды.
Если ты изучаешь C - добро пожаловать сюда: https://2ch.hk/pr/res/1074988.html (М) ,
C++ ? Тогда сюда https://2ch.hk/pr/res/1065530.html (М)
>Также, у тебя нет обработки ошибок, а промисы по умолчанию "съедают" ошибки, и ты о них может быть не узнаешь (точнее, узнаешь, если поставишь обработчик unhandledPromise или как-то так).
У меня есть обработка ошибок в готовом черновом коде, но она идёт немного запутанным способом
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L62
Ошибка отправляется назад в backend. Я это исправлю в скоре.
>unhandledPromise
Я не совсем понял что это такое, это когда ошибку обрабатывают внутри экзекьютора Общеания?
var promise = new Promise(function (resolve, reject) {
if (something) {
resolve();
} else {
//unhandledPromise
reject();
}
});
>У меня тут нет кода обработки ошибок - ошибок получения сообщений и ошибок расшифровки. Это уже ты должен смотреть по логике приложения, как ошибки должны обрабатываться.
Я впервые пишу приложение на js и впервые работаю с его библеотеками, и у меня ещё большая путаница в голове с Обещаниями. Можно подсказку как узнавать что ошибка произошла? То есть например, в случае с ajax мы на вход функции onRejected отправляем jqXHR и textStatus. Насколько я понимаю, они (аргументы функции) появляются в самом коде метода ajax и возвращаются с помощью Promise.reject(jqXHR, textStatus), я правильно понимаю? Из чего следует, что подробности об ошибке Обещания нужно искать в самом коде приложения. Это так?
>Также, тут есть недостаток. Расшифровка сообщений - асинхронная, но тут мы ждем, пока они не расшифруются все. Можно написать более продвинутую версию кода:
>decryptedPromise.done(function (decrypted) {
>.done()
У стандартного ES6 класса Promise нету метода .done().
>Здесь мы видим громоздкую тяжелочитаемую конструкцию, а это верный признак проблемы, которая решается "добавлением еще одной абстракции". Попробуем применить тут реактивное программирование. Я напомню, что там есть объект Observable, который представляет собой поток каких-то событий. У нас будет 2 потока: поток, в который прибывают зашифрованные сообщения, и поток, в который приходя расшифрованные сообщения.
Я ещё только ознакамливаюсь с паттерном Observable и реактивным порграммированием. У меня в совокупности с вашими замечаниями ( https://gist.github.com/codedokode/6dfde1f0ec3d895bc940b67e7919cc29 ), в которых вы упоминали об этом, есть к этому вопросы, которые я задам после того как напишу приложение без модели. Причина по которой я хочу написать приложение без модели, это потому, что я хочу на собственом опыте хочу понять в чём разница между приложением с моделью и приложением с ней.
>>1080119
>Думаю, речь об этих плагинах, хотя не уверен: https://dev.mysql.com/doc/refman/5.7/en/authentication-plugins.html
Я должен оговориться, что в Debian stretch заместо mysql идёт MariaDB. Я не знаю как теперь у mysql с этим обстоят дела. Наверно, нужно проверить.
>Если ты используешь phpMyAdmin, проверь, что он не доступен снаружи. Были раньше случаи, когда там находили дыры, и я бы не стал его выставлять в интернет вообще. Ну или хотя бы закрыл HTTP авторизацией, доверия к его коду у меня нету. И защиты от подбора паролей там по моему тоже нет.
Я не пользуюсь им, потому что мне кажется что такого рода приложения говорят о некомпетенции программиста, потому что доступ к mysql можно получить и через консоль. То что вы тоже не доверияте ему говорит о том, что моя интуиция мне подсказывает правильно.
>Также, у тебя нет обработки ошибок, а промисы по умолчанию "съедают" ошибки, и ты о них может быть не узнаешь (точнее, узнаешь, если поставишь обработчик unhandledPromise или как-то так).
У меня есть обработка ошибок в готовом черновом коде, но она идёт немного запутанным способом
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L62
Ошибка отправляется назад в backend. Я это исправлю в скоре.
>unhandledPromise
Я не совсем понял что это такое, это когда ошибку обрабатывают внутри экзекьютора Общеания?
var promise = new Promise(function (resolve, reject) {
if (something) {
resolve();
} else {
//unhandledPromise
reject();
}
});
>У меня тут нет кода обработки ошибок - ошибок получения сообщений и ошибок расшифровки. Это уже ты должен смотреть по логике приложения, как ошибки должны обрабатываться.
Я впервые пишу приложение на js и впервые работаю с его библеотеками, и у меня ещё большая путаница в голове с Обещаниями. Можно подсказку как узнавать что ошибка произошла? То есть например, в случае с ajax мы на вход функции onRejected отправляем jqXHR и textStatus. Насколько я понимаю, они (аргументы функции) появляются в самом коде метода ajax и возвращаются с помощью Promise.reject(jqXHR, textStatus), я правильно понимаю? Из чего следует, что подробности об ошибке Обещания нужно искать в самом коде приложения. Это так?
>Также, тут есть недостаток. Расшифровка сообщений - асинхронная, но тут мы ждем, пока они не расшифруются все. Можно написать более продвинутую версию кода:
>decryptedPromise.done(function (decrypted) {
>.done()
У стандартного ES6 класса Promise нету метода .done().
>Здесь мы видим громоздкую тяжелочитаемую конструкцию, а это верный признак проблемы, которая решается "добавлением еще одной абстракции". Попробуем применить тут реактивное программирование. Я напомню, что там есть объект Observable, который представляет собой поток каких-то событий. У нас будет 2 потока: поток, в который прибывают зашифрованные сообщения, и поток, в который приходя расшифрованные сообщения.
Я ещё только ознакамливаюсь с паттерном Observable и реактивным порграммированием. У меня в совокупности с вашими замечаниями ( https://gist.github.com/codedokode/6dfde1f0ec3d895bc940b67e7919cc29 ), в которых вы упоминали об этом, есть к этому вопросы, которые я задам после того как напишу приложение без модели. Причина по которой я хочу написать приложение без модели, это потому, что я хочу на собственом опыте хочу понять в чём разница между приложением с моделью и приложением с ней.
>>1080119
>Думаю, речь об этих плагинах, хотя не уверен: https://dev.mysql.com/doc/refman/5.7/en/authentication-plugins.html
Я должен оговориться, что в Debian stretch заместо mysql идёт MariaDB. Я не знаю как теперь у mysql с этим обстоят дела. Наверно, нужно проверить.
>Если ты используешь phpMyAdmin, проверь, что он не доступен снаружи. Были раньше случаи, когда там находили дыры, и я бы не стал его выставлять в интернет вообще. Ну или хотя бы закрыл HTTP авторизацией, доверия к его коду у меня нету. И защиты от подбора паролей там по моему тоже нет.
Я не пользуюсь им, потому что мне кажется что такого рода приложения говорят о некомпетенции программиста, потому что доступ к mysql можно получить и через консоль. То что вы тоже не доверияте ему говорит о том, что моя интуиция мне подсказывает правильно.
Да ладно, как будто я и не знал.
Нее спасибо, там какие то ублюдки агрессивные сидят, нет уж, останусь тут.
Типа того. Скоро его место phalcon займет. А вообще они не нужны когда ты можешь в симфони/доктрину.
http://sandbox.onlinephpfunctions.com/code/c02804add7e68d607e821d536ba1c7664c4ff505
Тут все вкатываются через учебник в шапке.
select distinct
maker
from
product
where
product.type IN ('PC') AND product.type NOT IN ('Laptop')
Я не понимаю как работает NOT IN?
Мануал https://dev.mysql.com/doc/refman/5.7/en/comparison-operators.html#function_not-in
> expr NOT IN (value,...)
> This is the same as NOT (expr IN (value,...)).
Проверяет, что значение поля НЕ входит в список. В твоем случае равносильно type <> 'Laptop'.
Только надо учесть что в случае NULL там может быть особое поведение. Например сравнение NULL = NULL вернет не 1 (истина), а UNKNOWN если я не путаю. Мануал: https://dev.mysql.com/doc/refman/5.7/en/working-with-null.html
Тут будут только ответы на старые посты. Если вас пропустили - напомните о себе в новом треде.
>>1082050
Наверно нужно больше практики. Всегда можно попросить дополнительные задачки по той или иной теме. Вот тебе пример задачек:
-----
Дан список товаров на складе вида (название, вес), например:
ром, 50 кг
сахар, 100 кг
ром, 35 кг
сахар, 20 кг
болты, 200 кг
Как видно, некоторые товары повторяются. Напиши программу, которая принимает на вход список товаров (в каком виде - придумай сам) и выводит сгруппированный по товарам список, для примера выше это будет:
ром, 85 кг
сахар, 120 кг
болты, 200 кг
-----
Дан текст, найди в нем слова, которые встречаются больше 1 раза. Текст может содержать слова на русском языке, пробелы между ними и знаки препинания. Пример текста: "Ехал Грека через реку, видит Грека - в реке рак." (повторяется слово "Грека").
-----
Дан текст, найди в нем слова, в которых идет 3 или более согласных подряд.
-----
По задаче: код переусложнен. Вот смотри, у тебя есть такая строчка:
$slovar = [$word1,$word2,$word3, ["\n"], $word4,$word5];
В ней задается массив массивов слов, и мы должны пройтись по очереди и из каждого массива выбрать случайно по одному слову. Правда не хватает последней строчки, но это решается добавлением в массив нескольких элеиментов. Ты зачем-то написал там сложный запутанный код, но можно было сделать так:
для (каждого отдельного массива в $slovar) {
берем случайное слово из массива;
выводим его;
}
Ну и конкретно по коду:
> if ($i/3 == 1) {
Не проще написать if ($i == 3) ?
Ну и циклы как-то переусложнены.
Тут будут только ответы на старые посты. Если вас пропустили - напомните о себе в новом треде.
>>1082050
Наверно нужно больше практики. Всегда можно попросить дополнительные задачки по той или иной теме. Вот тебе пример задачек:
-----
Дан список товаров на складе вида (название, вес), например:
ром, 50 кг
сахар, 100 кг
ром, 35 кг
сахар, 20 кг
болты, 200 кг
Как видно, некоторые товары повторяются. Напиши программу, которая принимает на вход список товаров (в каком виде - придумай сам) и выводит сгруппированный по товарам список, для примера выше это будет:
ром, 85 кг
сахар, 120 кг
болты, 200 кг
-----
Дан текст, найди в нем слова, которые встречаются больше 1 раза. Текст может содержать слова на русском языке, пробелы между ними и знаки препинания. Пример текста: "Ехал Грека через реку, видит Грека - в реке рак." (повторяется слово "Грека").
-----
Дан текст, найди в нем слова, в которых идет 3 или более согласных подряд.
-----
По задаче: код переусложнен. Вот смотри, у тебя есть такая строчка:
$slovar = [$word1,$word2,$word3, ["\n"], $word4,$word5];
В ней задается массив массивов слов, и мы должны пройтись по очереди и из каждого массива выбрать случайно по одному слову. Правда не хватает последней строчки, но это решается добавлением в массив нескольких элеиментов. Ты зачем-то написал там сложный запутанный код, но можно было сделать так:
для (каждого отдельного массива в $slovar) {
берем случайное слово из массива;
выводим его;
}
Ну и конкретно по коду:
> if ($i/3 == 1) {
Не проще написать if ($i == 3) ?
Ну и циклы как-то переусложнены.
Код надо было сдвинуть влево на 4 пробела, после <?php отступ не добавляется.
@access private можно не писать, это писали в PHP4, когда не было ключевых слов private/public, а сейчас они есть и дублировать их не требуется.
> Get an array of employees
> @return array
Лучше писать @return Employee[] (мануал http://docs.phpdoc.org/guides/types.html#arrays )
Также, ты по-видимому используешь PHP7, обрати внимание, что там тип возвращаемого значения можно указать в самой функции:
public function getDepartmentName():string { ... }
Идея с переопределением констант мне не очень нравится:
- константы это по сути что-то неизменное и не переопределяемое
- нет гарантий, что тот, кто наследует твой класс, не забудет их переопределить
- не очевидно, что при наследовании класса Employee надо переопределить константы
Первую проблему можно решить, заменив константы на статическое или обычное поле с значением по умолчанию. Но это не решит проблемы 2 и 3. Все эти проблемы можно решить, если объявить в базовом классе абстрактные методы вроде getBasicSalary(). Тогда не определить их при наследовании не получится.
> private function addEmployeeToDepartment(
> switch ($profession) {
В таких случаях стоит всегда добавлять default с выбросом исключения для отлова ошибок.
Насчет класса Report - там можно попробовать убрать копипасту использованием массивов, где каждый элемент соответствует колонке:
$header = ['Департамент', 'сотр.', 'тугр.', 'кофе'];
$rows[] = [
$dep->getName(),
$dep->getEmployeeCount(),
...
];
Соответственно, не придется копипастить ширину колонок много раз. Также, если есть желание усложнить код, можно было сделать отдельный класс для вывода произвольных таблиц.
Не надо много раз писать try/catch, можно сделать это 1 раз, а можно вообще не ловить исключение, так как по умолчанию PHP его выведет сам.
Вообще, сделано хорошо, и код, и документация. Если ты начинающий, то это вообще очень хороший результат.
Ждем еще антикризисные меры.
Если захочешь еще попрактиковать ООП, у меня есть задачка про гостиницу:
------
Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер, количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу приезжают Гости. Нужно сделать ООП-модель Гостиницы с такими возможностями:
- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо подобрать им самый дешевый и маленький Номер, который их вместит и который свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается заселить их в несколько номеров, опять же, начиная с самых дешевых. Например, приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3 1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель заработал X тугриков, в день B - Y тугриков и так далее)
----
И если хочешь попрактиковаться еще, в учебнике была задача про вычисление выражения. Усложненная версия этой задачи - вычислить выражение с учетом приоритетов операций, добавить работу с обычными дробями (вроде 1/3) без потерь точности, все это на ООП. Хотя если честно, это может отнять время, так что может и не стоит делать.
Код надо было сдвинуть влево на 4 пробела, после <?php отступ не добавляется.
@access private можно не писать, это писали в PHP4, когда не было ключевых слов private/public, а сейчас они есть и дублировать их не требуется.
> Get an array of employees
> @return array
Лучше писать @return Employee[] (мануал http://docs.phpdoc.org/guides/types.html#arrays )
Также, ты по-видимому используешь PHP7, обрати внимание, что там тип возвращаемого значения можно указать в самой функции:
public function getDepartmentName():string { ... }
Идея с переопределением констант мне не очень нравится:
- константы это по сути что-то неизменное и не переопределяемое
- нет гарантий, что тот, кто наследует твой класс, не забудет их переопределить
- не очевидно, что при наследовании класса Employee надо переопределить константы
Первую проблему можно решить, заменив константы на статическое или обычное поле с значением по умолчанию. Но это не решит проблемы 2 и 3. Все эти проблемы можно решить, если объявить в базовом классе абстрактные методы вроде getBasicSalary(). Тогда не определить их при наследовании не получится.
> private function addEmployeeToDepartment(
> switch ($profession) {
В таких случаях стоит всегда добавлять default с выбросом исключения для отлова ошибок.
Насчет класса Report - там можно попробовать убрать копипасту использованием массивов, где каждый элемент соответствует колонке:
$header = ['Департамент', 'сотр.', 'тугр.', 'кофе'];
$rows[] = [
$dep->getName(),
$dep->getEmployeeCount(),
...
];
Соответственно, не придется копипастить ширину колонок много раз. Также, если есть желание усложнить код, можно было сделать отдельный класс для вывода произвольных таблиц.
Не надо много раз писать try/catch, можно сделать это 1 раз, а можно вообще не ловить исключение, так как по умолчанию PHP его выведет сам.
Вообще, сделано хорошо, и код, и документация. Если ты начинающий, то это вообще очень хороший результат.
Ждем еще антикризисные меры.
Если захочешь еще попрактиковать ООП, у меня есть задачка про гостиницу:
------
Есть Гостиница, в ней есть Номера. Для каждого Номера известен его номер, количество Гостей, которое в него влезет, а также цена за сутки. В Гостиницу приезжают Гости. Нужно сделать ООП-модель Гостиницы с такими возможностями:
- получить список свободных номеров на определенную дату
- получить список свободных номеров, которые будут свободны в определенный диапазон дат (от A до B)
- дан список Гостей и диапазон дат, в которые они хотели бы заселиться. Необходимо подобрать им самый дешевый и маленький Номер, который их вместит и который свободен в это время.
- то же самое, но при отстутствии одного подходящего номера для Гостей разрешается заселить их в несколько номеров, опять же, начиная с самых дешевых. Например, приехало 3 Гостя, но все 3-местные номера заняты и мы выделяем 2 2-местных, или 3 1-местных или 1-местный + 2-местный.
- зарегистрировать проживание данных Гостей в данных Номерах на данный период
- получить историю заселения Номера (кто в нем когда жил)
- получить историю заселения Гостя (в каких номерах он жил)
- получить статистику доходов Гостиницы за данный диапазон дат (в день A отдель заработал X тугриков, в день B - Y тугриков и так далее)
----
И если хочешь попрактиковаться еще, в учебнике была задача про вычисление выражения. Усложненная версия этой задачи - вычислить выражение с учетом приоритетов операций, добавить работу с обычными дробями (вроде 1/3) без потерь точности, все это на ООП. Хотя если честно, это может отнять время, так что может и не стоит делать.
Попробовал осилить палиндром.
Вот только на ideone видимо открутили mb модуль.
Нашел альтернативу: http://phpfiddle.org/
Но без понятия как линковать оттуда код, поэтому линк бросаю на ideone:
https://ideone.com/hlU88a
Может кому-то не лень будет копипастнуть оттуда код.
Ты имеешь в виду что? Разбить текст на массив предложений? На массив слов?
Если на предложения, то тут все просто, предложение заканчивается одним из знаков . ? ! - значит достаточно написать регулярку, которая ищет один любой из этих символов.
Если на слова, то надо разбивать по не-буквам (так как слово это последовательность букв).
Что ты имеешь в виду? Блоки, которые повторяются на одной странице или на разных страницах сайта?
Вообще, есть концепция верстки независимыми блоками, так, что любой блок можно легко взять и перенести в другое место сайта например, она называется БЭМ: https://ru.bem.info/methodology/quick-start/
>>1081728
Тебе надо либо хранить сессии PHP в БД либо сделать аналог сессий с хранением в БД. Как иначе-то?
>>1081546
Код какой-то странный:
> $randomNota = [$noti[$rng]];
Зачем создавать массив из единственного элеимента?
Тебе надо сделать так:
- либо завести пустую строку и на каждом шаге цикла добавлять к ней еще одну ноту
- либо создать пустой массив до цикла и на каждом шаге цикла класть в него еще одну ноту. А после цикле склеить ноты в строку через implode:
$notes = [];
...
$notes[] = 'do';
....
echo implode(' ', $notes);
Алсо на западе ноты часто обозначают просто буквами (c = до, d = ре и так далее). Ну или ты можешь просто писать их по-русски.
Что ты имеешь в виду? Блоки, которые повторяются на одной странице или на разных страницах сайта?
Вообще, есть концепция верстки независимыми блоками, так, что любой блок можно легко взять и перенести в другое место сайта например, она называется БЭМ: https://ru.bem.info/methodology/quick-start/
>>1081728
Тебе надо либо хранить сессии PHP в БД либо сделать аналог сессий с хранением в БД. Как иначе-то?
>>1081546
Код какой-то странный:
> $randomNota = [$noti[$rng]];
Зачем создавать массив из единственного элеимента?
Тебе надо сделать так:
- либо завести пустую строку и на каждом шаге цикла добавлять к ней еще одну ноту
- либо создать пустой массив до цикла и на каждом шаге цикла класть в него еще одну ноту. А после цикле склеить ноты в строку через implode:
$notes = [];
...
$notes[] = 'do';
....
echo implode(' ', $notes);
Алсо на западе ноты часто обозначают просто буквами (c = до, d = ре и так далее). Ну или ты можешь просто писать их по-русски.
>Если ты знаешь ООП.
К сожалению, еще не начал изучать.
> Ей передается содержимое склада и название, и она возвращает товары с таким названием (попробуй дописать).
Вот: https://ideone.com/XhydTt#stdin. Правильно ли дописал? А то может я неправильно понял. Если правильно, то можно было как-то лучше? Спасибо.
> Мы можем выразить критерий поиска в виде анонимной функции, которая получает на вход товар и возвращает true или false в зависимости от того, соответствует товар условию поиска или нет.
И что будет если вернется true ? false ?
что будет если искать товар с параметром false?
Я обязательно сейчас буду пытаться понять, просто кусочек написал, чтобы разбираться потихоньку
Когда ты пишешь выражение вроде
(....){10}
То в круглые скобки будет захвачена только одна цифра (скорее всего последняя). Это легко исправить, добавив еще одни круглые скобки:
((...){10})
А внутреннии скобки можно сделать незахватывающими.
> Мне не нравится, что нужно создавать отдельную переменную под 40000, чтобы потом посчитать переплату(так как переменная $bodyLoan(тело кредита) меняется на протяжении всего цикла и я не могу её использовать). Есть какое-то "правильное" решение?
Можно присвоить в начале программы $bodyLoad = 40000 и дальше ее же уменьшать. Можно сделать 2 переменных - начальное, неизменное значение и текущее значение долга.
В коде у тебя числа 40 000 и 5 000 повторяются 2 раза - это стоит исправить.
Для вычисления суммы выплаченного можно обойтись без $n, просто увеличивая каждый раз $totalPay на сумму выплаты.
> Total for the loan was paid: 56270.186744521 RUB
А должно быть 61270. Ты там чуть ошибся с формулами.
>>1081346
Выводить текст можно только слева направо и сверху вниз. Значит, надо выводить его в правильном порядке.
Посмотрим на пример таблицы:
...1...2...3...4
...5...6...7...8
Как такую таблицу вывести? Если присмотреться, видно, что перед каждым числом стоит по 3 пробела, а в общем под одно число отведено 4 символа (3 пробела + 1 цифра). Мы выводим 4 числа, затем переводим строку и выводим еще 4 числа:
printf("%4d", 1);
printf("%4d", 2);
printf("%4d", 3);
printf("%4d", 4);
echo "\n";
printf("%4d", 5);
printf("%4d", 6);
printf("%4d", 7);
printf("%4d", 8);
%4d - 4 здесь значит ширину поля, а d - значит, что мы выводим число.
Вот тебе надо сделать примерно то же, но не копипастой одной и той же строки, а циклом.
>>1081174
Можешь в треде спросить, правда не сразу, но ответят.
> Мне не нравится, что нужно создавать отдельную переменную под 40000, чтобы потом посчитать переплату(так как переменная $bodyLoan(тело кредита) меняется на протяжении всего цикла и я не могу её использовать). Есть какое-то "правильное" решение?
Можно присвоить в начале программы $bodyLoad = 40000 и дальше ее же уменьшать. Можно сделать 2 переменных - начальное, неизменное значение и текущее значение долга.
В коде у тебя числа 40 000 и 5 000 повторяются 2 раза - это стоит исправить.
Для вычисления суммы выплаченного можно обойтись без $n, просто увеличивая каждый раз $totalPay на сумму выплаты.
> Total for the loan was paid: 56270.186744521 RUB
А должно быть 61270. Ты там чуть ошибся с формулами.
>>1081346
Выводить текст можно только слева направо и сверху вниз. Значит, надо выводить его в правильном порядке.
Посмотрим на пример таблицы:
...1...2...3...4
...5...6...7...8
Как такую таблицу вывести? Если присмотреться, видно, что перед каждым числом стоит по 3 пробела, а в общем под одно число отведено 4 символа (3 пробела + 1 цифра). Мы выводим 4 числа, затем переводим строку и выводим еще 4 числа:
printf("%4d", 1);
printf("%4d", 2);
printf("%4d", 3);
printf("%4d", 4);
echo "\n";
printf("%4d", 5);
printf("%4d", 6);
printf("%4d", 7);
printf("%4d", 8);
%4d - 4 здесь значит ширину поля, а d - значит, что мы выводим число.
Вот тебе надо сделать примерно то же, но не копипастой одной и той же строки, а циклом.
>>1081174
Можешь в треде спросить, правда не сразу, но ответят.
die(), exit(), может быть return - зависит от того, как твой скрипт написан.
>>1082173
Насчет обработки ошибок - я что-то сам пока не представляю, как лучше сделать. Тут можно использовать разные подходы:
- можно попробовать сделать функции, которые в принципе не возвращают ошибку, а пытаются провести операцию повторно (можно с увеличивающимся интервалом). Только тут надо предусмотреть отмену операции, а то может накопиться много таких "вечных" операций.
- можно попробовать сделать централизованный обработчик, и прикрутить к нему индикатор ошибки в интерфейсе (который будет показывать что есть проблемы со связью, или что сейчас выполняется запрос). Ну например, если у нас есть модуль работы с API то мы можем в нем это и реализовать.
- также, в случае мессенджера можно около сообщения показывать его статус (отпраляется - отправлено - невозможно отправить)
То есть тут надо сначала решить, что мы делаем при ошибках, что делаем с интерфейсом, а только потом проектировать код.
> У меня есть обработка ошибок
Вместо объекта результата jQuery, лучше наверно стандартный промис возвращать.
>>unhandledPromise
> Я не совсем понял что это такое, это когда ошибку обрабатывают внутри экзекьютора Общеания?
Не, это событие https://developer.mozilla.org/en-US/docs/Web/Events/unhandledrejection
У window есть событие error, которое происходит при непойманном исключении. Если в промисе произошло reject и оно не было обработано, то сработает событие unhandledrejection. Можно с его помощью централизованно собирать ошибки. Но проблема конечно в том, что это ловит глобально все ошибки, не позволяя например ловить их только в рамках одного класса. И в ФФ судя по MDN не работает. Обработка ошибок в промисах (по моему личному мнению) сделана неудачно.
Интересная особенность промисов в том, что ты при ошибке не можешь даже выбросить исключение, так как оно снова будет поймано:
var x = getMessages().then(null, function (error) {
// исключение перехватится и будет возвращено внутри промиса x
throw new Error(error);
});
> То есть например, в случае с ajax мы на вход функции onRejected отправляем jqXHR и textStatus.
Если произойдет ошибка, то jQuery вызовет onRejected, верно.
> Насколько я понимаю, они (аргументы функции) появляются в самом коде метода ajax и возвращаются с помощью Promise.reject(jqXHR, textStatus), я правильно понимаю?
Нет, в коде ошибка, в reject информация об ошибке передается одним аргументом-исключением:
reject(new RequestError(textStatus));
> Из чего следует, что подробности об ошибке Обещания нужно искать в самом коде приложения. Это так?
Где обрабатывать ошибку, зависит от того, что ты хочешь делать при ошибке.
> У стандартного ES6 класса Promise нету метода .done().
Это я наверно из PHP взял. Тогда then().
> я хочу на собственом опыте хочу понять в чём разница между приложением с моделью и приложением с ней.
Ок
> в Debian stretch заместо mysql идёт MariaDB.
Так это форк mysql (как и percona), и я думаю, там процентов на 95 тот же самый код.
> мне кажется что такого рода приложения говорят о некомпетенции программиста
Ну я бы не был столь категоричен, в GUI в принципе тоже есть свои преимущества (например, таблицы можно выводить более качественно, особенно большие, прокрутка лучше реализуется). Веб-интерфейс конечно имеет свои недостатки - например, нельзя отменить долго выполняющийся запрос (а в консоли можно через Ctrl + C). Но есть и другие GUI клиенты, и в принципе, если кому-то нравится ими пользоваться, почему бы и нет. Там например можно сохранять часто выполняемые запросы, можно редактировать таблицы визуально и тд.
die(), exit(), может быть return - зависит от того, как твой скрипт написан.
>>1082173
Насчет обработки ошибок - я что-то сам пока не представляю, как лучше сделать. Тут можно использовать разные подходы:
- можно попробовать сделать функции, которые в принципе не возвращают ошибку, а пытаются провести операцию повторно (можно с увеличивающимся интервалом). Только тут надо предусмотреть отмену операции, а то может накопиться много таких "вечных" операций.
- можно попробовать сделать централизованный обработчик, и прикрутить к нему индикатор ошибки в интерфейсе (который будет показывать что есть проблемы со связью, или что сейчас выполняется запрос). Ну например, если у нас есть модуль работы с API то мы можем в нем это и реализовать.
- также, в случае мессенджера можно около сообщения показывать его статус (отпраляется - отправлено - невозможно отправить)
То есть тут надо сначала решить, что мы делаем при ошибках, что делаем с интерфейсом, а только потом проектировать код.
> У меня есть обработка ошибок
Вместо объекта результата jQuery, лучше наверно стандартный промис возвращать.
>>unhandledPromise
> Я не совсем понял что это такое, это когда ошибку обрабатывают внутри экзекьютора Общеания?
Не, это событие https://developer.mozilla.org/en-US/docs/Web/Events/unhandledrejection
У window есть событие error, которое происходит при непойманном исключении. Если в промисе произошло reject и оно не было обработано, то сработает событие unhandledrejection. Можно с его помощью централизованно собирать ошибки. Но проблема конечно в том, что это ловит глобально все ошибки, не позволяя например ловить их только в рамках одного класса. И в ФФ судя по MDN не работает. Обработка ошибок в промисах (по моему личному мнению) сделана неудачно.
Интересная особенность промисов в том, что ты при ошибке не можешь даже выбросить исключение, так как оно снова будет поймано:
var x = getMessages().then(null, function (error) {
// исключение перехватится и будет возвращено внутри промиса x
throw new Error(error);
});
> То есть например, в случае с ajax мы на вход функции onRejected отправляем jqXHR и textStatus.
Если произойдет ошибка, то jQuery вызовет onRejected, верно.
> Насколько я понимаю, они (аргументы функции) появляются в самом коде метода ajax и возвращаются с помощью Promise.reject(jqXHR, textStatus), я правильно понимаю?
Нет, в коде ошибка, в reject информация об ошибке передается одним аргументом-исключением:
reject(new RequestError(textStatus));
> Из чего следует, что подробности об ошибке Обещания нужно искать в самом коде приложения. Это так?
Где обрабатывать ошибку, зависит от того, что ты хочешь делать при ошибке.
> У стандартного ES6 класса Promise нету метода .done().
Это я наверно из PHP взял. Тогда then().
> я хочу на собственом опыте хочу понять в чём разница между приложением с моделью и приложением с ней.
Ок
> в Debian stretch заместо mysql идёт MariaDB.
Так это форк mysql (как и percona), и я думаю, там процентов на 95 тот же самый код.
> мне кажется что такого рода приложения говорят о некомпетенции программиста
Ну я бы не был столь категоричен, в GUI в принципе тоже есть свои преимущества (например, таблицы можно выводить более качественно, особенно большие, прокрутка лучше реализуется). Веб-интерфейс конечно имеет свои недостатки - например, нельзя отменить долго выполняющийся запрос (а в консоли можно через Ctrl + C). Но есть и другие GUI клиенты, и в принципе, если кому-то нравится ими пользоваться, почему бы и нет. Там например можно сохранять часто выполняемые запросы, можно редактировать таблицы визуально и тд.
> Вот: https://ideone.com/XhydTt#stdin. Правильно ли дописал? А то может я неправильно понял. Если правильно, то можно было как-то лучше? Спасибо.
Да, правильно, если надо найти только один товар. Но если может быть несколько товаров с одинаковым именем, то надо возвращать не 1 товар, а массив.
> И что будет если вернется true ? false ?
Функция представляет собой критерий поиска. Она получает на вход 1 товар и должна вернуть:
- true если товар соответствует критерию (это то, что мы ищем)
- false если нет
То есть твой код получает функцию-критерий поиска. Он обходит склад, для каждого товара по очереди вызывает эту функцию и если она вернет true, то добавляет товар в список подходящих под условия.
да, повторяющиеся блоки на разных страницах, например меню или подвал страницы. Пока попробовал через require(). Еще нагуглил метод SSI, но он, как я понял, с php не очень дружит
На кой делать студентов в yii, там по сути хеллоуворлд, описаный в документации фреймворка.
Спасибо за ответ, учёл советы. Ещё помогло распараллеливание (через процессы ОС, без чего-либо хитрого):
php script.php 0 500000 &
php script.php 500000 1000000 &
...
> просто выборка через SELECT ... FROM table без хитрых джойнов и условий?
Увы, да, заслуга предыдущего разработчика, который даже джойны толком не знал и повсюду в коде использовал N + 1. Договорились с заказчиком с нуля переписывать.
>>1081981
Тоже запомню.
https://ideone.com/Rivr5w
последний пример - чистейшая удача окончание а
>> Из чего следует, что подробности об ошибке Обещания нужно искать в самом коде приложения. Это так?
>Где обрабатывать ошибку, зависит от того, что ты хочешь делать при ошибке.
Как вы говорили, мне нужно обработать ошибку дешифровки. Например, может быть передан неправильный passphrase. Изучив код библиотеки я выяснил, что, при дешифровке ключа, метод Key.prototype.decrypt(...) возвращает false, если ключевое слово не подошло.
https://openpgpjs.org/openpgpjs/doc/key.js.html#line389
И после этого, при получении сообщений, я проверяю этот метод перед дешифровкой
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L284
https://github.com/someApprentice/chat/blob/master/public/js/crypter.js#L11-L21
Здесь всё понятно, потому что нету никаких Обещаний.
А вот в сам метод дешифровки завязан на Обещании, и мне до сих пор не понятно как оно работает
Вот его код https://openpgpjs.org/openpgpjs/doc/message.js.html#line95
>return Promise.resolve()...
Означает вернуть выполненное обещание с пустым значением
Зачем делать пустое обещание? И зачем дожидаться его выполнения, если мы уже вернули выполненное обещание, которое должно произойти мгновенно?
>...then(
и когда оно выполниться выполнить функцию, которая
Сначала проверит ключ сессии что это может быть? и если он неверен выбросит ошибку
Затем отфилтрует какие-то пакеты
И если ни одного из них ни найдено вернет false (null?)
Затем возмёт первый попавшейся пакет
И с его помощью асинхронно выполнит рашифровку
https://openpgpjs.org/openpgpjs/doc/packet_symmetrically_encrypted.js.html#line66
https://openpgpjs.org/openpgpjs/doc/packet_sym_encrypted_integrity_protected.js.html#line113
symEncryptedAEADProtected не нашел
Метды выше выполняют какой-то алгоритм дешифровки, выбрасывают исключения если что-то не получилось и опять возвращают выполненное обещание с пустым значением return Promise.resolve(). Причём, когда происходит ошибка не возвращается Promise.reject(new Error(...)). Я не понимаю как это работает.
Вы поэтому упоминули про unhandledRejection? Его нужно где-то повесить?
Если абстрогироваться от всего этого запутанного кода, можно разделить ошибки на:
- передан неправильный шифр сообщения
- передан неправильный ключ
- передана неверная ключивая фраза
- ключ не подходит к данному шифру
var privateKey = '-----BEGIN PGP PRIVATE KEY BLOCK ... END PGP PRIVATE KEY BLOCK-----';
var encrypted = '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----';
// Если ключ неправильный, то вбрасываются ошибки
// https://openpgpjs.org/openpgpjs/doc/key.js.html#line1030
// https://openpgpjs.org/openpgpjs/doc/key.js.html#line1036
privateKey = openpgp.key.readArmored(privateKey).keys[0];
// Если ключевая фраза не подошла, то просто вернётся false
var success = privateKey.decrypt(this.passphrase);
if (success) {
var options = {
// Если шифр неверен, опять же, вбрасываются ошибки
// https://openpgpjs.org/openpgpjs/doc/encoding_armor.js.html#line285
// https://openpgpjs.org/openpgpjs/doc/encoding_armor.js.html#line337
message: openpgp.message.readArmored(encrypted),
privateKey: privateKey
};
// Вешаем unhandledRejection
window.addEventListener("unhandledrejection", function (e) {
console.log(e.reason);
});
// Если ключ не подходит, то ошибка должна произойти где-то здесь и пойматься в unhandledRejection
var promise = openpgp.decrypt(options).then(function(decrypted) {
return decrypted;
});
}
>>>unhandledPromise
>> Я не совсем понял что это такое, это когда ошибку обрабатывают внутри экзекьютора Общеания?
>Не, это событие https://developer.mozilla.org/en-US/docs/Web/Events/unhandledrejection
>
>У window есть событие error, которое происходит при непойманном исключении. Если в промисе произошло reject и оно не было обработано, то сработает событие unhandledrejection. Можно с его помощью централизованно собирать ошибки. Но проблема конечно в том, что это ловит глобально все ошибки, не позволяя например ловить их только в рамках одного класса. И в ФФ судя по MDN не работает. Обработка ошибок в промисах (по моему личному мнению) сделана неудачно.
>
>Интересная особенность промисов в том, что ты при ошибке не можешь даже выбросить исключение, так как оно снова будет поймано:
>
>var x = getMessages().then(null, function (error) {
>// исключение перехватится и будет возвращено внутри промиса x
>throw new Error(error);
>});
>Если в промисе произошло reject и оно не было обработано, то сработает событие unhandledrejection.
Т.е. в случае если не был повешан .then(..., onRejected) или .catch(onRejected)?
Я не понимаю, в коде библиотеки не происходит reject, а просто вбрасываются исключения внутри then(), как будто это синхронный код. Эти ошибки получаются идут в результат обешания. Мне нужно сделать что-то вроде
var promise = openpgp.decrypt(options).then(function(decrypted) {
if (decrypted instanceof Error) {
console.log(decrypted.reason)
} else {
return decrypted;
}
});
?
Надо спросить у авторов библиотеки почему они не делают reject?
>Можно с его помощью централизованно собирать ошибки.
А можно небольшой пример как это делается?
>И в ФФ судя по MDN не работает.
Не совсем понял, что именно не работает?
>> У стандартного ES6 класса Promise нету метода .done().
>Это я наверно из PHP взял. Тогда then().
Тогда обещания выполняться асинхронно и сообщения могут быть в не правильном порядке. Но вашу идею я понял.
>> я хочу на собственом опыте хочу понять в чём разница между приложением с моделью и приложением с ней.
>Ок
Я опечатался. Какой стыд.
разница между приложением с моделью и приложенеем без неё*
>> Из чего следует, что подробности об ошибке Обещания нужно искать в самом коде приложения. Это так?
>Где обрабатывать ошибку, зависит от того, что ты хочешь делать при ошибке.
Как вы говорили, мне нужно обработать ошибку дешифровки. Например, может быть передан неправильный passphrase. Изучив код библиотеки я выяснил, что, при дешифровке ключа, метод Key.prototype.decrypt(...) возвращает false, если ключевое слово не подошло.
https://openpgpjs.org/openpgpjs/doc/key.js.html#line389
И после этого, при получении сообщений, я проверяю этот метод перед дешифровкой
https://github.com/someApprentice/chat/blob/master/public/js/conversation.js#L284
https://github.com/someApprentice/chat/blob/master/public/js/crypter.js#L11-L21
Здесь всё понятно, потому что нету никаких Обещаний.
А вот в сам метод дешифровки завязан на Обещании, и мне до сих пор не понятно как оно работает
Вот его код https://openpgpjs.org/openpgpjs/doc/message.js.html#line95
>return Promise.resolve()...
Означает вернуть выполненное обещание с пустым значением
Зачем делать пустое обещание? И зачем дожидаться его выполнения, если мы уже вернули выполненное обещание, которое должно произойти мгновенно?
>...then(
и когда оно выполниться выполнить функцию, которая
Сначала проверит ключ сессии что это может быть? и если он неверен выбросит ошибку
Затем отфилтрует какие-то пакеты
И если ни одного из них ни найдено вернет false (null?)
Затем возмёт первый попавшейся пакет
И с его помощью асинхронно выполнит рашифровку
https://openpgpjs.org/openpgpjs/doc/packet_symmetrically_encrypted.js.html#line66
https://openpgpjs.org/openpgpjs/doc/packet_sym_encrypted_integrity_protected.js.html#line113
symEncryptedAEADProtected не нашел
Метды выше выполняют какой-то алгоритм дешифровки, выбрасывают исключения если что-то не получилось и опять возвращают выполненное обещание с пустым значением return Promise.resolve(). Причём, когда происходит ошибка не возвращается Promise.reject(new Error(...)). Я не понимаю как это работает.
Вы поэтому упоминули про unhandledRejection? Его нужно где-то повесить?
Если абстрогироваться от всего этого запутанного кода, можно разделить ошибки на:
- передан неправильный шифр сообщения
- передан неправильный ключ
- передана неверная ключивая фраза
- ключ не подходит к данному шифру
var privateKey = '-----BEGIN PGP PRIVATE KEY BLOCK ... END PGP PRIVATE KEY BLOCK-----';
var encrypted = '-----BEGIN PGP MESSAGE ... END PGP MESSAGE-----';
// Если ключ неправильный, то вбрасываются ошибки
// https://openpgpjs.org/openpgpjs/doc/key.js.html#line1030
// https://openpgpjs.org/openpgpjs/doc/key.js.html#line1036
privateKey = openpgp.key.readArmored(privateKey).keys[0];
// Если ключевая фраза не подошла, то просто вернётся false
var success = privateKey.decrypt(this.passphrase);
if (success) {
var options = {
// Если шифр неверен, опять же, вбрасываются ошибки
// https://openpgpjs.org/openpgpjs/doc/encoding_armor.js.html#line285
// https://openpgpjs.org/openpgpjs/doc/encoding_armor.js.html#line337
message: openpgp.message.readArmored(encrypted),
privateKey: privateKey
};
// Вешаем unhandledRejection
window.addEventListener("unhandledrejection", function (e) {
console.log(e.reason);
});
// Если ключ не подходит, то ошибка должна произойти где-то здесь и пойматься в unhandledRejection
var promise = openpgp.decrypt(options).then(function(decrypted) {
return decrypted;
});
}
>>>unhandledPromise
>> Я не совсем понял что это такое, это когда ошибку обрабатывают внутри экзекьютора Общеания?
>Не, это событие https://developer.mozilla.org/en-US/docs/Web/Events/unhandledrejection
>
>У window есть событие error, которое происходит при непойманном исключении. Если в промисе произошло reject и оно не было обработано, то сработает событие unhandledrejection. Можно с его помощью централизованно собирать ошибки. Но проблема конечно в том, что это ловит глобально все ошибки, не позволяя например ловить их только в рамках одного класса. И в ФФ судя по MDN не работает. Обработка ошибок в промисах (по моему личному мнению) сделана неудачно.
>
>Интересная особенность промисов в том, что ты при ошибке не можешь даже выбросить исключение, так как оно снова будет поймано:
>
>var x = getMessages().then(null, function (error) {
>// исключение перехватится и будет возвращено внутри промиса x
>throw new Error(error);
>});
>Если в промисе произошло reject и оно не было обработано, то сработает событие unhandledrejection.
Т.е. в случае если не был повешан .then(..., onRejected) или .catch(onRejected)?
Я не понимаю, в коде библиотеки не происходит reject, а просто вбрасываются исключения внутри then(), как будто это синхронный код. Эти ошибки получаются идут в результат обешания. Мне нужно сделать что-то вроде
var promise = openpgp.decrypt(options).then(function(decrypted) {
if (decrypted instanceof Error) {
console.log(decrypted.reason)
} else {
return decrypted;
}
});
?
Надо спросить у авторов библиотеки почему они не делают reject?
>Можно с его помощью централизованно собирать ошибки.
А можно небольшой пример как это делается?
>И в ФФ судя по MDN не работает.
Не совсем понял, что именно не работает?
>> У стандартного ES6 класса Promise нету метода .done().
>Это я наверно из PHP взял. Тогда then().
Тогда обещания выполняться асинхронно и сообщения могут быть в не правильном порядке. Но вашу идею я понял.
>> я хочу на собственом опыте хочу понять в чём разница между приложением с моделью и приложением с ней.
>Ок
Я опечатался. Какой стыд.
разница между приложением с моделью и приложенеем без неё*
>> Насколько я понимаю, они (аргументы функции) появляются в самом коде метода ajax и возвращаются с помощью Promise.reject(jqXHR, textStatus), я правильно понимаю?
>Нет, в коде ошибка, в reject информация об ошибке передается одним аргументом-исключением:
>
>reject(new RequestError(textStatus));
Но где вызывается сам reject() тогда? Мне почему-то кажеться, что, обычно, где-то по среди кода возвращается Promise.reject(...), это не так?
>> Из чего следует, что подробности об ошибке Обещания нужно искать в самом коде приложения. Это так?
>Где обрабатывать ошибку, зависит от того, что ты хочешь делать при ошибке.
Кхм, неправильно понял ваш намёк сначала.
В предыдущем посте я выяснил какие ошибки могут произойти:
>>1083110
>- передана неверная ключивая фраза
В этом случае нужно просто предложить заного ввести ключевую фразу заного. Что я уже сделал.
>- передан неправильный шифр сообщения
>- передан неправильный ключ
>- ключ не подходит к данному шифру
А вот эти ошибки уже говорят о серьёзной ошибке в приложении - передаются неверные данные. Нужно для пользователя вывести ошибку и в консоль вывести её подробности. В идеале отправить эту ошибку на сервер, с разрешения пользователя.
В принципе, стандартная процедура. Для меня сначала нужно понять как именно обработать эти ошибки.
>1) Дан список категорий товаров в виде такого массива:
>$categories = [
>// id, название, parentId, кол-во товаров
>[1, 'Бытовая техника', null, 0],
>[2, 'Телевизоры', 1, 0],
>[3, 'LCD-телевизоры', 2, 20],
>[4, 'Телевизоры с газоразрядным дисплеем', 16],
>[5, 'Стиральные машины', 1, 0],
>[6, 'Холодильники', 1, 0],
>...
>];
>Для каждого товара указан уникальный id категории, >название, id родительской категории или null, если ее >нет, количество товаров в этой категории без учета >категорий-детей. Используя эти данные:
>а) Напиши функцию, которая для любого переданной >id категории вернет массив, содержащий id этой >категории и всех ее предков, начиная от корня >дерева.
>Например, для категории 3 вернет массив [1, 2, 3] >(Бытовая техника -> Телевизоры -> LCD-телевизоры). А >для 1 - массив [1].
>б) Напиши функцию, которая для любой категории >вернет массив id ее потомков. Например для id = 2 >функция должна вернуть массив [3, 4]
>в) Напиши функцию, которая вернет массив >категорий-сестер (то есть категорий, имеющих того >же родителя). Для id = 2 функция должна вернуть >массив [5, 6]
>г) Напиши функцию, которая выведет список >категорий в виде дерева "лесенкой", с указанием >числа товаров с учетом дочерних категорий:
>Бытовая техника (36)
>- Телевизоры (36)
>-- LCD-телевизоры (20)
>-- Телевизоры с газоразрядным дисплеем (16)
>Стиральные машины
>Холодильники
Что-то у меня совсем не получается. М. б. кто-нибудь намекнет как такое решать.
>1) Дан список категорий товаров в виде такого массива:
>$categories = [
>// id, название, parentId, кол-во товаров
>[1, 'Бытовая техника', null, 0],
>[2, 'Телевизоры', 1, 0],
>[3, 'LCD-телевизоры', 2, 20],
>[4, 'Телевизоры с газоразрядным дисплеем', 16],
>[5, 'Стиральные машины', 1, 0],
>[6, 'Холодильники', 1, 0],
>...
>];
>Для каждого товара указан уникальный id категории, >название, id родительской категории или null, если ее >нет, количество товаров в этой категории без учета >категорий-детей. Используя эти данные:
>а) Напиши функцию, которая для любого переданной >id категории вернет массив, содержащий id этой >категории и всех ее предков, начиная от корня >дерева.
>Например, для категории 3 вернет массив [1, 2, 3] >(Бытовая техника -> Телевизоры -> LCD-телевизоры). А >для 1 - массив [1].
>б) Напиши функцию, которая для любой категории >вернет массив id ее потомков. Например для id = 2 >функция должна вернуть массив [3, 4]
>в) Напиши функцию, которая вернет массив >категорий-сестер (то есть категорий, имеющих того >же родителя). Для id = 2 функция должна вернуть >массив [5, 6]
>г) Напиши функцию, которая выведет список >категорий в виде дерева "лесенкой", с указанием >числа товаров с учетом дочерних категорий:
>Бытовая техника (36)
>- Телевизоры (36)
>-- LCD-телевизоры (20)
>-- Телевизоры с газоразрядным дисплеем (16)
>Стиральные машины
>Холодильники
Что-то у меня совсем не получается. М. б. кто-нибудь намекнет как такое решать.
>>1083067
Ответ в новом треде >>1085261
>>1083110
Ответ в новом треде.
Это копия, сохраненная 5 ноября 2017 года.
Скачать тред: только с превью, с превью и прикрепленными файлами.
Второй вариант может долго скачиваться. Файлы будут только в живых или недавно утонувших тредах. Подробнее
Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.