Этого треда уже нет.
Это копия, сохраненная 1 декабря 2015 года.

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

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
33 Кб, 500x500
157 Кб, 1024x683
187 Кб, 853x480
135 Кб, 1280x720
Клуб изучающих PHP 62 #569049 В конец треда | Веб
Добро пожаловать в наш уютный тредик. Тут мы изучаем язык PHP (а также JS/CSS/HTML/SQL), решаем задачки и даже делаем простые сайты! Зачем? Кто-то хочет научиться программировать, кто-то - делать сайты, кто-то - просто размять мозги и заняться чем-то полезным.

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

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

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

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

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

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

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

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

Учебник дает основы языка PHP, но чтобы делать сайты, этого недостаточно. Если ты его прошел, то надо переходить в более серьезным задачкам, которые научат тебя как выдавать страницы в браузер, работе с таблицами в БД, работе с формами, MVC.

- Простая, но полезная задача сделать список студентов: https://github.com/codedokode/pasta/blob/master/student-list.md
- Более сложная задача сделать файлообменник на микрофреймворке Slim: https://gist.github.com/codedokode/9424217
- Еще более сложная и долгая задача на Yii/Yii2: https://gist.github.com/codedokode/8733007
- После нее можно изучать автоматизированное тестирование
- Если ты все решил, переходи к Symfony 2/Doctrine 2

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

https://gist.github.com/codedokode/10774100
https://gist.github.com/codedokode/7054af4a03865c4cc863

Может тебе понадобится пользоваться командной строкой, вот гайд https://gist.github.com/codedokode/10539568

Вот небольшой туториал по тому как начать использовать PHP на сервере для отдачи странички в браузер: https://php.net/manual/ru/tutorial.php Увы, уроков плавно подводящих к тому, как сделать задачи выше, пока нет, так что если что, задавай вопросы.

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

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

- HTML/CSS: https://gist.github.com/codedokode/58ebc90bd006baf4b35c
- JS: https://gist.github.com/codedokode/ce30e7a036f18f416ae0
- Проверялка решений на JS: http://dkab.github.io/jasmine-tests/
- MySQL: https://gist.github.com/codedokode/10539213

Что почитать

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

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

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

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

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

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

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

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

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

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

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

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

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

Объясняй

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

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

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

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

Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
56 Кб, 500x644
193 Кб, 1024x768
Самый важный пост #2 #569053
Еще. Код нужно писать не как попало, а аккуратно и по правилам. Почему? Потому, что на неакуратно написанный код не хочется даже смотреть.

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

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

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

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

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

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

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

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

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

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

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

Объясняй

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

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

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

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

Ах да. Если тебе кажется, что что-то в учебнике или задачах можно сделать лучше — пиши, обратная связь всегда очень полезна.
#3 #569054
Вроде бы я всем ответил в предыдущем треде >>558058 (OP) . Самое время зайти и прочесть ответ. Если кому-то не ответил, напомните о себе.

А я напомню составить задачку на написание клиентского приложения на JS и может быть, на командную строку в Линуксе.
#4 #569091
Кто-то работал с CMS SIMPLA? Такая проблема, добавил дополнительные поля в админке в месте вывода одного заказа, для этого изменил файлы которые добавляют значения в базу данных а также создал поля в нужных таблицах. Но теперь есть одна проблема, при обновлении товара (нажатие кнопки сохранить) данные которые я ввёл не сохраняются в базе данных. Для того что бы они сохранялись я так понимаю надо отредактировать запрос UPDATE в каком-то файле OrderAdmin, api/order.php и т.д. Не могу найти где это сделать.
sage #5 #569144
>>569053

>4 пробела заместо таба


сага скрыл
#6 #569163
Я все по поводу http://ideone.com/bx56X9

Так и не понял как мне поможет простая замена echo на return
#7 #569214
>>569054
ОП, я поустранял замечания.
https://github.com/never3ver/catsandmice
134 Кб, 797x740
#8 #569251
Как обычно у меня долго грузился ideone, но в этот раз он стер у меня все задачи из оп учебника, включая кошек мышек которые я решаю почти уже месяц. Жизньболь.
156 Кб, 836x738
#9 #569252
>>569251
А нет, отлагало.
#10 #569259
>>569252

Хороший повод сохранить все в текстовые файлы пока не поздно.
#11 #569272
ОП или кто-то еще, посмотрите задание по списку студентов, только начал пробовать ООП - https://github.com/lexdss/abitur
Правда я сортировку по столбцам еще не сделала там. Но все же.
#12 #569335
Снова вкатываюсь со своим палиндромом. Теперь вроде доделал, учёл ошибки. Буду рад разочароваться

http://ideone.com/lF688L
#13 #569386
>>569091

>SIMPLA


Eat PASTA - run FASTA.
#14 #569392
>>569335
Норм. Но в твоём случае можно вместо elseif ($tx != $xt) писать просто else. Зачем лишний раз проверять условие?

notOP
#15 #569458
>>569091
Ну это ведь очевидно, что если ты вносишь изменения в View в виде дополнительных полей, то тебе надо внести изменения и в контроллер, который будет работать с данными из этих полей, и изменить запрос в модели которая работает с товарами.
#16 #569485
>>568986

>По поводу использования одного хеша с многими ключами (page:visits:unique) против хранения отдельных ключей (visit:{IP}:{id})


Да, про масштабируемость не подумал.
Ну и у меня уже подсознательная тяга к инкапсуляции (положить все в один хеш, а не держать миллионы несвязанных ключей) и реляционности.
И был вопрос о выборке необходимых ключей, я тогда знал только команду KEYS, которая перебирает все ключи, поэтому непродуктивна.
Кажется, там еще есть команда SCAN, но я пока не понимаю, как она работает.
http://redis.io/commands/keys

>Don't use KEYS in your regular application code. If you're looking for a way to find keys in a subset of your keyspace, consider using SCAN or sets


http://redis.io/commands/scan

>SCAN is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call.


Что за "cursor"? О каком итераторе они говорят? Это какой-то алгоритм? яннп
Ну хорошо, я согласен что нужно хранить отдельные ключи вместо хеша, только не понимаю как по ним искать нужные.

>в чем проблема накопления одинаковых id в очереди?


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

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


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

>редис не гарантирует что все команды в транзакции будут выполнены. Это совсем не то же что транзакции в MySQL например.


Этого тоже не знал, я думал транзакция = acid.

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


Думал об этом, но отказался по соображениям: если "суммировать и группировать" на стороне редиса, то я пока просто не знаю как это сделать; если на стороне php, то нам понадобится выгрести из редиса все пары ip:id, не много ли памяти это займет? Если каждый ключ допустим в среднем 30 байт, то десять миллионов посещений в сутки даст почти 300 мб.
А, ну да, можно же выгребать это по частям, все время забываю.

>- в каком порядке коммитим mysql/redis?


Сначала mysql конечно. Он же пишет на диск. Redis пишет в оперативную память, это пара милисекунд. Да, у нас остается точка отказа между этими двумя коммитами, но во-первых это промежуток наверное меньше милисекунды, во-вторых я просто не знаю, что тут можно сделать.

Ну хорошо, значит упрощаем алгоритм.
При просмотре страницы:
Если ключ ip:id существует, то конец. Иначе создаем такой ключ, и добавляем его в очередь.

Скрипт по расписанию:
1. Берет длину очереди (LLEN), фиксирует это значение в переменную. Так что нас не беспокоит, что в конец очереди будут продолжать добавляться записи, мы будем работать только с этими N записей из головы очереди.
2. Запрашиваем порциями данные из редиса (без удаления их из очереди), пока не достигнем этой суммы N.
2.1. Парсим каждую строку вида "ip:id", чтобы получить ip и id, сохраняем в некий массив вида ['id страницы'=>кол-во посещений,].
2.2. Получаем минимальное и максимальное значение этого массива. Затем в цикле ходим от min до max, осуществляя поиск ключей для каждого такого значения.
В этом поможет функция array_keys со вторым параметром. В конце этого шага получаем массив вида ['кол-во посещений'=>array('все id страниц с таким кол-вом посещений')].
2.3. Ходим в цикле и для каждого ключа массива, упомянутого выше, подставляем массив айдишников в запрос:
UPDATE tbl_name SET visit_counter = visit_counter + delta WHERE id IN (implode($arr, ',')).
2.4. Коммитим mysql, затем удаляем обработанное кол-во записей из начала очереди.

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

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

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


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

Ну ладно, пошел читать матчасть.
#16 #569485
>>568986

>По поводу использования одного хеша с многими ключами (page:visits:unique) против хранения отдельных ключей (visit:{IP}:{id})


Да, про масштабируемость не подумал.
Ну и у меня уже подсознательная тяга к инкапсуляции (положить все в один хеш, а не держать миллионы несвязанных ключей) и реляционности.
И был вопрос о выборке необходимых ключей, я тогда знал только команду KEYS, которая перебирает все ключи, поэтому непродуктивна.
Кажется, там еще есть команда SCAN, но я пока не понимаю, как она работает.
http://redis.io/commands/keys

>Don't use KEYS in your regular application code. If you're looking for a way to find keys in a subset of your keyspace, consider using SCAN or sets


http://redis.io/commands/scan

>SCAN is a cursor based iterator. This means that at every call of the command, the server returns an updated cursor that the user needs to use as the cursor argument in the next call.


Что за "cursor"? О каком итераторе они говорят? Это какой-то алгоритм? яннп
Ну хорошо, я согласен что нужно хранить отдельные ключи вместо хеша, только не понимаю как по ним искать нужные.

>в чем проблема накопления одинаковых id в очереди?


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

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


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

>редис не гарантирует что все команды в транзакции будут выполнены. Это совсем не то же что транзакции в MySQL например.


Этого тоже не знал, я думал транзакция = acid.

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


Думал об этом, но отказался по соображениям: если "суммировать и группировать" на стороне редиса, то я пока просто не знаю как это сделать; если на стороне php, то нам понадобится выгрести из редиса все пары ip:id, не много ли памяти это займет? Если каждый ключ допустим в среднем 30 байт, то десять миллионов посещений в сутки даст почти 300 мб.
А, ну да, можно же выгребать это по частям, все время забываю.

>- в каком порядке коммитим mysql/redis?


Сначала mysql конечно. Он же пишет на диск. Redis пишет в оперативную память, это пара милисекунд. Да, у нас остается точка отказа между этими двумя коммитами, но во-первых это промежуток наверное меньше милисекунды, во-вторых я просто не знаю, что тут можно сделать.

Ну хорошо, значит упрощаем алгоритм.
При просмотре страницы:
Если ключ ip:id существует, то конец. Иначе создаем такой ключ, и добавляем его в очередь.

Скрипт по расписанию:
1. Берет длину очереди (LLEN), фиксирует это значение в переменную. Так что нас не беспокоит, что в конец очереди будут продолжать добавляться записи, мы будем работать только с этими N записей из головы очереди.
2. Запрашиваем порциями данные из редиса (без удаления их из очереди), пока не достигнем этой суммы N.
2.1. Парсим каждую строку вида "ip:id", чтобы получить ip и id, сохраняем в некий массив вида ['id страницы'=>кол-во посещений,].
2.2. Получаем минимальное и максимальное значение этого массива. Затем в цикле ходим от min до max, осуществляя поиск ключей для каждого такого значения.
В этом поможет функция array_keys со вторым параметром. В конце этого шага получаем массив вида ['кол-во посещений'=>array('все id страниц с таким кол-вом посещений')].
2.3. Ходим в цикле и для каждого ключа массива, упомянутого выше, подставляем массив айдишников в запрос:
UPDATE tbl_name SET visit_counter = visit_counter + delta WHERE id IN (implode($arr, ',')).
2.4. Коммитим mysql, затем удаляем обработанное кол-во записей из начала очереди.

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

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

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


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

Ну ладно, пошел читать матчасть.
#17 #569641
>>569019

>не должна передавать лишние аргументы внутренней функции: partialAny(fn, 1, undefined, 3, undefined)(2) -> [1, 2, 3, undefined]



Я так понял partialAny(fn, 1, undefined, 3, undefined)(2) -> [1, 2, 3, undefined] вот так и не должно происходить? Что-то если честно не могу додуматься куда деть этот второй массив аргументов. Ковырял отладчик, не особо помогло, дай подсказочку :3
#18 #569667
>>568993

>главное что нужно, это понимание принципов нормализации (именно понимание, а не заучивание определений)


А понимание откуда берется? Нужно нащупать определенную точку в толстой кишке, и оно включится? Или благодаря практическому опыту?
У тебя как всегда неадекватно сложные задачи. Мне так почему-то кажется, что проектировали itunes и google play люди с немного большим опытом, чем у меня, и потратили чуть больше чем полчаса.

Я не знаю, как это решить.
Например, как хранить ссылку на исполнителя трека? Исполнителем может быть либо группа, либо сольный артист (который может одновременно принадлежать к одной группе, а может даже и не одной). Если я сделаю две таблицы, для групп и для артистов, то я не смогу у трека выставить внешний ключ одновременно на две таблицы. Или создать два ключа? Тогда половина значений будет null, тоже некрасиво.
Можно создать таблицу исполнителей, где будут и группы, и артисты. Внешние ключи хранить в таблице групп и артистов на эту таблицу. Как например советуют здесь http://stackoverflow.com/questions/2002985/mysql-conditional-foreign-key-constraints
Скажем так

artist
- id
- name
...
- performer_id
foreign key (performer_id) references performer (id)

ensemble
- id
...
- performer_id
foreign key (performer_id) references performer (id)

performer
- id
- type (enum: artist, ensemble)

Но тогда я не представляю, как получить информацию по исполнителю.
Дай хоть слова, по которым гуглить.
#18 #569667
>>568993

>главное что нужно, это понимание принципов нормализации (именно понимание, а не заучивание определений)


А понимание откуда берется? Нужно нащупать определенную точку в толстой кишке, и оно включится? Или благодаря практическому опыту?
У тебя как всегда неадекватно сложные задачи. Мне так почему-то кажется, что проектировали itunes и google play люди с немного большим опытом, чем у меня, и потратили чуть больше чем полчаса.

Я не знаю, как это решить.
Например, как хранить ссылку на исполнителя трека? Исполнителем может быть либо группа, либо сольный артист (который может одновременно принадлежать к одной группе, а может даже и не одной). Если я сделаю две таблицы, для групп и для артистов, то я не смогу у трека выставить внешний ключ одновременно на две таблицы. Или создать два ключа? Тогда половина значений будет null, тоже некрасиво.
Можно создать таблицу исполнителей, где будут и группы, и артисты. Внешние ключи хранить в таблице групп и артистов на эту таблицу. Как например советуют здесь http://stackoverflow.com/questions/2002985/mysql-conditional-foreign-key-constraints
Скажем так

artist
- id
- name
...
- performer_id
foreign key (performer_id) references performer (id)

ensemble
- id
...
- performer_id
foreign key (performer_id) references performer (id)

performer
- id
- type (enum: artist, ensemble)

Но тогда я не представляю, как получить информацию по исполнителю.
Дай хоть слова, по которым гуглить.
#19 #569676
Задача 12 по JS на ООП.
https://ideone.com/u5hpTU

Сделал все функции, кроме проверки на ошибки. Это нужно делать через try..catch? Там получается каждый метод в него нужно будет оборачивать?
#20 #569750
>>569667
Госпади, да что ты его задачки читаешь вообще, он же шизик? Он хорош только советы давать по уже готовым проектам, которые ты сам реализовал и выложил. Возьми фреймворк и пиши нормальный стандартный интернет магазин по продаже хуйни, коих тысячи в сети. Не забудь админку. Все это уже будет твоя наработка, с которой можно пиздовать во фриланс и на ее основе штамповать бабершопы.
#21 #569771
Знаю ПХП и Яваскрипт, но не умею верстать. То есть ХТМЛ и КСС конечно немного знаю, но верстать толком не умею, по работе необходимо уметь адаптивно верстать, подскажите где лучше подучиться в интернете всему этому. Интересуют самые последние технологии в этом направлении, и как много это может занять времени?
#22 #569831
мда, после прочтения книги на свой файлообменник без боли не могу смотреть. но переписывать все с нуля уже лень.
#23 #569838
>>569831
Какой книги?
someApprentice #25 #570096
>>569006

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


>Хорошо, давай подойдем с другой стороны. Допустим кошка стоит выше мышки на 5 клеток. Сколько ей надо ходов чтобы добраться до нее (при условии что мышка стоит на месте)?


>


>А если мы сместим мышку право на 1 клетку? На 2? На 5? на 10?


Предлагаешь что ли отдельно считать расстояние по X и по Y?

>> Еще я не понимаю, почему плохо использовать декартово расстояние:


>В общем это не плохо но число ходов даст более точное значение. Ведь мир искажен, кошка по диагонали делает ход, проходя 1.44 клеточки (корень из 2).


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

Я совершенно не понимаю эту задачу.
someApprentice #26 #570135
>>569163

>Так и не понял как мне поможет простая замена echo на return


Пользоваться echo считается дурным тоном в программировании. Им в большинстве случаев пользуются только чтобы искать ошибки в коде.

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

function getName($name) {
return $name;
}

$var = getName('Bill');

Если ты будешь использовать здесь echo за место return, то значение $var не измениться.

Так же не забывай что использование return останавливает работу функции.

Пишу с дивана.
#27 #570229
>>569750
Не правда, ОП успешный человек и занимается самым благородным и чистым делом - его уроки помогли уже многим анонам устроиться на работу, в том числе и мне. ОП своими силами расширяет границы достоинства всех людей занимаясь этим. Он великий.
#28 #570252
>>570229
Ты давай лучше вместо того чтобы вылизывать опу очко, расскажи о работе, интересно же чем занимаются на практике.
Какие технологии, проекты какой сложности, какие темпы?
#29 #570273
>>570252
Если ты хочешь оказаться правым, то не меняй тему спора. Что ты можешь противопоставить ОПу из моего поста выше?
#30 #570280
>>568993
Сделал пока только часть задания (оно слишком большое).

Учитывая то, что исполнителем и автором трека может быть как группа, так и сольный артист, сделал одну общую таблицу, на которую будет ссылаться трек (author_id, performer_id). Для групп и артистов две отдельные таблицы, так как у них могут быть разные свойства, внешний ключ на таблицу исполнителей. На самом деле мелькала мысль сделать по принципу eav, но мне кажется это большим усложнением в данном случае.

performer
- id
- type (enum: artist, ensemble)

artist
- id
- name
- surname
- birth_year
- ensemble_id (fk, null если сольная карьера)
- performer_id (fk)

ensemble
- id
- name
- foundation_year
- performer_id (fk)

track
- id
- title
- short_description
- full_description
- release_date
- category_id (fk)
- type (enum: single, remake, remix, cover)

track_performer
- track_id
- performer_id (fk)

track_author
- track_id (pk, fk)
- author_id (pk, fk)

genre
- id
- name

track_genre
- track_id (pk, fk)
- genre_id (pk, fk)

album
- id
- short_description
- full_description
- release_date
- type (enum: album, tribute, remix, remake, collection)
- author_id (может быть null)

album_track
- album_id (pk, fk)
- track_id (pk, fk)

label
- id
- name

category
- id
- title
- label_id (fk)

price
- country_id (pk, fk)
- category_id (pk, fk)
- available (enum: y, n)
- base_price
- royalties

Не сделал пока подписки, продажи, отчеты, и что там еще требуется.
#30 #570280
>>568993
Сделал пока только часть задания (оно слишком большое).

Учитывая то, что исполнителем и автором трека может быть как группа, так и сольный артист, сделал одну общую таблицу, на которую будет ссылаться трек (author_id, performer_id). Для групп и артистов две отдельные таблицы, так как у них могут быть разные свойства, внешний ключ на таблицу исполнителей. На самом деле мелькала мысль сделать по принципу eav, но мне кажется это большим усложнением в данном случае.

performer
- id
- type (enum: artist, ensemble)

artist
- id
- name
- surname
- birth_year
- ensemble_id (fk, null если сольная карьера)
- performer_id (fk)

ensemble
- id
- name
- foundation_year
- performer_id (fk)

track
- id
- title
- short_description
- full_description
- release_date
- category_id (fk)
- type (enum: single, remake, remix, cover)

track_performer
- track_id
- performer_id (fk)

track_author
- track_id (pk, fk)
- author_id (pk, fk)

genre
- id
- name

track_genre
- track_id (pk, fk)
- genre_id (pk, fk)

album
- id
- short_description
- full_description
- release_date
- type (enum: album, tribute, remix, remake, collection)
- author_id (может быть null)

album_track
- album_id (pk, fk)
- track_id (pk, fk)

label
- id
- name

category
- id
- title
- label_id (fk)

price
- country_id (pk, fk)
- category_id (pk, fk)
- available (enum: y, n)
- base_price
- royalties

Не сделал пока подписки, продажи, отчеты, и что там еще требуется.
#31 #570286
>>570273
Какого спора, поехавший? Я спросил, чем занимается твоя конторка, интересно же чем занимаются люди на практике.
В твоем посте жополизство, зачем мне ему что-то противопоставлять.
#32 #570290
>>570286

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


А, значит ты безработный, но при этом хуесосишь ОП-а который многим помог найти работу и рассуждаешь как правильно?
Кекнул с тебя.
другой анон если что
#33 #570306
>>570290
Ты идиот что ли?
#35 #570319
Так и не пойму, SASS и LESS компилятся один раз или для каждого вызова страницы?
#36 #570326
>>570310
Может быть глумиться над больными людьми и плохо, но это все-таки смешно.

На что ответить, дурачок?
Вот мой пост, где я выражаю недовольство слишком сложным уровнем оповских задач.
>>569667
Мне зачем-то подпездывает быдлокодер и советует писать говнокод. >>569750
Ты наверное решил, что это мой пост, возбудился и зачем-то начал рассказывать ему том, как оп кому-то помог устроиться на работу.
Я тебя в этом посте >>570252 попросил не лизать опу очко, а рассказать о работе. Я скоро тоже планирую устраиваться, поэтому интересно, какую нагрузку дают на джуниоров.

Так вот, ты сумасшедший или просто дурак?
#37 #570374
>>568993

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


Вот это вообще не понял.
Что за отчисления для бесплатного прослушивания? Это значит, что наш интернет-магазин обязан платить пеню правообладателям даже за те немногие бесплатные прослушивания, которые разрешены? Безобразие. Копирасты не люди, форсим тор вконтакте, чтобы простые люди могли пользоваться рутрекером.
#38 #570440
>>570426
У тебя всю жизнь все будет плохо и подохнешь ты как собака.
#39 #570442
>>570440
что там было?
2484 Кб, 600x338
#40 #570451
Все привет и няше опыт отдельный.

Я тут студент пак от гитхаба получил, думаю себе сайт-резюме заделать, посоветуйте чего туда напихать. Стоит ли вообще делать?
Может ещё кто годных примеров накидает.
#41 #570454
>>570451
Переведите кто-нибудь.
#42 #570464
>>570454
All greetings and nyashe experience separate.

I've been a student pack from githaba received, I think the site itself resumes repaired, advise what to cram. Whether it is worth doing?
Maybe someone suitable examples promptly inserted.
#43 #570465
>>569252
Дай, пожалуйста, ссылку на задачи.
#44 #570470
>>570451
Открываешь любой фриланс сайт->смотришь заказы на сайты -> ищешь идею которая тебе понравится
#45 #570475
>>569771
Если для себя то возьми например какой нибудь любой сайт, заскринь главную, в html набросай сайт без функционала, просто чтобы элементы те же самые были, и попробуй добиться схожести своего сайта с тем что на скрине.
Если бы я снова учился верстать - я бы поступил так.
50 Кб, 1366x768
Константы #46 #570521
Когда и как стоит использовать константы в классах?
Вот, есть у меня класс с методом, в котором используются константные данные, но только в одном методе. Надо ли их объявлять, как константу класса? Или же достаточно описать просто, как переменную в конкретном методе?
#47 #570655
мля, месяц не брался за файлообменник, помню я что-то там ковырял следуя ахуенно мудрым советам опа, в итоге вообще все поломалось, файлы не инсертятся, и я даже хуй знает почему. весь коннект с дб есть слим работает, все файлы не вставляются.
#48 #570700
>>569838
вот той из шапки.
#49 #570707
>>570252
По моим ощущениям он работает преподом. Дело в том, что его задачки лишены практической ценности, такое ощущение, что любые задания и правки, которые он делают, имеют единственную цель - потянуть время, чтобы человек сидел и десятилетиями копался в переусложненных вещах. Как раз по такой методике обучают школьников и студентах в наших шарагах, чтобы они пришли и тупо отсидели учебные часы, занимаясь херней.
Возможно чисто теоритически это все полезно, но мы-то уже не школота, у наст столько времени в запасе нет, нам нужно скорее в практику, а конекретно в веб.
#50 #570709
>>570326
при чем тут быдлокодер? я тебе дал практический совет, в какую сторону копать, такие задачи мне давали аж два раза в сети.
56 Кб, 654x500
#51 #570788
>>570709
Ну не обижайся, мелкобуквенный, но

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


это уже другая крайность. Тебе интересна такая работа, штамповать посредственные сайты за маленькие деньги?
Мне точно нет, я хочу гордиться своей работой. Я с прошлой работы ушел, когда меня пытались заставить дописывать гнилой порно-сайт.
И стандартные магазины пишутся не на фреймворках, а на cms типа opencart, собственно там писать нечего, нужно только натянуть верстку.
>>570707
Есть в них ценность, только нужно как-то рассчитывать уровень сложности.

Что-то я жалею, что ввязался во флуд. По моим ощущениям, вы тут ни хера не делаете, только обсуждаете опа или жалуетесь на злую судьбу.
Не понимаю, что я вообще среди вас делаю. (Пикрандом)
#52 #570789
>>570788

>за маленькие деньги?


А ты думал тебя сразу в гугол позовут? Тех, кого в гугол зовут, на сосаче кодить не учатся. Будешь чистить говно на вордпрессе с жумолой и радоваться. Всем бабершопы нужны, просто так говорю, а уж на филигранность твоего кода всем строго похуй.
#53 #570790
Кстати. когда куки проставляешь в слиме, то незарегенным пользователям одинаковые юзернейм ставить или генерировать уникальный токеном, как и куки?
#54 #570792
>>570788

>Я с прошлой работы ушел, когда меня пытались заставить дописывать гнилой порно-сайт.


вот дурачок, классная работа, пишешь, а в перервыха дрочишь, тьфу на тебя.
оффтоп #55 #570793
Как поставить nginx и PostgreSQL на ubuntu 15.04?
Есть ли анонасы, у которых такая смесь работает именно на этой версии бубунты? Как вы добились профита?
#57 #570814
>>568993
Тот же вопрос касательно покупки альбомов и треков.
Альбомы и треки хранятся в отдельных таблицах. Как мне сделать таблицу покупок, чтобы внешний ключ в ней указывал на две таблицы? Очевидно никак, но что делать? Создать доп.таблицу "товар" и ссылаться на нее из таблиц альбомов и треков?
Мне не очень нравится такой подход с точки зрения размера полученной таблицы. Наверняка есть даже какие-то паттерны на эту тему, но я не знаю в каком направлении гуглить.
#58 #570842
Оп, что можешь сказать про laravel?
#59 #570845
Не нашел отдельного Wordpress треда, пишу здесь.
Недавно поднял бложик на Wordpress.
Год назад я написал на three.js один проект и теперь хочу разместить его на своем бложике. Проект представляет собой каталог с кучей файлов; есть один, типа main.html Там намешано куча всякого javascript, в каталоге лежат ещё картинки, файлы моделей и т.д. Как мне это разместить на моем Wordpress? Хочу разместить целиком всю папку. Ещё желательно, чтобы в админке оно было доступно. FTP-доступ есть.
#60 #570847
>>570845
Это в /web
#61 #570856
Анончики, много дел, еле время нашел.

>>569091

Simpla я помню, когда-то давно его еще пиарил автор на Хабре и он стоил 500 долларов. Я на нем делал какой-то интернет магазин. Я еще удивлялся, что там автор все классы как-то странно от одного общего наследует, своеобразное понимание ООП, но интерфейс приятный.

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

Алсо патчить код это глупая идея, лучше бы посмотреть нет ли в CMS средств расширения и сделать все это в виде какого-то плагина. Иначе нельзя ни обновить движок, ни понять где чей код. Я попробовал посмотреть, но на сайте автора нет ссылки на документацию - где искать информацию, непонятно. А код скачивать (скачивать! в 2015 году) и распаковывать мне некогда.

>>569163

>Так и не понял как мне поможет простая замена echo на return


Я и не давал таких советов. Я написал что надо в функции создать массив и класть в него все сгенерированные слова (включая сгенерированные вложенными вызовами функции), а в конце функции возвращать.
https://github.com/never3ver/catsandmice/ #62 #570857
>>569214

> https://github.com/never3ver/catsandmice/blob/master/animals.php


В этом файле код плохой (с копипастой, все одной простыней без разбиения на функции, с логическими ошибками). К примеру:

> https://github.com/never3ver/catsandmice/blob/master/animals.php#L16


> $world->addAnimal(new Mouse(rand(0, $world->getWidth()), rand(0, $world->getHeight())));


Нет гарантий что клетка свободна

> https://github.com/never3ver/catsandmice/blob/master/animals.php#L10


> $tempX = rand(0, $world->getWidth());


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

Ну и код читается тяжело. Вот как можно было написать:

функция добавитьЖивотное(карта, животное) {
попытаться 10 раз {
сгенерировать координаты животного;
если (карта говорит что клеткаCвободна()) {
на карту поместитьЖивотное();
выйти;
}
}

выдать ошибку;
}

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

> https://github.com/never3ver/catsandmice/blob/master/animals.php#L30


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

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php


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

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L43


Тут нет проверки что $key не пуст и животное вообще есть на карте, неаккуратненько

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L49


> $x > $this->getWidth()


Тут не >= должен быть?

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L59


> if ($critter instanceof Cat) {


> return "Cat";


Это неправильно и не позволяет добавлять новые виды животных без переделки кода World. А надо, чтобы это было возможно. да и какая выгода возвращать строку вместо полноценного объекта в котором гораздо больше информации? Надо возвращать само животное.

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L67


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

> https://github.com/never3ver/catsandmice/blob/master/classes/Animal.php#L43


> public function setWorld($world) {


Нужен тайп-хинт. Так как тут можно передавать и объект и null, не забудь приписать его как значение по умолчанию (ClassName $world = null), а то null проходить не будет. Мануал: http://php.net/manual/ru/language.oop5.typehinting.php

> https://github.com/never3ver/catsandmice/blob/master/classes/Animal.php#L6


> protected $awareness;


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

> https://github.com/never3ver/catsandmice/blob/master/classes/Mouse.php#L16


> public function makeMove(World $world)


зачем передавать world если он есть в животном?

> https://github.com/never3ver/catsandmice/blob/master/classes/Mouse.php#L80


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

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

> https://github.com/never3ver/catsandmice/blob/master/classes/Mouse.php#L88


> $rate = $distanceToCat + $pathsQuantity;


Ты складываешь 2 фактора, но одинаков ли вес этих факторов? Вот 2 ситуации:

- до ближайшей кошки 1 ход, из клетки 4 выхода, сумма = 5
- до ближайшей кошки 3 хода, из клетки 1 выход (допустим там пара мышей стоит), сумма = 4

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

Насчет расчета расстояния, ты считаешь декартово расстояние. Оно актуально в тех случаях когда мир изотропен (одинаков во всех направлениях), но у нас кошка при ходе по диагонали ходит не на 1, а на 1.41 (корень из 2) условных единицы. В таком мире логичнее считать не декартово расстояние, а сколько ходов надо кошке чтобы добраться до цели (с учетом что она ходит в 8 сторон). Это кстати можно вынести в отдельную функцию тоже.

> https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L15


> public function getSymbol() {


> if ($this->sleepCounter == 8) { // если кошка съела мышку или сделала 8 ходов


> $this->sleepCounter = 0;


Вот это мина замедленного действия. У тебя функция называется getSymbol, то есть судя по названию она только возвращает текущее обозначение. А на деле она меняет состояние кошки (это называется побочный эффект). Что же будет если вызвать ее 2 раза?

$s1 = $cat->getSymbol(); // @
$s2 = $cat->getSymbol(); // C

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

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

> https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L62


> $length = min($length);


> return $length;


Лучше писать return min($length);, а также не использовать одну переменную для хранения разных типов данных (массив и число).

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

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

В общем, у меня ощущение что ты основы ООП понимаешь потихоньку, но код надо еще доработать. Тут вроде немного, давай доделывай и перейдем к более сложным (но близким к жизни) задачам, наверно про студентов?
https://github.com/never3ver/catsandmice/ #62 #570857
>>569214

> https://github.com/never3ver/catsandmice/blob/master/animals.php


В этом файле код плохой (с копипастой, все одной простыней без разбиения на функции, с логическими ошибками). К примеру:

> https://github.com/never3ver/catsandmice/blob/master/animals.php#L16


> $world->addAnimal(new Mouse(rand(0, $world->getWidth()), rand(0, $world->getHeight())));


Нет гарантий что клетка свободна

> https://github.com/never3ver/catsandmice/blob/master/animals.php#L10


> $tempX = rand(0, $world->getWidth());


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

Ну и код читается тяжело. Вот как можно было написать:

функция добавитьЖивотное(карта, животное) {
попытаться 10 раз {
сгенерировать координаты животного;
если (карта говорит что клеткаCвободна()) {
на карту поместитьЖивотное();
выйти;
}
}

выдать ошибку;
}

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

> https://github.com/never3ver/catsandmice/blob/master/animals.php#L30


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

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php


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

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L43


Тут нет проверки что $key не пуст и животное вообще есть на карте, неаккуратненько

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L49


> $x > $this->getWidth()


Тут не >= должен быть?

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L59


> if ($critter instanceof Cat) {


> return "Cat";


Это неправильно и не позволяет добавлять новые виды животных без переделки кода World. А надо, чтобы это было возможно. да и какая выгода возвращать строку вместо полноценного объекта в котором гораздо больше информации? Надо возвращать само животное.

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L67


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

> https://github.com/never3ver/catsandmice/blob/master/classes/Animal.php#L43


> public function setWorld($world) {


Нужен тайп-хинт. Так как тут можно передавать и объект и null, не забудь приписать его как значение по умолчанию (ClassName $world = null), а то null проходить не будет. Мануал: http://php.net/manual/ru/language.oop5.typehinting.php

> https://github.com/never3ver/catsandmice/blob/master/classes/Animal.php#L6


> protected $awareness;


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

> https://github.com/never3ver/catsandmice/blob/master/classes/Mouse.php#L16


> public function makeMove(World $world)


зачем передавать world если он есть в животном?

> https://github.com/never3ver/catsandmice/blob/master/classes/Mouse.php#L80


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

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

> https://github.com/never3ver/catsandmice/blob/master/classes/Mouse.php#L88


> $rate = $distanceToCat + $pathsQuantity;


Ты складываешь 2 фактора, но одинаков ли вес этих факторов? Вот 2 ситуации:

- до ближайшей кошки 1 ход, из клетки 4 выхода, сумма = 5
- до ближайшей кошки 3 хода, из клетки 1 выход (допустим там пара мышей стоит), сумма = 4

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

Насчет расчета расстояния, ты считаешь декартово расстояние. Оно актуально в тех случаях когда мир изотропен (одинаков во всех направлениях), но у нас кошка при ходе по диагонали ходит не на 1, а на 1.41 (корень из 2) условных единицы. В таком мире логичнее считать не декартово расстояние, а сколько ходов надо кошке чтобы добраться до цели (с учетом что она ходит в 8 сторон). Это кстати можно вынести в отдельную функцию тоже.

> https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L15


> public function getSymbol() {


> if ($this->sleepCounter == 8) { // если кошка съела мышку или сделала 8 ходов


> $this->sleepCounter = 0;


Вот это мина замедленного действия. У тебя функция называется getSymbol, то есть судя по названию она только возвращает текущее обозначение. А на деле она меняет состояние кошки (это называется побочный эффект). Что же будет если вызвать ее 2 раза?

$s1 = $cat->getSymbol(); // @
$s2 = $cat->getSymbol(); // C

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

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

> https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L62


> $length = min($length);


> return $length;


Лучше писать return min($length);, а также не использовать одну переменную для хранения разных типов данных (массив и число).

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

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

В общем, у меня ощущение что ты основы ООП понимаешь потихоньку, но код надо еще доработать. Тут вроде немного, давай доделывай и перейдем к более сложным (но близким к жизни) задачам, наверно про студентов?
#63 #570860
>>570814
Боюсь, тебе придется пересматривать структуру БД.
Смотри:
Один Трек содержится только в одном альбоме, но один Альбом может содержать несколько треков. Значит, таблица Треков содержит внешний ключ на таблицу Альбомов. Насколько я понял из задания, да и вообще знаю, в Альбоме могут быть Треки нескольких Исполнителей та же "дискотека восьмидесятых" значит связь с исполнителями должна быть на уровне Трека (но это не имеет значения). Таким образом, я считаю, что в таблице Заказ связь должна быть только с таблицей Трек. Заказ будет связан с Альбом по транзитивности, если надо будет, то данные будут выбираться джойнами.
#64 #570861
>>569272

https://github.com/lexdss/abitur - у меня не открывается (ошибка 404). Репозиторий удален? Баг на гитхабе? Перезалей, а то я не смогу проверить.

>>569335

> $xt, $tx


Плохие названия, только путают, назови например $a и $b или $letter1 и $letter2.

> $lText = mb_strtolower($text);


Можно тут не заводить новую переменную, а использовать ту же.

Насчет того, как после цикла понять палиндром или нет, лучше сделать так: завести переменную, занести в нее 1 (или специальное значение true что значит истина), а при несовпадении внести 0 (или false = ложь). И в конце проверять через if.

Сам алгоритм верный, надо только код причесать ради читаемости.

Ну и то что анон выне написал, elseif можно заменить на else без условия.
#65 #570863
>>570860

Нет. Покупка альбома не то же самое что купить все треки в альбоме. Посмотри цены сам:

https://itunes.apple.com/ru/album/all-that-you-cant-leave-behind/id14888276

Треки: 19р × 12 ~ 228
Альбом: 149 р

Также менеджеры хотят отчеты, сколько альбомов куплено целиком, а сколько треков. Эти данные нельзя терять.
#66 #570864
>>569485

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


Редис это NoSQL и тут надо мыслить именно ключами-значениями.

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


> Кажется, там еще есть команда SCAN, но я пока не понимаю, как она работает.


SCAN позволяет получать список ключей порциями. Она возвращает тебе допустим 10 ключей и специальное число-идентифиактор, который ты указываешь при следущем вызове чтобы получить следующие 10. Преимщуества очевидны: редис блокируется ненадолго в отличие от KEYS, на стороне PHP не нужна память чтобы хранить все ключи. Вообще KEYS это команда не для продакшена, это больше для отладки у себя на компьютере. Да и SCAN тоже больше для целей вроде экспорта данных, создания бекапов, отладки, и тд. Не стоит алгоритмы на ней основывать. NoSQL так неэффективно использовать.

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

> Что за "cursor"? О каком итераторе они говорят?


Это из баз данных, некоторые базы данных позволяют читать результаты запроса по мере выполнения (стримить), и там «курсор» это абстрактная структура которая позволяет получить следующий кусок ответа. В редисе он нужен чтобы следующий вызов SCAN вернул не те же самые данные, а следующий блок.

Там в мануале по SCAN первый раз выполняют команду scan 0, она возвращает 10 записей и курсор - число «17». Его передают во второй вызов scan 17, и получают следующие записи и новое значение курсора. И т д.

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

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


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

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

>>в чем проблема накопления одинаковых id в очереди?


> Лишняя память. Зачем мне по сто-тысяче раз хранить в списке повторяющиеся значения, если можно хранить только уникальные?


Мы платим памятью за упрощение алгоритма, производительность и снижение нагрузки на базу (которая упирается в IOPS диска = число отдельных операций которые диск делает за секунду). И это во многих случаях выгодный обмен. Плюс, я думаю там даже за день больше пары гигабайт не набежит, а ведь мы можем сбраывать данные каждые 5-10 минут и не доводить до такого.

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

>Хорошо, сет тоже выбрасываем.


Рад что мы пришли к пониманию

> Я пока не в курсе, как реализованы транзакции в редисе, поэтому не понимаю почему транзакции препятствуют масштабированию.


Как минимум тем, что масштабирование подразумевает распределение нагрузки на N серверов (так как 1 не справляется), а транзакция выполняется на одном сервере. Механизмы распределенных транзакций между несколькими серверами сложны и в редисе их нет. Также они обычно бьют по производительности. Если используется отдельный сервер-координатор, то мы получаем еще и единую точку отказа. Если интересно, можешь на досуге подумать про то как сделать распределенную транзакцию c ACID, которая была бы устойчива к отключению серверов и нарушению каналов связи, но только не сломай голову, это реально сложная тема, сложнее чем все что ты тут изучал. Для начала можешь гуглить по словам «Distributed transaction», «two-phase commit», «CAP теорема».

Вот тут вроде простая статья: https://ru.wikipedia.org/wiki/XA_%D0%A2%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B8

Если тебе нужен простой пример где нужна распределенная транзакция: представь банк, у которого данные пользователей разнесены на N серверов. Со счета на сервере A надо перевести сумму на счет, хранящийся на сервере B. Описанный выше протокол может использоваться для выполнения этого перевода с поддержкой ACID, но конечно производительность тут будет значительно ниже из-за многочисленных коммуникаций между серверами, приложением и координатором. Это не для хайлоада, а для случаев когда на первом месте надежность.

На практике при шардинге MySQL (разнесении базы на несколько серверов) обычно просто отказываются от транзакций, внешних ключей и джойнов (и ACID). Все это хорошо работает только в пределах одного сервера.

В редисе «транзакция» это не SQL транзакция с ACID, это просто команды накапливаются в буфере и выполняются атомарно (так как редис однопоточный) по команде EXEC. можешь почитать описание в документации редиса ( http://redis.io/topics/transactions ) и сделать сравнение с SQL ACID транзакциями.

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

> Сначала mysql конечно. Он же пишет на диск. Redis пишет в оперативную память, это пара милисекунд. Да, у нас остается точка отказа между этими двумя коммитами, но во-первых это промежуток наверное меньше милисекунды, во-вторых я просто не знаю, что тут можно сделать.


Я тоже. Есть конечно решение, которое описано выше, распределенные транзакции, но я думаю реализовать XA (который не поддерживается ни редисом ни MySQL как я понял) ради учета просморов объявления это излишне.

> 2.1. Парсим каждую строку вида "ip:id", чтобы получить ip и id, сохраняем в некий массив вида ['id страницы'=>кол-во посещений,].


А зачем нам в очереди хранить ip? Мы же кладем туда только уникальные просмотры (неуникальные отсеиваются хешем pvu).

> В этом поможет функция array_keys со вторым параметром. В конце этого шага получаем массив вида ['кол-во посещений'=>array('все id страниц с таким кол-вом посещений')].


Возможно тебе поможет функция array_count_values. array_keys это как-то сложно, лучше тогда просто циклом массив обойти и сгруппировать.

> Как видишь, здесь значительно больше телодвижений в самом php-скрипте,


Пусть. Это часть которую масштабирвать проще всего, просто ставим еще пару серверов.

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


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

В общем, алгоритм меня устраивает, кроме вопроса про хранение IP в очереди (зачем?) и настройки сохранения на диск. Когда будешь писать код, не поленись в комментарии хотя бы скопипастить текст алгоритма из поста, а то поверь, в такой штуке будет непросто разобраться. Также (чтобы попрактиковаться в ООП и хорошем коде), постарайся сделать универсальный счетчик, который можно подключить к любому сайту (для этого тебе скорее всего придется разбить его на универсальный класс и небольшой класс, который реализует особенности, относящиеся к твоему сайту).
#66 #570864
>>569485

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


Редис это NoSQL и тут надо мыслить именно ключами-значениями.

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


> Кажется, там еще есть команда SCAN, но я пока не понимаю, как она работает.


SCAN позволяет получать список ключей порциями. Она возвращает тебе допустим 10 ключей и специальное число-идентифиактор, который ты указываешь при следущем вызове чтобы получить следующие 10. Преимщуества очевидны: редис блокируется ненадолго в отличие от KEYS, на стороне PHP не нужна память чтобы хранить все ключи. Вообще KEYS это команда не для продакшена, это больше для отладки у себя на компьютере. Да и SCAN тоже больше для целей вроде экспорта данных, создания бекапов, отладки, и тд. Не стоит алгоритмы на ней основывать. NoSQL так неэффективно использовать.

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

> Что за "cursor"? О каком итераторе они говорят?


Это из баз данных, некоторые базы данных позволяют читать результаты запроса по мере выполнения (стримить), и там «курсор» это абстрактная структура которая позволяет получить следующий кусок ответа. В редисе он нужен чтобы следующий вызов SCAN вернул не те же самые данные, а следующий блок.

Там в мануале по SCAN первый раз выполняют команду scan 0, она возвращает 10 записей и курсор - число «17». Его передают во второй вызов scan 17, и получают следующие записи и новое значение курсора. И т д.

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

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


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

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

>>в чем проблема накопления одинаковых id в очереди?


> Лишняя память. Зачем мне по сто-тысяче раз хранить в списке повторяющиеся значения, если можно хранить только уникальные?


Мы платим памятью за упрощение алгоритма, производительность и снижение нагрузки на базу (которая упирается в IOPS диска = число отдельных операций которые диск делает за секунду). И это во многих случаях выгодный обмен. Плюс, я думаю там даже за день больше пары гигабайт не набежит, а ведь мы можем сбраывать данные каждые 5-10 минут и не доводить до такого.

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

>Хорошо, сет тоже выбрасываем.


Рад что мы пришли к пониманию

> Я пока не в курсе, как реализованы транзакции в редисе, поэтому не понимаю почему транзакции препятствуют масштабированию.


Как минимум тем, что масштабирование подразумевает распределение нагрузки на N серверов (так как 1 не справляется), а транзакция выполняется на одном сервере. Механизмы распределенных транзакций между несколькими серверами сложны и в редисе их нет. Также они обычно бьют по производительности. Если используется отдельный сервер-координатор, то мы получаем еще и единую точку отказа. Если интересно, можешь на досуге подумать про то как сделать распределенную транзакцию c ACID, которая была бы устойчива к отключению серверов и нарушению каналов связи, но только не сломай голову, это реально сложная тема, сложнее чем все что ты тут изучал. Для начала можешь гуглить по словам «Distributed transaction», «two-phase commit», «CAP теорема».

Вот тут вроде простая статья: https://ru.wikipedia.org/wiki/XA_%D0%A2%D1%80%D0%B0%D0%BD%D0%B7%D0%B0%D0%BA%D1%86%D0%B8%D0%B8

Если тебе нужен простой пример где нужна распределенная транзакция: представь банк, у которого данные пользователей разнесены на N серверов. Со счета на сервере A надо перевести сумму на счет, хранящийся на сервере B. Описанный выше протокол может использоваться для выполнения этого перевода с поддержкой ACID, но конечно производительность тут будет значительно ниже из-за многочисленных коммуникаций между серверами, приложением и координатором. Это не для хайлоада, а для случаев когда на первом месте надежность.

На практике при шардинге MySQL (разнесении базы на несколько серверов) обычно просто отказываются от транзакций, внешних ключей и джойнов (и ACID). Все это хорошо работает только в пределах одного сервера.

В редисе «транзакция» это не SQL транзакция с ACID, это просто команды накапливаются в буфере и выполняются атомарно (так как редис однопоточный) по команде EXEC. можешь почитать описание в документации редиса ( http://redis.io/topics/transactions ) и сделать сравнение с SQL ACID транзакциями.

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

> Сначала mysql конечно. Он же пишет на диск. Redis пишет в оперативную память, это пара милисекунд. Да, у нас остается точка отказа между этими двумя коммитами, но во-первых это промежуток наверное меньше милисекунды, во-вторых я просто не знаю, что тут можно сделать.


Я тоже. Есть конечно решение, которое описано выше, распределенные транзакции, но я думаю реализовать XA (который не поддерживается ни редисом ни MySQL как я понял) ради учета просморов объявления это излишне.

> 2.1. Парсим каждую строку вида "ip:id", чтобы получить ip и id, сохраняем в некий массив вида ['id страницы'=>кол-во посещений,].


А зачем нам в очереди хранить ip? Мы же кладем туда только уникальные просмотры (неуникальные отсеиваются хешем pvu).

> В этом поможет функция array_keys со вторым параметром. В конце этого шага получаем массив вида ['кол-во посещений'=>array('все id страниц с таким кол-вом посещений')].


Возможно тебе поможет функция array_count_values. array_keys это как-то сложно, лучше тогда просто циклом массив обойти и сгруппировать.

> Как видишь, здесь значительно больше телодвижений в самом php-скрипте,


Пусть. Это часть которую масштабирвать проще всего, просто ставим еще пару серверов.

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


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

В общем, алгоритм меня устраивает, кроме вопроса про хранение IP в очереди (зачем?) и настройки сохранения на диск. Когда будешь писать код, не поленись в комментарии хотя бы скопипастить текст алгоритма из поста, а то поверь, в такой штуке будет непросто разобраться. Также (чтобы попрактиковаться в ООП и хорошем коде), постарайся сделать универсальный счетчик, который можно подключить к любому сайту (для этого тебе скорее всего придется разбить его на универсальный класс и небольшой класс, который реализует особенности, относящиеся к твоему сайту).
#67 #570866
>>569641

> Я так понял partialAny(fn, 1, undefined, 3, undefined)(2) -> [1, 2, 3, undefined] вот так и не должно происходить?


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

> Что-то если честно не могу додуматься куда деть этот второй массив аргументов. Ковырял отладчик, не особо помогло, дай подсказочку :3


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

>>569667

>>главное что нужно, это понимание принципов нормализации (именно понимание, а не заучивание определений)


> А понимание откуда берется?


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

Суть нормализации можно свести к тому, что мы стремимся избежать хранения любых избыточных данных, а сами данные храним в первичной, атомарной форме (например размер файла числом а не строкой вида «12 Гб»). Если не соблюдать нормализацию, то при работе с базой вылезут проблемы рано или поздно. Почитай реальную историю на примере NoSQL хранилища MongoDB, там люди наслушались хипстеров и отказались от нормализации: http://habrahabr.ru/post/231213/ (я не говорю что монго зло, надо просто применять ее где это уместно).

Кроме нормализации важно еще знать виды связей между сущностями (1:1, 1:M, M:N), а также понимать суть этих связей. Ну например между сущностями «лейбл» и «альбом» есть связь «выпустил» вида «1:M»: один лейбл выпустил много (0...N) альбомов. И наоборот, каждый альбом «выпущен» каким-то одним лейблом. Эти связи еще можно рисовать стрелочками, есть несколько форматов таких ER диаграмм (и даже программы для этого). ВОт например:

http://www.intuit.ru/EDI/23_03_15_1/1427062716-22593/tutorial/531/objects/5/files/05_02.gif
https://en.wikipedia.org/wiki/File:ERD_Representation.svg

Может быть тебе полезно попробовать ее нарисовать.

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

> У тебя как всегда неадекватно сложные задачи


Ну ведь неадекватно легкие про лайки и кинотеатр ты уже решил. Тебе ведь неинтересно еще одну такую же получить.

> Мне так почему-то кажется, что проектировали itunes и google play люди с немного большим опытом,


Ну тебя никто и не просит сделать сервис такого уровня целиком (да его и не один человек делал). А лишь предложить схему БД, да еще и с возможностью попросить подсказку.

> Например, как хранить ссылку на исполнителя трека? Исполнителем может быть либо группа, либо сольный артист (который может одновременно принадлежать к одной группе, а может даже и не одной)


Для начала можно сделать это 2 отдельными сущностями: Артист и Группа. Так как у них много общего, тут уместно применить одну из схем наследования таблиц, унаследовав их от абстрактной сущности «Исполнитель». Паттерны наследования таблиц, попробуй сравнить их преимущества и недостатки: Single Table Inheritance, Class Table Inheritance, Concrete Table Inheritance. Ссылки не даю, найдешь сам.

Соответственно мы можем ввести отношение «Исполнитель является автором Трека».

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

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


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

> ensemble


> - id


...

> - performer_id


Если это Class Table INheritance то тут один из этих 2 идентификаторов является лишним. Тут уместнее совместить первичный и внешний ключ, а не добавлять искуственный.
#67 #570866
>>569641

> Я так понял partialAny(fn, 1, undefined, 3, undefined)(2) -> [1, 2, 3, undefined] вот так и не должно происходить?


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

> Что-то если честно не могу додуматься куда деть этот второй массив аргументов. Ковырял отладчик, не особо помогло, дай подсказочку :3


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

>>569667

>>главное что нужно, это понимание принципов нормализации (именно понимание, а не заучивание определений)


> А понимание откуда берется?


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

Суть нормализации можно свести к тому, что мы стремимся избежать хранения любых избыточных данных, а сами данные храним в первичной, атомарной форме (например размер файла числом а не строкой вида «12 Гб»). Если не соблюдать нормализацию, то при работе с базой вылезут проблемы рано или поздно. Почитай реальную историю на примере NoSQL хранилища MongoDB, там люди наслушались хипстеров и отказались от нормализации: http://habrahabr.ru/post/231213/ (я не говорю что монго зло, надо просто применять ее где это уместно).

Кроме нормализации важно еще знать виды связей между сущностями (1:1, 1:M, M:N), а также понимать суть этих связей. Ну например между сущностями «лейбл» и «альбом» есть связь «выпустил» вида «1:M»: один лейбл выпустил много (0...N) альбомов. И наоборот, каждый альбом «выпущен» каким-то одним лейблом. Эти связи еще можно рисовать стрелочками, есть несколько форматов таких ER диаграмм (и даже программы для этого). ВОт например:

http://www.intuit.ru/EDI/23_03_15_1/1427062716-22593/tutorial/531/objects/5/files/05_02.gif
https://en.wikipedia.org/wiki/File:ERD_Representation.svg

Может быть тебе полезно попробовать ее нарисовать.

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

> У тебя как всегда неадекватно сложные задачи


Ну ведь неадекватно легкие про лайки и кинотеатр ты уже решил. Тебе ведь неинтересно еще одну такую же получить.

> Мне так почему-то кажется, что проектировали itunes и google play люди с немного большим опытом,


Ну тебя никто и не просит сделать сервис такого уровня целиком (да его и не один человек делал). А лишь предложить схему БД, да еще и с возможностью попросить подсказку.

> Например, как хранить ссылку на исполнителя трека? Исполнителем может быть либо группа, либо сольный артист (который может одновременно принадлежать к одной группе, а может даже и не одной)


Для начала можно сделать это 2 отдельными сущностями: Артист и Группа. Так как у них много общего, тут уместно применить одну из схем наследования таблиц, унаследовав их от абстрактной сущности «Исполнитель». Паттерны наследования таблиц, попробуй сравнить их преимущества и недостатки: Single Table Inheritance, Class Table Inheritance, Concrete Table Inheritance. Ссылки не даю, найдешь сам.

Соответственно мы можем ввести отношение «Исполнитель является автором Трека».

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

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


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

> ensemble


> - id


...

> - performer_id


Если это Class Table INheritance то тут один из этих 2 идентификаторов является лишним. Тут уместнее совместить первичный и внешний ключ, а не добавлять искуственный.
#68 #570867
>>569676

Константы надо хранить не отдельным объектом, а поместить в «класс» Гамбургер. То есть можно так:

Hamburger.SIZE_BIG = 'big';
или
Hamburger.SIZE_BIG = 1;

Значение константы это число или строка, не стоит в ней хранить данные, это будет уже не константа, а что-то странное.

Вместо того чтобы создавать методы при создании объекта, лучше создать их один раз, с помощью прототипов. Разберись с прототипами и реализацией классов на их основе. Твой подход имеет недостатки:

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

> var price = size.price + stuffing.price;


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

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

> кроме проверки на ошибки. Это нужно делать через try..catch? Там получается каждый метод в него нужно будет оборачивать?


Почитай урок про исключения и зачем они нужны (чтобы сообщать об ошибках). try/catch используется для ловли исключений тем, кто использует твой класс. А от тебя требуется только выкидывать их через throw.

То есть если ты раньше писал console.log("Неверно что-то передано"), теперь замени это на throw new HamburgerError(...) или new Error(...).

>>569750

Зачем писать 100500-й движок ИМ если есть готовые?

>>569771

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

Вообще адаптивность это умение хорошо отображаться на разных устройствах. Она достигается за счет правильной «резиновой» верстки и переключения раскладки страницы на маленьких экранах через @media.

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

>>569831

Почему бы потихоньку не попробовать?

>>569896

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

>>570096

> Предлагаешь что ли отдельно считать расстояние по X и по Y?


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

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


Если кошка на 3 клетки выше и на 3 правее, то твой код даст декартово расстояние = sqrt(18) = 4.24. Если кошка на той же строчке, в 4 клетках справа, расстояние до нее = 4. Кажется что первый вариант лучше, кошка дальше.

В нашем изотропном мире, где все направления равноценны, это так. Но в игре мир неизотропен. Кошка по диагонали двигается быстрее. В первом случае кошка доберется до мышки не за 4.24, а за 3 хода (по диагонали). Он хуже.

> Я совершенно не понимаю эту задачу.


Давай еще чуть помучаем расстояния. Разбери примеры которые я дал и сколько там ходов надо кошке.
#68 #570867
>>569676

Константы надо хранить не отдельным объектом, а поместить в «класс» Гамбургер. То есть можно так:

Hamburger.SIZE_BIG = 'big';
или
Hamburger.SIZE_BIG = 1;

Значение константы это число или строка, не стоит в ней хранить данные, это будет уже не константа, а что-то странное.

Вместо того чтобы создавать методы при создании объекта, лучше создать их один раз, с помощью прототипов. Разберись с прототипами и реализацией классов на их основе. Твой подход имеет недостатки:

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

> var price = size.price + stuffing.price;


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

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

> кроме проверки на ошибки. Это нужно делать через try..catch? Там получается каждый метод в него нужно будет оборачивать?


Почитай урок про исключения и зачем они нужны (чтобы сообщать об ошибках). try/catch используется для ловли исключений тем, кто использует твой класс. А от тебя требуется только выкидывать их через throw.

То есть если ты раньше писал console.log("Неверно что-то передано"), теперь замени это на throw new HamburgerError(...) или new Error(...).

>>569750

Зачем писать 100500-й движок ИМ если есть готовые?

>>569771

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

Вообще адаптивность это умение хорошо отображаться на разных устройствах. Она достигается за счет правильной «резиновой» верстки и переключения раскладки страницы на маленьких экранах через @media.

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

>>569831

Почему бы потихоньку не попробовать?

>>569896

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

>>570096

> Предлагаешь что ли отдельно считать расстояние по X и по Y?


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

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


Если кошка на 3 клетки выше и на 3 правее, то твой код даст декартово расстояние = sqrt(18) = 4.24. Если кошка на той же строчке, в 4 клетках справа, расстояние до нее = 4. Кажется что первый вариант лучше, кошка дальше.

В нашем изотропном мире, где все направления равноценны, это так. Но в игре мир неизотропен. Кошка по диагонали двигается быстрее. В первом случае кошка доберется до мышки не за 4.24, а за 3 хода (по диагонали). Он хуже.

> Я совершенно не понимаю эту задачу.


Давай еще чуть помучаем расстояния. Разбери примеры которые я дал и сколько там ходов надо кошке.
#69 #570868
>>570280

Разберись с наследованием, чтобы не изобретать велосипеды.

> На самом деле мелькала мысль сделать по принципу eav, но мне кажется это большим усложнением в данном случае.


EAV это замена наследованию когда классов сущностей огромное число (сотни), чтобы упростить систему. Но у нас всего 2 наследуемые сущности и EAV не подходит.

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

> ensemble


Тут id и performer_id по моему дублируют друг друга.

> track


> - category_id (fk)


По моему там на уровне альбомов же проставляется категория?

Связь между альбомами и треками M:N, почему? Один трек на разных альбомах разных лейблов может иметь разную стоимость и условия распространения.

>>570286
>>570310
>>570290
>>570326

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

Алсо я в общем согласен с постом, что ОП неплохой человек.

>>570319

Зависит от того, как ты настроишь. Там есть такие возможности:

- для разработки локально ты можешь встроить компилятор LESS/SASS на яваскрипте в веб-страницу. Тогда код компилируется в браузере, удобно тем что все изменения в файле применяются сразу, но страдает скорость загрузки и браузер притрмаживает.
- для выкладки кода на сервер ты компилируешь код в CSS с помощью компилятора, вызвая его напрямую из командной строки или через инструмент вроде gulp/grunt. Соответственно пользователь загружает итоговый CSS файл. Кстати, grunt/gulp умеют еще много чего: склеивать, сжимать файлы, делать CSS спрайты и тд. Правильные разработчики делают один скрипт деплоя который все это делает и автоматически загружает изменения на сервер.

Проверить что у тебя исплоьзуется можно глянув на исходный код страницы в браузере (Ctrl + U), или в dev tools (Ctrl + Shift + I) на вкладке network.

>>570374

Должен, если так написан договор. Более того, ты только разрешение продавать их треки у лейблов выпрашивать замучаешься, и там будет куча условий: минимальный объем продаж который ты обеспечишь (неустойка за провал плана), география распространения, обязательные отчеты, итд. Ты не можешь просто взять и продать 10 песенок, там счет идет на миллионы минимум. Раньше лейблы еще требовали использовать DRM, но благодаря Джобсу удалось это отстоять.

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

Истории по теме:

https://m.roem.ru/11-06-2015/197756/apple-music-no-rocks/
https://m.roem.ru/22-06-2015/198520/swift-wins/
#69 #570868
>>570280

Разберись с наследованием, чтобы не изобретать велосипеды.

> На самом деле мелькала мысль сделать по принципу eav, но мне кажется это большим усложнением в данном случае.


EAV это замена наследованию когда классов сущностей огромное число (сотни), чтобы упростить систему. Но у нас всего 2 наследуемые сущности и EAV не подходит.

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

> ensemble


Тут id и performer_id по моему дублируют друг друга.

> track


> - category_id (fk)


По моему там на уровне альбомов же проставляется категория?

Связь между альбомами и треками M:N, почему? Один трек на разных альбомах разных лейблов может иметь разную стоимость и условия распространения.

>>570286
>>570310
>>570290
>>570326

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

Алсо я в общем согласен с постом, что ОП неплохой человек.

>>570319

Зависит от того, как ты настроишь. Там есть такие возможности:

- для разработки локально ты можешь встроить компилятор LESS/SASS на яваскрипте в веб-страницу. Тогда код компилируется в браузере, удобно тем что все изменения в файле применяются сразу, но страдает скорость загрузки и браузер притрмаживает.
- для выкладки кода на сервер ты компилируешь код в CSS с помощью компилятора, вызвая его напрямую из командной строки или через инструмент вроде gulp/grunt. Соответственно пользователь загружает итоговый CSS файл. Кстати, grunt/gulp умеют еще много чего: склеивать, сжимать файлы, делать CSS спрайты и тд. Правильные разработчики делают один скрипт деплоя который все это делает и автоматически загружает изменения на сервер.

Проверить что у тебя исплоьзуется можно глянув на исходный код страницы в браузере (Ctrl + U), или в dev tools (Ctrl + Shift + I) на вкладке network.

>>570374

Должен, если так написан договор. Более того, ты только разрешение продавать их треки у лейблов выпрашивать замучаешься, и там будет куча условий: минимальный объем продаж который ты обеспечишь (неустойка за провал плана), география распространения, обязательные отчеты, итд. Ты не можешь просто взять и продать 10 песенок, там счет идет на миллионы минимум. Раньше лейблы еще требовали использовать DRM, но благодаря Джобсу удалось это отстоять.

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

Истории по теме:

https://m.roem.ru/11-06-2015/197756/apple-music-no-rocks/
https://m.roem.ru/22-06-2015/198520/swift-wins/
#70 #570869
>>570451

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

>>570470

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

>>570465

Учебник на народе из оп поста.

>>570475

Лучше наши задания на html/css из оп поста.

>>570521

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

$tank->type = 1; // плохо: что это значит? какие есть еще варианты? непонятно
$tank->type = 'light'; // что это значит? какие есть еще варианты? непонятно

Также, если ты опечатаешься то PHP не укажет тебе на это.

А вот как надо:

class Tank
{
// содержательный комментарий
const TYPE_LIGHT = 'light';
const TYPE_MEDIUM = ...
...

$tank->type = Tank::TYPE_LIGHT; // прекрасно: читабельно, PHP или IDE укажет на ошибку при опечатке, IDE покажет автодополнение, можно искать поиском по коду

Также, константы можно использовать например для хранения постоянных величин, например максимальная скорость танка:

const MAX_SPEED = 80;

> Вот, есть у меня класс с методом, в котором используются константные данные, но только в одном методе. Надо ли их объявлять, как константу класса? Или же достаточно описать просто, как переменную в конкретном методе?


зависит от ситуации и хочешь ли ты чтобы она была видна снаружи.

>>570655

Нужно больше подробностей. Что используешь, PDO или MySQLi, включен ли режим PDO::ERRMODE_EXCEPTION, в случае mysqli пишешь ли if после query, и тд. Что в логе ошибок ? Включен ли display_errors?
#70 #570869
>>570451

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

>>570470

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

>>570465

Учебник на народе из оп поста.

>>570475

Лучше наши задания на html/css из оп поста.

>>570521

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

$tank->type = 1; // плохо: что это значит? какие есть еще варианты? непонятно
$tank->type = 'light'; // что это значит? какие есть еще варианты? непонятно

Также, если ты опечатаешься то PHP не укажет тебе на это.

А вот как надо:

class Tank
{
// содержательный комментарий
const TYPE_LIGHT = 'light';
const TYPE_MEDIUM = ...
...

$tank->type = Tank::TYPE_LIGHT; // прекрасно: читабельно, PHP или IDE укажет на ошибку при опечатке, IDE покажет автодополнение, можно искать поиском по коду

Также, константы можно использовать например для хранения постоянных величин, например максимальная скорость танка:

const MAX_SPEED = 80;

> Вот, есть у меня класс с методом, в котором используются константные данные, но только в одном методе. Надо ли их объявлять, как константу класса? Или же достаточно описать просто, как переменную в конкретном методе?


зависит от ситуации и хочешь ли ты чтобы она была видна снаружи.

>>570655

Нужно больше подробностей. Что используешь, PDO или MySQLi, включен ли режим PDO::ERRMODE_EXCEPTION, в случае mysqli пишешь ли if после query, и тд. Что в логе ошибок ? Включен ли display_errors?
#71 #570870
>>570707

Чтобы не быть пустословом, напиши важные пункты которые я не даю и наоборот, бесполезные знания которые я заставляю учить. Не больше 10 слов на 1 пункт. Пока будем считать тебя пустословом.

И да, хорошо анон написал, давайте меньше обсуждать личность ОПа, а больше программирование.

>>570790

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

>>570794

> смертной казни за оскорбление святынь ислама


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

>>570793

Через пакетный менеджер ubuntu (apt-get install?)

> Есть ли анонасы, у которых такая смесь работает именно на этой версии бубунты?


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

>>570814

Наследование может быть? Ну или 2 отношения вида «пользователь купил альбом» и «пользователь купил трек» с 2 внешними ключами.

> Создать доп.таблицу "товар" и ссылаться на нее из таблиц альбомов и треков?


Это одна из форм наследования

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


Тут нужна оценка. Мы создаем глобальный сервис и лишний гигабайт ничего не решает.

>>570842

Никогда не использовал. Не нравится много статических методов.

>>570845

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

>>570847

В документацию можно и тут послать.
#71 #570870
>>570707

Чтобы не быть пустословом, напиши важные пункты которые я не даю и наоборот, бесполезные знания которые я заставляю учить. Не больше 10 слов на 1 пункт. Пока будем считать тебя пустословом.

И да, хорошо анон написал, давайте меньше обсуждать личность ОПа, а больше программирование.

>>570790

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

>>570794

> смертной казни за оскорбление святынь ислама


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

>>570793

Через пакетный менеджер ubuntu (apt-get install?)

> Есть ли анонасы, у которых такая смесь работает именно на этой версии бубунты?


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

>>570814

Наследование может быть? Ну или 2 отношения вида «пользователь купил альбом» и «пользователь купил трек» с 2 внешними ключами.

> Создать доп.таблицу "товар" и ссылаться на нее из таблиц альбомов и треков?


Это одна из форм наследования

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


Тут нужна оценка. Мы создаем глобальный сервис и лишний гигабайт ничего не решает.

>>570842

Никогда не использовал. Не нравится много статических методов.

>>570845

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

>>570847

В документацию можно и тут послать.
#72 #570968
>>570869
Спасибо!
#73 #571003
>>570867

>Константы надо хранить не отдельным объектом, а поместить в «класс» Гамбургер. То есть можно так:


>Hamburger.SIZE_BIG = 'big';


>или


>Hamburger.SIZE_BIG = 1;


>Значение константы это число или строка, не стоит в ней хранить данные, это будет уже не константа, а что-то странное.



Если про перенос объекта в класс понятно, то с тем что в константе нужно хранить только одно значение или строку - не согласен. И вот почему:

- Из 9 аккуратных строк кода мы получаем 14 (в нашем случае, а ведь в других может быть и в разы больше).
- Если объявлять константы отдельно на цену и на калории, то получается и передавать в аргументы при создании нового гамбургера нужно не 2 значения а 4. Раньше было (размер, начинка), сейчас (размер_цена, размер_калории, начинка_цена, начинка_калории). А это противоречит указанной у тебя строке для создания нового гамбургера var hamburger = new Hamburger(Hamburger.SIZE_SMALL, Hamburger.STUFFING_CHEESE);
И для методов такая же ситуация.
#75 #571009
Аноны, а что, реально чтобы работать php-программистом нужно действительно хорошо знать html/css? Если да то за каким фигом программист занимается дизайном?
8 Кб, 200x150
#76 #571027
>>571009
А что сложного в верстке? Макет верстается от силы час-два.
#77 #571033
>>571009
что бы начать нужно хотя бы маленько знать, что бы делать вьюхи в админку и хотя бы понимать как на бутстрапе сверстать простенький проект.

Чем меньше проектик, тем за больше всего ты в нем отвечаешь, и тем больше ты должен уметь "всего понемногу". В большом проекте наверное сидишь чисто бэкэнд ковыряешь и в душе не ебешь что-то во фронтенде, ибо фронтэнд там тоже дохуя сложный и им отдельный человек занимается, или отдельная команда.
#78 #571034
>>571003
>>571005

Понял свою ошибку. На пикче ни первый, ни второй вариант не работают.

>Константы надо хранить не отдельным объектом, а поместить в «класс» Гамбургер


В буквальном смысле воспринял.

Хотя не во всем я оказался не прав. Все-таки теперь приходится передавать в 2 раза больше аргументов.

Вот что сейчас получилось.
https://ideone.com/FsDztW
#79 #571039
Переустановил винду, решил поставить новый апач с пыхой, но на этапе подключения пхп к апачу застрял. Добавляю строки

LoadModule php5_module "C:/php/php5apache2_4.dll"
AddHandler application/x-httpd-php .php
PHPIniDir "C:/php"

В httpd.conf, сервис перестаёт запускаться. Удаляю, всё нормально. Файл php5apache2_4.dll в С:/php точно есть. В логи ничего не пишется.
#80 #571047
>>571039
Пардон, я имбецил, каким-то образом скачал архив для 32ух битной версии, вместо 64.
#81 #571058
>>571027

Охуительные истории, прям открыл книгу по html5/css3 и на следующий день верстаю профессиональные страницы за час-два, ага.
33 Кб, 850x377
#82 #571072
Антоши, в Yii2 использую ActiveRecord, надо ли писать отдельные геттеры/сеттеры для каждого поля таблицы или же обращаться напрямую к полям, например $user->id=123 в данном случае нормальная практика?
#83 #571127
>>571003

> Из 9 аккуратных строк кода мы получаем 14 (в нашем случае, а ведь в других может быть и в разы больше).


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

> Если объявлять константы отдельно на цену и на калории,


Это не требуется. Это не константа из физики вроде ускорения свободного падения. В программировании константы могут иметь другой смысл.

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

А чему она равна абсолютно не важно так как мы никогда не используем ее значение. Hamburger.SIZE_SMALL может быть равно 1 или 'small' - это ни на что не влияет.

Вот глянь еще тут пример с танками: >>570869

> то получается и передавать в аргументы при создании нового гамбургера нужно не 2 значения а 4


Нет. Мы передаем размер и начинку, а класс должен сам знать сколько они стоят.

>>571005

В первом примере:

SIZE_BIG: ...

SIZE_BIG это не константа, а лишь строка 'SIZE_BIG', ты не можешь в программе написать например console.log(SIZE_BIG), это выдаст ошибку о несуществующей переменной.

Во втором примере: не надо стоимость делать константами. КОнстанты нужны только для обозначения параметров гамбургера вроде размера или начинки.

Ну сам подумай: а как без констант указать какого размера ты хочешь гамбургер? с какой начинкой? Строки не годятся так как это не понятно, легко опечататься, непонятно какие еще есть варианты.
#83 #571127
>>571003

> Из 9 аккуратных строк кода мы получаем 14 (в нашем случае, а ведь в других может быть и в разы больше).


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

> Если объявлять константы отдельно на цену и на калории,


Это не требуется. Это не константа из физики вроде ускорения свободного падения. В программировании константы могут иметь другой смысл.

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

А чему она равна абсолютно не важно так как мы никогда не используем ее значение. Hamburger.SIZE_SMALL может быть равно 1 или 'small' - это ни на что не влияет.

Вот глянь еще тут пример с танками: >>570869

> то получается и передавать в аргументы при создании нового гамбургера нужно не 2 значения а 4


Нет. Мы передаем размер и начинку, а класс должен сам знать сколько они стоят.

>>571005

В первом примере:

SIZE_BIG: ...

SIZE_BIG это не константа, а лишь строка 'SIZE_BIG', ты не можешь в программе написать например console.log(SIZE_BIG), это выдаст ошибку о несуществующей переменной.

Во втором примере: не надо стоимость делать константами. КОнстанты нужны только для обозначения параметров гамбургера вроде размера или начинки.

Ну сам подумай: а как без констант указать какого размера ты хочешь гамбургер? с какой начинкой? Строки не годятся так как это не понятно, легко опечататься, непонятно какие еще есть варианты.
#84 #571131
Извините новичка, накипело немного.
А я могу накатить IIS как веб-сервер? Или поставить Apache и не париться?
Зашёл на скачать пхп 5.5.30 и там написано:

>If you are using PHP as FastCGI with IIS you should use the Non-Thread Safe (NTS) versions of PHP.


Какие это версии? Платформа Windows 8.0 Корпоративная.
#85 #571132
>>571009

Да. Только PHP это слишком просто. Еще и SQL придется выучить, и наверно много всего другого. Библиотеки, фреймворки, инструменты.

Программирование это не работа на конвеере где достаточно запомнить простейшие движения и всю жизнь повторять.

>>571034

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

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

>>571058

Конечно не один день, недели уйдут. У нас в ОП посте есть неплохие задачи на HTML/CSS которые помогут тебе разобраться в основах CSS, позиционировании, без которых нормально в верстке не разберешься.

>>571072

да, нормальная.
#86 #571133
>>571131

Лучше АПач. В Оп посте есть инструкции по установке.
#87 #571135
>>571133
Спасибо.
#88 #571149
>>571127

То есть мы можем сделать константы в виде
Hamburger.SIZE_BIG = "BIG";

А уже в функции (size) {
if (size = "BIG") {
price = 100;
caloric = 40;
}
}

Ну это так грубо говоря. Правильно?
52 Кб, 1366x688
57 Кб, 1362x705
#89 #571151
Ну что за хуита, анон? Я заебался пердолиться с этими ИДЕ и серверами, а все, что я хочу, так это просто юзать ИДЕ и проверять результат прямо в программе и по жалению запускать его в браузере и чтобы код красиво оформлялся и пару свистоперделок.

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

На опенсервер не смотри, я пока что от него только интерпритатор подключил, хотя я думал еще дебагер подключить, не знаю нахуя, но вроде там можно смотреть как работает твой код мол не спеша, но я скорее стану танцором с бубном 80 лвла, весь день дрочу эти сервера и пхпштормы, а получается хуйня.
#90 #571163
>>571149

Нет. Ты не должен что-то делать с значением константы и сраванивать ее со строкой. Ты должен писать

if (size == Hamburger.SIZE_BIG)
#91 #571169
>>571151

Ты навключал лишних настроек, наскачивал лишних плагинов, ставишь сборки вместо апача + php, не читаешь документацию к IDE и теперь заслуженно страдаешь.

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

Соответственно начни с чтения документации по IDE и прочитай что делают команды которые ты используешь. Пойми где именно ты подключил запуск юнит-тестов. Затем удали опенсервер.
#92 #571172
>>571163

>Нет. Ты не должен что-то делать с значением константы



Тогда вообще без разницы что в значении константы? Мы его и не используем ни разу? Нам нужно только хорошо читаемое название этой константы?
#93 #571177
>>571172

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

Соответственно если поменять значение такой константы на любое другое код должен работать как ни в чем не бывало.
#94 #571178
>>571169
где ты плагины и кучу настроек увидел?

все, что я сделал, так это увеличил шрифт кода и изменил оформление его уже, включил показ номера строчки.

Потом, я скачал опен сервер, но с пхпшторма просто взял и подключил интерпритатор от опен сервера ничего более, потом в папке локалхост создал пхп файл и закинул туда свой недоделанный код и все заебись. Создал в той же папке где и локалхост другой проект, опять создал же пхп файл, закинул тот же код и уже нихуяшечки не работает, а выдает ошибку.
#95 #571184
>>571178

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

Почитай документацию по функции запуска и выясни почему она работает не так.
#96 #571185
>>571178
Переустанови шторм, может поможет.
Я вот запускаю php-файлы даже с рабочего стола, все нормально работает.
Или у тебя нелицензионная версия? В пиратских кряках можно запускать только из папки локалхост, с этим ничего не поделаеш...
95 Кб, 1366x768
#97 #571189
>>571185
>>571184

Ну и советчики конечно.

>при каждой ошибке читать тонны макулатуры



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

Дебагер вообще не ебу как подключить, геммороая до жопы
#98 #571191
>>570868
А я кстати знал про эти паттерны, но не понимал в каких ситуациях их можно применить на практике.

Тогда применим Class Table Inheritance для групп и артистов.
Performer
- id
- еще какие-то общие свойства
Artist
- id (pk + внешний на performer(id))
- first_name
- surname
- birth_year и т.д.
Ensemble
- id (pk + внешний на performer(id))
- name
- foundation_year и т.д.

Я так понимаю, что выбирать из этих таблиц двумя джойнами с юнионом
SELECT p.id, a.name, a.surname FROM performer p JOIN artist a ON p.id = a.id
UNION (SELECT p.id, e.name FROM performer p JOIN ensemble e ON p.id = e.id)

Еще одна особенность такого подхода в том, что мы должны внимательно следить за бизнес-логикой в приложении, чтобы не заинсертить что-то неправильное, например в Artist и Ensemble записи с одним id.

>Почитай про паттерны наследования. Ты явно пытаешься их переизобрести


Я о них не знал/не понимал их.
#98 #571191
>>570868
А я кстати знал про эти паттерны, но не понимал в каких ситуациях их можно применить на практике.

Тогда применим Class Table Inheritance для групп и артистов.
Performer
- id
- еще какие-то общие свойства
Artist
- id (pk + внешний на performer(id))
- first_name
- surname
- birth_year и т.д.
Ensemble
- id (pk + внешний на performer(id))
- name
- foundation_year и т.д.

Я так понимаю, что выбирать из этих таблиц двумя джойнами с юнионом
SELECT p.id, a.name, a.surname FROM performer p JOIN artist a ON p.id = a.id
UNION (SELECT p.id, e.name FROM performer p JOIN ensemble e ON p.id = e.id)

Еще одна особенность такого подхода в том, что мы должны внимательно следить за бизнес-логикой в приложении, чтобы не заинсертить что-то неправильное, например в Artist и Ensemble записи с одним id.

>Почитай про паттерны наследования. Ты явно пытаешься их переизобрести


Я о них не знал/не понимал их.
#99 #571205
>>570870
Куки же нужно как-то вставлять и доставать.
if(!$cookie=$app->request->cookies->get('username')){ //setting cokkie if the user doesn't have it
$cookieToken = new Token();

$cookieKey=$cookieToken->generatePassword(8);
$app->setCookie('username', $cookieKey, time()+86400*4);
}
$cookie=$app->request->cookies->get('username');
5 Кб, 283x70
2 Кб, 216x29
#100 #571207
Получаю ответ от сервера и прогоняю через симплхмл
$out = simplexml_load_string($out),
потом смотрю, что получилось (1 пик)
$out -> Pvz[0],
пытаюсь получить значение
$out -> Pvz[0]["City"],
а получаю объект (2 пик).
Как мне получить строковое значение?
#101 #571208
>>571058
У меня верстка 3х страничного магаза по всем правилам адаптивности, резиновости, каруселей, модальных окон и прочей хрени не меньше недели займет.
Самого волнует этот вопрос, ибо я ни разу ни дизинер, жабаскрипт и кроссбраузерность вызывают рвотные позывы, вообще терпеть не могу верстку, какое-то издевательство над программистом.
#102 #571209
>>571009

>Если да то за каким фигом программист занимается дизайном?


Программист дизайном не занимается, для этого должен быть дизайнер, который рисует макет страницы. Задача программиста нарезать макет и сверстать страничку и соответственно навесить на неё необходимый функционал/анимации. В более крупных конторах есть верстальщики, там от программиста уже вёрстка не требуется, но разбираться в ней всё равно необходимо.
#103 #571211
>>571189
гугли xdebug + phpstorm
там правда проблема в том, что потом для каждого проекта тебе придется настраивать дебаггер - порты прописывать и т.п. но это не особо геморройно. во всяком случае оно того стоит.
#104 #571212
>>571211
вкратце - ставишь расширение xdebug, включаешь его в php.ini, в конфиге xdebug прописываешь необходимые настройки, дублируешь их в проекте в phpstorm.
далее рабочий процесс - расставляешь точки выполнения, жмешь debug и можешь переключаться пошагово и смотреть, как у тебя выполняется код - что выводится, сохраняется в переменные и т.п.
в общем, стоит запариться, советую.
#105 #571214
>>571009
php-программист натягивает сверстанные html-странички на php - режет страницы на повторяющиеся блоки, реализует задуманный функционал и т.п.
т.е. понятное дело, что тебе не придется именно верстать макеты. однако об этом процессе тебе нужно иметь представление, чтобы быстро и качественно выполнять свою работу по натягиванию верстки на php.
#106 #571215
>>571178
при создании каждого нового проекта в phpstorm тебе придется заново прописывать все настройки. проверь.
#107 #571216
такой вопрос - мб кто-нибудь насоветует годных задачников? но чтоб с готовыми написанными ответами для проверки себя

причем с задачами типовыми, бытовыми в программировании и крутыми
#108 #571224
>>571216
гостевуха - имиджобрда - магазин.
#109 #571235
Как взять текующую дату прибавить к ней число дней? regexp date делать? типа файл удаляется через нное кол-во дней после дня создания.
#110 #571236
>>571214

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


ой вей, сказали уже смотря где. везде где я был - нужны были человеки-оркестры.
#112 #571253
>>571132

> Да. Только PHP это слишком просто. Еще и SQL придется выучить, и наверно много всего другого. Библиотеки, фреймворки, инструменты.



Это как раз нормально и ожидаемо, так во всех языках программирования.
#113 #571279
Как воспользоваться объектом $app Slim\Slim в классе. т.е. $app->render('File.php', ['files'=>$files]); вот это должно вызываться при создании метода другого класса. просто public function (Slim\Slim $app){} писать?
39 Кб, 938x489
#114 #571293
Да и рейт структуру таблиц. Т.е. все каждый файл на странице выводится вместе с комментами под ним, которые выбираются из двух таблиц по равным полям JOIN ON files.comments_id = coomets.id. Каждому файлу и комменту проставляются автор, делая выборку из таблицы users где JOIN ON users.id== comments.user_id OR JOIN ON users.id == files.user_id.
Все правильно?
#115 #571303
И еще непонятно, если юзер вылогинился или его кука истекла, то по истечению или при вылогинивании нужно куку в поле перезаписывать?
#116 #571318
>>571212
Спасибо, вечерком побалуюсь

>>571215
Ну то ладно, но тут же я создаю новый файл php пишу код и нажимаю пуск, а конфиг, как я понял, там нужно только путь к файлу прописать, остается тот же. И нужно правой кнокой запускать. Странно конечно сделано.
#117 #571337
>>571191

> Artist


- id (pk + внешний на performer(id))
Лучше назвать поле performer_id чтобы было понятнее.

А ты сравнивал варианты? Сравни-ка Single Table Inheritance против Class TI.

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


Юнион работает только когда список полей одинаковый. У тебя таблицы с разными полями и это осложнит жизнь, так что выбирай просто 2 джойнами.

> Еще одна особенность такого подхода в том, что мы должны внимательно следить за бизнес-логикой в приложении, чтобы не заинсертить что-то неправильное, например в Artist и Ensemble записи с одним id.


Это да. Или рассмотреть еще другие варианты наследования.

>>571205

Нет, погоди, зачем незарегистрированному пользователю кука? Куками обычно идентифицируют зарегистрированных.

>>571207

strval(...), почитай примеры по smplexml в мануале PHP, там отдельная страница есть.

>>571208

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

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

Потому тебе надо разбраться в CSS как следует. Гармоничный HTML и CSS код вряд ли вызовет у тебя неприятные ощущения, скорее наоборот, удовлетворение от хорошо сделанного дела.
#117 #571337
>>571191

> Artist


- id (pk + внешний на performer(id))
Лучше назвать поле performer_id чтобы было понятнее.

А ты сравнивал варианты? Сравни-ка Single Table Inheritance против Class TI.

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


Юнион работает только когда список полей одинаковый. У тебя таблицы с разными полями и это осложнит жизнь, так что выбирай просто 2 джойнами.

> Еще одна особенность такого подхода в том, что мы должны внимательно следить за бизнес-логикой в приложении, чтобы не заинсертить что-то неправильное, например в Artist и Ensemble записи с одним id.


Это да. Или рассмотреть еще другие варианты наследования.

>>571205

Нет, погоди, зачем незарегистрированному пользователю кука? Куками обычно идентифицируют зарегистрированных.

>>571207

strval(...), почитай примеры по smplexml в мануале PHP, там отдельная страница есть.

>>571208

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

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

Потому тебе надо разбраться в CSS как следует. Гармоничный HTML и CSS код вряд ли вызовет у тебя неприятные ощущения, скорее наоборот, удовлетворение от хорошо сделанного дела.
#118 #571340
Кстати, раз тут о дебаггере заговорили, анон, который Юи делает, а ты дебаггер в своей IDE настроил и освоил? Важная штука, и помогает иногда разобраться в проблеме.

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

>>571208

Потому предлагаю прорешать задачки из ОП поста и показать решения.

>>571236

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

>>571216

А задачи из ОП поста как тебе? Правда, без ответов.

> причем с задачами типовыми, бытовыми в программировании и крутыми


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

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

У нас есть хоршие задачи на студентов и файлообменник в ОП посте.
44 Кб, 677x341
#119 #571341
Не понимаю я, почему в таблицу, у которой я специально указал collation utf8_general_ci не вставляется кирилица?
17 Кб, 643x467
#120 #571342
>>571341
Вот переменные, если что.
#121 #571345
>>571235

Урок по работе с датами: https://gist.github.com/codedokode/10539805

Мне ООП-версия DateTime нравится больше.

>>571279

> т.е. $app->render('File.php', ['files'=>$files]); вот это должно вызываться при создании метода другого класса.


Это очень странно что ты рендеришь шаблоны из класса. Скорее всего это неправильно.

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

>>571293

Вроде на первый взгляд да. Не забудь внешние ключи и NULL/NOT NULL правильно прописать.

А для файла и комментария всегда есть автор или там может быть NULL? Тогда нужен не JOIN а LEFT JOIN. Почитай про разницу между видами джойнов.
#122 #571349
>>571303

Если юзер разлогинивается то надо удалить авторизационную куку. Если время ее жизни истекло и браузер ее удалил, то юзер тоже фактически разлогинилсяи должен перезалогиниться.
#123 #571350
>>571341

Командная строк винды использует кодировку cp866. Потому ты должен сделать SET NAMES cp866; в начале работы.

Этим ты говоришь MySQL что ты присылаешь и хочешь получать данные в такой кодироке. Это никак не влияет на кодировку таблиц, полей, и тд, MySQL сделает все преобразования сама.
#124 #571355
>>571350
Благодарю. Я почему-то думал, что SET NAMES только на отображение влияет, не думал что из-за этого не получается вставлять значения.
#125 #571374
Анон подскажи по поводу вордпресс, надо создать форму данные с которой будут заноситься в базу данных. Я создал форму при помощи плагина contact form7, разместил её код на новой странице, где мне писать обработчик этой формы? Саму страницу с таким названием на хостинге найти не могу (судя по всему страницы не хранятся в отдельных файлах). Мне нужен код страницы на которой расположена эта форма одним словом.
#126 #571407

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


Категория задается для альбома? Значит, трек обязан входить минимум в один альбом, даже если это сингл?

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


Лицензионные отчисления зависят от страны, как это было в случае с ценообразованием? И они вообще в чем измеряются, в процентах?

>>571340

>анон, который Юи делает, а ты дебаггер в своей IDE настроил и освоил?


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

>>571337

>А ты сравнивал варианты? Сравни-ка Single Table Inheritance против Class TI.


Сравнивал. STI мне не нравится из-за большого кол-ва нулевых значений. Хотя да, она нас обезопасит от вставки одинаковых id, с чем мы можем столкнуться в Class TI.
И джойны будут не нужны. Ок, заменяем на STI.
Concrete TI не рассматриваю, потому что эта схема имеет все недостатки Class TI, плюс отсутствует "общая" таблица, ради которой эти пляски и затевались.

Короче, у меня пока получилось так
Performer
- id
- first_name
- surname
- group_id (внешний ключ на эту же таблицу, null если музыкант не состоит в группе)
- birth_year и пр.атрибуты музыканта
- group_name
- foundation_year и пр.атрибуты группы
- type (enum: artist, group)

Country
- id
- name

Label
- id
- name
- country_id (fk)

Category
- id
- name
- label_id (fk)
- album_base_price
- track_base_price

Category_country
- category_id (pk, fk)
- country_id (pk, fk)
- local_album_price
- local_track_price
- available (enum: y, n)

Tariff
- id
- label_id (fk)
- type (enum: trial, premium)
- tracks_total (макс.кол-во треков доступно для прослушивания)
- tracks_total_free
- one_track_per_day (допустимое кол-во прослушиваний треков в день)
- one_track_per_day_free
- one_album_per_day (допустимое кол-во прослушиваний альбомов в день)
- one_album_per_day_free
- one_performer_per_day (треков исполнителя в день доступно для прослушивания)
- one_performer_per_day_free
- purchase_fee (отчисления за покупки)
- trial_fee (отчисления за бесплатные прослушивания)

Subscription
- id
- name (trial, premium)
- duration

Audition
- id
- user_id
- track_id

User
- id
- email (null для незарегистрированных)
- password (null для незарегистрированных)
- country_id
- прочие свойства пользователя

Content
- id
- title
- length
- track_album (fk на эту же таблицу)
- album_type (enum: simple, remix, tribute и т.д.)
- release_year
- content_type (enum: album, track)

Genre
- id
- name

Content_genre
- content_id
- genre_id

Content_author
- content_id
- performer_id

Content_performer
- content_id
- performer_id

Purchase
- id
- content_id
- дата покупки и т.д.

User_subscription
- user_id
- subscription_id
- expired

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

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


Не знаю, допустим сделаем таблицу
Promo
- album_id
- expired

Теперь нужно еще написать запросы на выборку из этой свалки.
#126 #571407

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


Категория задается для альбома? Значит, трек обязан входить минимум в один альбом, даже если это сингл?

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


Лицензионные отчисления зависят от страны, как это было в случае с ценообразованием? И они вообще в чем измеряются, в процентах?

>>571340

>анон, который Юи делает, а ты дебаггер в своей IDE настроил и освоил?


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

>>571337

>А ты сравнивал варианты? Сравни-ка Single Table Inheritance против Class TI.


Сравнивал. STI мне не нравится из-за большого кол-ва нулевых значений. Хотя да, она нас обезопасит от вставки одинаковых id, с чем мы можем столкнуться в Class TI.
И джойны будут не нужны. Ок, заменяем на STI.
Concrete TI не рассматриваю, потому что эта схема имеет все недостатки Class TI, плюс отсутствует "общая" таблица, ради которой эти пляски и затевались.

Короче, у меня пока получилось так
Performer
- id
- first_name
- surname
- group_id (внешний ключ на эту же таблицу, null если музыкант не состоит в группе)
- birth_year и пр.атрибуты музыканта
- group_name
- foundation_year и пр.атрибуты группы
- type (enum: artist, group)

Country
- id
- name

Label
- id
- name
- country_id (fk)

Category
- id
- name
- label_id (fk)
- album_base_price
- track_base_price

Category_country
- category_id (pk, fk)
- country_id (pk, fk)
- local_album_price
- local_track_price
- available (enum: y, n)

Tariff
- id
- label_id (fk)
- type (enum: trial, premium)
- tracks_total (макс.кол-во треков доступно для прослушивания)
- tracks_total_free
- one_track_per_day (допустимое кол-во прослушиваний треков в день)
- one_track_per_day_free
- one_album_per_day (допустимое кол-во прослушиваний альбомов в день)
- one_album_per_day_free
- one_performer_per_day (треков исполнителя в день доступно для прослушивания)
- one_performer_per_day_free
- purchase_fee (отчисления за покупки)
- trial_fee (отчисления за бесплатные прослушивания)

Subscription
- id
- name (trial, premium)
- duration

Audition
- id
- user_id
- track_id

User
- id
- email (null для незарегистрированных)
- password (null для незарегистрированных)
- country_id
- прочие свойства пользователя

Content
- id
- title
- length
- track_album (fk на эту же таблицу)
- album_type (enum: simple, remix, tribute и т.д.)
- release_year
- content_type (enum: album, track)

Genre
- id
- name

Content_genre
- content_id
- genre_id

Content_author
- content_id
- performer_id

Content_performer
- content_id
- performer_id

Purchase
- id
- content_id
- дата покупки и т.д.

User_subscription
- user_id
- subscription_id
- expired

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

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


Не знаю, допустим сделаем таблицу
Promo
- album_id
- expired

Теперь нужно еще написать запросы на выборку из этой свалки.
#127 #571413
>>571132

>Программирование это не работа на конвеере где достаточно запомнить простейшие движения и всю жизнь повторять


В 95% случаев как раз нужно повторять заученные действия. Если ты не старший разработчик, конечно, но большинство собравшихся здесь не дорастут даже до миддла.
Я понимаю, что ты умен и тебе скучно выполнять рутинную работу, но зачем ты грузишь сложными задачами тупых нубов, которым это не уперлось?
#128 #571442
Добрый день, как сделать кнопку с переходом по внутренней ссылке в yii2? Читаю офф.мануал, он какой-то слишком сухой и тяжелый для восприятия
#129 #571466
Антоша, выучил html, php & sql от корки до корки, теперь хочу освоить Yii2 чтобы после этого пытаться найти работу irl. Как я понимаю мне для начала надо понять что такое MVC, так? Что почитать по этому поводу порекомендуешь? В гугле не забанен, но лучше уж от вас узнать что лучше прочитать по теме чем перерывать голы водянистой макулатуры.

Или, быть может, чтобы искать работу мне надо браться за что-то другое?
#130 #571479
>>571407

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


На сингле редко бывает ровно 1 трек. Например, вот на одном из синглов я вижу 2 песни + 2 инструментальных версии.

Я думаю, лучше вместо понятия «альбом» ввести понятие «пластинка/диск». То есть вполне может быть диск с 1 треком. Разумеется в таком случае показывать 2 цены нелогично.

> Лицензионные отчисления зависят от страны, как это было в случае с ценообразованием? И они вообще в чем измеряются, в процентах?


В валюте, для простоты пусть будет в долларах.

> Там еще какие-то рекомендации, непонятно как их делать, и нужно ли их хранить отдельно в базе, или выводить из анализа продаж в приложении.


От тебя требуется спроектировать систему их хранения, а алгоритм их составления это уже другое дело. Рекомендация, это по моему (если я не путаю) просто отношение между альбомами вида «c альбомом A рекомендуют альбом B, C, D».
#131 #571499
>>570857
ОП, проверь пожалуйста.
https://github.com/never3ver/catsandmice

>И еще, у кошки и мышки функция makeMove похожа.


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

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


Да, планировал студентов после кошек-мышек. Если я правильно понял, то для решения нужно дополнительно к текущему багажу изучить верстку и sql?
#132 #571502
>>571466
Я не понимаю откуда вы такие беретесь, вот что значит

>выучил html, php & sql от корки до корки


Ты книжку прочитал, или что?
По теме не берись сразу за уии2, судя по вопросам которые ты задаешь ты совсем к нему не готов. Лучше сделай файлообменник из заданий ОПа, это будет тебе намного полезней, а еще лучше начни с задания про студентов, заодно и проверишь как ты выучил все от корки до корки
#133 #571506
ОП, мне таки и не ответили, попробую тебя спросить в твоем треде, ты меня уже когда-то выручал:
https://2ch.hk/pr/res/561925.html
#134 #571508
Полчаса искал свой бывший скин от саблайма, но так и не нашел. Все остальные меня вгоняют в тоску.
#135 #571534
>>571508
Ура, нашел. Им оказался Solarflare. Не представляю, что бы я без него делал.
#136 #571535
>>571534
А я посрал только что.
#137 #571539
>>570864
Так использовать хеш для хранения уникальных посещений?
Вообще я первоначально использовал сет, поскольку нам нужны только значения, причем уникальные.
Сет собственно для того и предназначен, для проверки наличия в нем значения. Так что лучше использую сет.

При запросе страницы проверяем, есть ли в сете pagesVisitsUnique текущее значение "id:ip". Если нет, то записываем его туда, и кладем в очередь id страницы.

Скрипт по расписанию:
1. Берет текущую длину очереди, фиксирует это значение в переменную.
2. Запрашиваем порциями данные из редиса (без удаления их из очереди на этом шаге), пока не достигнем этой суммы N.
2.1. Преобразуем полученный массив в ['кол-во посещений'=>array('все id страниц с таким кол-вом посещений')].
2.2. Ходим в цикле и для каждого ключа массива, упомянутого выше, подставляем массив айдишников в запрос:
UPDATE tbl_name SET visit_counter = visit_counter + delta WHERE id IN (implode($arr, ',')).
2.3. Коммитим mysql, затем удаляем обработанное кол-во записей из начала очереди.

>алгоритм меня устраивает, кроме вопроса про хранение IP в очереди (зачем?) и настройки сохранения на диск.


Действительно, ip в самой очереди не нужен, просто пришлось несколько раз переписывать, немного замаялся, недосмотрел.
По поводу настройки на диск мануал читал http://redis.io/topics/persistence , но мало что вынес.
Короче, настройки "save 1 1" вполне хватит. (сбрасывать на диск каждую секунду)

Кстати, мы в прошлом треде рассматривали оптимизацию запросов, еще тогда назрел вопрос по тому, как выполняется оператор IN в условии. Explain почему-то пишет join type "range", это кажется не совсем очевидным. Range это диапазон, следовательно должен употребляться только с операторами > и <.
Я так думаю, что mysql при запросе where id in (1, 44, 88) берет сначала этот диапазон между min 1 и max 88 (поэтому Range), а потом ходит по полученному промежутку бинарным поиском и ищет указанные значения.
#139 #571541
>>571466
оп-пост читай, там ссылка на учебник и блог опа. Там же задания, начиная от простых типа кредитного калькулятора, заканчивая большими полноценными приложениями вроде файлообменника и сервиса для тестов.
#140 #571542
>>571540

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

Ну и программирование, я думаю, станет не уделом небольшого количества странных людей, а огромной отраслью. Так что учитесь хорошо, анончики, если хотите занять места в этом поезде.
#141 #571572
>>571534
Скинь, что-то не гуглится.
#143 #571577
Strict Standards: Declaration of Slim\Extras\Views\Twig::render() should be compatible with Slim\View::render($template, $data = NULL) in C:\Apache24\htdocs\filehosting.ru\www\Slim\Extras\Views\Twig.php on line 43

Что это значит? Я уже весь день ебусь с этим слимом и пытаюсь подружить его с твигом и это похоже на танцы с бубном, так как я нихера не понимаю, просто копирую какие-то советы, которые нахожу на stackoverflow.
#144 #571580
Почему у меня код код включает \n , а гугл, мозилла всё лепят в одну строчку?
#145 #571587
>>571539

> Короче, настройки "save 1 1" вполне хватит. (сбрасывать на диск каждую секунду)


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

А чтобы ты знал что искать в этом мануале, объясню. В редисе есть 2 способа сохранения: RDB и AOF.

RDB - это сохранение снапшота (снимка) всей базы в файл. Как сделать снимок многогигабайтного массива данных и сохранить, не останавливая работу редиса? Для этого использется форк. В линукс-системах форк - это операция, которая создает полную копию процесса, то есть выделяется память и все содержимое памяти редиса копируется в нее, и появляется второй процесс-клон первого, который не спеша сбрасывает на диск гигабайты данных. Так как это отдельный процесс, то он никак не мешает редису. Редис блокируется только на время выполнения форка.

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

Разумеется сделать копию огромного объема данных мгновенно нельзя. Но ОС оптимизирует форк, вместо реального копирования она использует copy-on-write ( http://freesource.info/wiki/Texnologii/CopyOnWrite& ), то есть одни и те же страницы памяти отображаются в оба процесса и реально копируются только когда один из них пытается что-то в них поменять. Если редис особо ничего не меняет в памяти, то копирования не происходит, оба процесса работают с одной областью памяти.

После того как произошел форк, процесс-копия записывает данные в файл. Последовательная запись данных на диск - это наиболее эффективный режим его работы и скорость записи может достигать 100-200 Мб/с. Но даже так, на сброс 3 гб данных нужно около 15 секунд.

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

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

Потому снапшоты нельзя делать часто.

И потому в редисе есть второй способ сохранения данных - AOF. AOF значит append only file, то есть файл, данные в котором дописываются только в конец. Почему только в конец? Чтобы ни при какой ситуации не повредить ранее записанные данные и потому что тут опять получается последовательная запись, самый эффективный режим работы магнитных дисков.

Редис пишет в AOF файл все полученные от клиентов команды, например SET key value. При успешном сбросе RDB снапшота на диск лог очищается (так как эти данные есть в снапшоте).

Восстановление данных происходит так. При перезапуске сервера редис сначала читает RDB файл, если он есть, и загружает в память данные из него. Это идет со скоростью чтения диска с файла и время зависит от объема данных. Затем редис читает AOF файл (хранящий изменения с момента последнего снапшота) и проигрывает все эти команды заново. Это тоже фактически по времени упирается в скорость чтения.

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

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

Лог обычно генерирует небольшую нагрузку на диск так как записываются в него только приходящие команды, если одна команда имеет размер 100 байт и идет 10 000 команд в секунду, это 1 Мб/с дискового трафика.

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

Потому у администратора есть большой выбор вариантов сохранения данных:

- отключить RDB/AOF
- использовать только редкий RDB
- использовать RDB + AOF с разными степенями надежности

Также, даю тебе почитать вот такую статью, сделанную разработчиками вконтакте (они тоже пилили свои хранилища наподобие редиса, у них же хайлоад), вдруг что полезного найдешь: https://github.com/vk-com/kphp-kdb/blob/master/docs/ru/DBMS_Storage_Comparison.wiki
#145 #571587
>>571539

> Короче, настройки "save 1 1" вполне хватит. (сбрасывать на диск каждую секунду)


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

А чтобы ты знал что искать в этом мануале, объясню. В редисе есть 2 способа сохранения: RDB и AOF.

RDB - это сохранение снапшота (снимка) всей базы в файл. Как сделать снимок многогигабайтного массива данных и сохранить, не останавливая работу редиса? Для этого использется форк. В линукс-системах форк - это операция, которая создает полную копию процесса, то есть выделяется память и все содержимое памяти редиса копируется в нее, и появляется второй процесс-клон первого, который не спеша сбрасывает на диск гигабайты данных. Так как это отдельный процесс, то он никак не мешает редису. Редис блокируется только на время выполнения форка.

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

Разумеется сделать копию огромного объема данных мгновенно нельзя. Но ОС оптимизирует форк, вместо реального копирования она использует copy-on-write ( http://freesource.info/wiki/Texnologii/CopyOnWrite& ), то есть одни и те же страницы памяти отображаются в оба процесса и реально копируются только когда один из них пытается что-то в них поменять. Если редис особо ничего не меняет в памяти, то копирования не происходит, оба процесса работают с одной областью памяти.

После того как произошел форк, процесс-копия записывает данные в файл. Последовательная запись данных на диск - это наиболее эффективный режим его работы и скорость записи может достигать 100-200 Мб/с. Но даже так, на сброс 3 гб данных нужно около 15 секунд.

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

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

Потому снапшоты нельзя делать часто.

И потому в редисе есть второй способ сохранения данных - AOF. AOF значит append only file, то есть файл, данные в котором дописываются только в конец. Почему только в конец? Чтобы ни при какой ситуации не повредить ранее записанные данные и потому что тут опять получается последовательная запись, самый эффективный режим работы магнитных дисков.

Редис пишет в AOF файл все полученные от клиентов команды, например SET key value. При успешном сбросе RDB снапшота на диск лог очищается (так как эти данные есть в снапшоте).

Восстановление данных происходит так. При перезапуске сервера редис сначала читает RDB файл, если он есть, и загружает в память данные из него. Это идет со скоростью чтения диска с файла и время зависит от объема данных. Затем редис читает AOF файл (хранящий изменения с момента последнего снапшота) и проигрывает все эти команды заново. Это тоже фактически по времени упирается в скорость чтения.

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

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

Лог обычно генерирует небольшую нагрузку на диск так как записываются в него только приходящие команды, если одна команда имеет размер 100 байт и идет 10 000 команд в секунду, это 1 Мб/с дискового трафика.

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

Потому у администратора есть большой выбор вариантов сохранения данных:

- отключить RDB/AOF
- использовать только редкий RDB
- использовать RDB + AOF с разными степенями надежности

Также, даю тебе почитать вот такую статью, сделанную разработчиками вконтакте (они тоже пилили свои хранилища наподобие редиса, у них же хайлоад), вдруг что полезного найдешь: https://github.com/vk-com/kphp-kdb/blob/master/docs/ru/DBMS_Storage_Comparison.wiki
#146 #571601
>>571580
\n для консоли, в html нужно использовать <br> для перевода строки, или просто блочный объект типа параграфа или дива.

>>571577
Давай ссылку на гитхаб, так сложно догадаться, что у тебя в коде.
Для того чтобы слим подцепил твиг, нужен пакет slim/views
https://github.com/slimphp/Slim-Views
В конфиге соответственно нужно передать объект твига в качестве объекта представления.
$app = new Slim\Slim(
array(
'view' => new Slim\Views\Twig(),
));
#147 #571602
>>571539

> Я так думаю, что mysql при запросе where id in (1, 44, 88) берет сначала этот диапазон между min 1 и max 88 (поэтому Range), а потом ходит по полученному промежутку бинарным поиском


По моему, она делает N бинарных поисков. Это будет наверно быстрее.

И ведь между 1 и 44 может быть очень много строк, особенно если индекс не уникальный.

По поводу алгоритма, все выглядит ок.
#148 #571610
>>571539

тут http://dev.mysql.com/doc/refman/5.7/en/explain-output.html#jointype_range написано

> range can be used when a key column is compared to a constant using any of the =, <>, >, >=, <, <=, IS NULL, <=>, BETWEEN, or IN() operators:



заметь что и = тут упомянуто, но возможно это для случаев когда у нас много колоночный индекс и мы ищем по первой его части.
#149 #571612
>>571577

Версия PHP какая? Слим ставил через композер или руками?
#150 #571613
>>571580

Чтобы переносы строк нормально работали и в браузере и в ideone (и в консоли), можно использовать для этого \n, а в начале программы поставить

header("Content-Type: text/plain; charset=utf-8");

Это заставит браузер воспринимать то, что выводит твоя программа, как обычный текст, а не HTML, и уважать переносы строк в нем (так как в языке HTML перенос строки равносилен пробелу).

Иначе перенос строки будет в исходном коде страницы (его можно увидеть нажав Ctrl + U), но на самой странице его не будет.
#151 #571622
>>571612
5.6. Через композер. Вырезал из папки vendor/slim/slim/ папку слима и вставил в корневую директорию сайта, там создал папку Extras/Views, туда вставил содержимое vendor/slim/extras/views, В Twig.php изменил значение public static $twigDirectory на "Twig" (причем нигде не было написано, что это нужно было сделать, даже в репозитории твига. нашел в гугле).
#152 #571626
>>571622

> Вырезал из папки vendor/slim/slim/ папку слима


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

Так что удаляй все что ты напереносил и подключай тот слим что в vendor. для этого тебе достаточно приреквайрить vendor/autoload.php и все остальное подключится само собой. Это по моему в документации Слима написано.

> В Twig.php изменил значение public static $twigDirectory на "Twig" (


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

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


Потому что так нельзя делать. а тот кто написал это в гугле - тот быдллокодер какой-то наверно.
#153 #571629
>>571622

Идея композера в том что ты лишь добавляешь в свой проект compoer.json и после этого любой скачавший твой проект запускает композер и он устанаваливает те же версии библиотек что у тебя.

Обязательно потом покажи свой код на проверку. Я вижу у тебя есть какие-то нездоровые наклонности.
32 Кб, 169x448
#154 #571631
>>571626
>>571629
Ладно, завтра со свежей головой удалю всё к херам и поставлю заново композером. Просто в этой статье написано сделать структуру папок как на пикрелейтеде, вот я и повыдергивал всё из вендора http://code.tutsplus.com/tutorials/rapid-application-prototyping-in-php-using-a-micro-framework--net-21638
#155 #571636
>>571577

Еще вот тут вот https://github.com/codeguy/Slim-Extras написано DEPRECATED то есть проект устарел и не поддерживается.

Тебе надо:

1) разобраться как работает композер, почитать хотя бы пару страниц документации слима, и не делать ничего наугад или по советам из гугла , а все делать осознанно
2) вот более новый проект для твига в Слим: https://github.com/slimphp/Slim-Views#twig
#156 #571639
>>571631

> 2011


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

При установке композером от тебя требуется только прописать стрчку в composer.json и сделать composer install. Ничего копировать не надо. Разберись как это работает.
#158 #571644
>>571631

Алсо Paris и Idiorm мне тоже не нравятся. Почитай например мой урок про паттерны работы с БД - они им плохо соответствуют. У нас в PHP есть только один полноценный ORM - Doctrine 2.

Статью можешь почитать, но тебе придется самому править код под современную ситуацию.
#159 #571647
>>571642

> codedokode created this gist on Mar 8, 2014.


Пусть codedokode будет стыдно
#160 #571674
Задача 12 на JS.

https://ideone.com/K8jt1E

Правильно переделал? Насчет добавления ошибок не уверен, это не проверял пока. И еще у меня цену и калории нужно где-то обнулить, а то неправильно высчитывается при нескольких вызовах, но пока я не придумал где.
#161 #571682
>>571674
Пофиксил неправильные расчеты.
#162 #571683
>>571674

> if (topping == Hamburger.TOPPING_SAUCE) ++this.topping_sause;


Пиши со скобками в 3 строчки, ++ перед именем смотрится как-то непривычно и сбивает с толку. Почему ты экономишь место? У тебя слишком громоздкие функции? Надо значит их разбивать на части, а не пытаться впихнуть как можно больше кода в одну строку.

> if (this.topping_sause >= 2) throw new HamburgerError("Приправа добавлена более 1 раза");


Ты сначала меняешь состояние объекта на недопустимое (выбрано 2 добавки), а потом бросаешь исключение. Лучше бросить исключение, оставив объект в корректном состоянии.

Проверки надо вынести в отдельные функции, например:

this.validateSize(size);

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


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

> throw new HamburgerError(


Не вижу определения этой функции

> this.topping_sause = 0;


Добавки лучше хранить в массиве так как в будущем мы можем добавить новые
.
Методы надо сделать через прототипы. Посмотри какой у тебя гигантский конструктор и как все смешано из-за этого.

> return this.price


Точка с запятой
#163 #571686
>>571613
>>571601
Благодарю! Всё так и есть!
#164 #571727
Читаю Мэтта Зандстру из шапки, очень мутно объясняет паттерны, не очень понятно бывает для чего какой и когда применять, чем именно лучше альтернативных решений. Есть нормальные книги, где это на пальцах разъясняется?
#165 #571737
>>571683

>Методы надо сделать через прототипы. Посмотри какой у тебя гигантский конструктор и как все смешано из-за этого.


this.addTopping => Hamburger.prototype.addTopping
Но что это дает? Пойду перечитывать главу про это, но на леарн.яваскрипт в этом уроке настолько хороший пример, что ничего не понятно. Там просто заменили this. на class.prototype. в том классе, где остальной код и не подлежит изменению, поэтому и непонятно на что это влияет. Но, возможно, в предыдущих уроках этой главы объяснялось. Буду перечитывать.

Расчет цены и калорий уже починил. Правильно или опять не то?

>Проверки надо вынести в отдельные функции, например:


>this.validateSize(size);


Зачем? И почему через this. Сделал, но не пойму зачем.

>Ты сначала меняешь состояние объекта на недопустимое (выбрано 2 добавки), а потом бросаешь исключение. Лучше бросить исключение, оставив объект в корректном состоянии.


А если ввести и вывести? В общем мое решение подойдет?

>>this.topping_sause = 0;


>Добавки лучше хранить в массиве так как в будущем мы можем добавить новые


Пока не дошло как это сделать, но буду думать.

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

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

Пока вариант такой.
https://ideone.com/yUstCm
#165 #571737
>>571683

>Методы надо сделать через прототипы. Посмотри какой у тебя гигантский конструктор и как все смешано из-за этого.


this.addTopping => Hamburger.prototype.addTopping
Но что это дает? Пойду перечитывать главу про это, но на леарн.яваскрипт в этом уроке настолько хороший пример, что ничего не понятно. Там просто заменили this. на class.prototype. в том классе, где остальной код и не подлежит изменению, поэтому и непонятно на что это влияет. Но, возможно, в предыдущих уроках этой главы объяснялось. Буду перечитывать.

Расчет цены и калорий уже починил. Правильно или опять не то?

>Проверки надо вынести в отдельные функции, например:


>this.validateSize(size);


Зачем? И почему через this. Сделал, но не пойму зачем.

>Ты сначала меняешь состояние объекта на недопустимое (выбрано 2 добавки), а потом бросаешь исключение. Лучше бросить исключение, оставив объект в корректном состоянии.


А если ввести и вывести? В общем мое решение подойдет?

>>this.topping_sause = 0;


>Добавки лучше хранить в массиве так как в будущем мы можем добавить новые


Пока не дошло как это сделать, но буду думать.

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

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

Пока вариант такой.
https://ideone.com/yUstCm
123 Кб, 581x584
125 Кб, 581x584
122 Кб, 581x584
149 Кб, 581x584
someApprentice #166 #571740
>>570867

>Ну число ходов нужное кошке чтобы добраться до мышки зависит от расстояния по X и Y. Вопрос, как? Попробуй рассмореть примеры которые я дал и найти зависимость. Не видишь?


Да, теперь я вижу в чем проблема. На вопрос, как количество ходов зависит от расстояния по X и Y мне было сложно ответить, но я нашел решение: Берем наибольшее значение по модулю между разницами расстояний между иксами и игркиками - max(abs(x1 - x2), abs(y1 - y2)); Это так? [spo]Если это так, то это просто ломает мой мозг[/spo]
#167 #571791
Посоны, в общем пилю у себя на денвере обычную форму обратной связи и уже тут возник обосрамс. Почему вместо вывода результата на экран, мне выдают обычный код?

http://pastebin.com/EEBnYTBq
http://pastebin.com/vPz7cwz8
#168 #571834
>>571791
Что именно выдает? Мы не телепаты гадать. Если echo $_POST, то денвер твой php не видит, ставь по-отдельности веб-сервер и php и настраивай через конфиги. Готовые сборки для школьников.
#169 #571880
>>571587

>Редис пишет в AOF файл все полученные от клиентов команды, например SET key value. При успешном сбросе RDB снапшота на диск лог очищается


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

Все это чудесно в теории, но где искать настройки? save единственная, которая упоминается в мануале, потому ее и притащил. Но я уже понял, что она отвечает за RDB, то есть за снапшоты, их не нужно делать часто.
save 900 1 // делаем снимок каждые 15 мин
В документации вижу только ссылку на файл с примерами тысяч настроек https://raw.githubusercontent.com/antirez/redis/2.8/redis.conf
Мне это все читать ради 2-3 строчек, которые мне реально понадобятся?
А нет, пронесло, вроде не так и много, ладно.

>By default Redis does not run as a daemon.


А у меня почему-то запускается автоматически (ставил апт-гетом).
Там они говорят только запускать его руками командой ./redis-server /path/to/redis.conf

>daemonize no


У меня прописано yes.
loglevel notice
logfile /var/log/redis/redis-server.log
dir /var/lib/redis // папка, куда складываются rdb и aof файлы

Нашел наконец-то
appendonly yes // +
appendfilename "appendonly.aof"
appendsync everysec // +
no-appendfsync-on-rewrite yes // +
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

Должно хватить. Был отключен режим appendonly и синхронизацию ставим в everysec. И еще опция no-appendfsync-onrewrite выставить в yes, чтобы лог продолжал вестись даже в момент сброса rdb. Остальное по умолчанию.
А, самое главное забыли
maxmemory 512mb

Я не знаю как быть, у меня на нетбуке всего 2 гигабайта, из них убунту съедает 800mb при запуске, хром еще 300-400.
Как-то можно войти в систему минуя графический интерфейс, как на настоящий сервер, чтобы оно мне не засирало память?
#169 #571880
>>571587

>Редис пишет в AOF файл все полученные от клиентов команды, например SET key value. При успешном сбросе RDB снапшота на диск лог очищается


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

Все это чудесно в теории, но где искать настройки? save единственная, которая упоминается в мануале, потому ее и притащил. Но я уже понял, что она отвечает за RDB, то есть за снапшоты, их не нужно делать часто.
save 900 1 // делаем снимок каждые 15 мин
В документации вижу только ссылку на файл с примерами тысяч настроек https://raw.githubusercontent.com/antirez/redis/2.8/redis.conf
Мне это все читать ради 2-3 строчек, которые мне реально понадобятся?
А нет, пронесло, вроде не так и много, ладно.

>By default Redis does not run as a daemon.


А у меня почему-то запускается автоматически (ставил апт-гетом).
Там они говорят только запускать его руками командой ./redis-server /path/to/redis.conf

>daemonize no


У меня прописано yes.
loglevel notice
logfile /var/log/redis/redis-server.log
dir /var/lib/redis // папка, куда складываются rdb и aof файлы

Нашел наконец-то
appendonly yes // +
appendfilename "appendonly.aof"
appendsync everysec // +
no-appendfsync-on-rewrite yes // +
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

Должно хватить. Был отключен режим appendonly и синхронизацию ставим в everysec. И еще опция no-appendfsync-onrewrite выставить в yes, чтобы лог продолжал вестись даже в момент сброса rdb. Остальное по умолчанию.
А, самое главное забыли
maxmemory 512mb

Я не знаю как быть, у меня на нетбуке всего 2 гигабайта, из них убунту съедает 800mb при запуске, хром еще 300-400.
Как-то можно войти в систему минуя графический интерфейс, как на настоящий сервер, чтобы оно мне не засирало память?
#170 #571900
>>571880

> Как-то можно войти в систему минуя графический интерфейс, как на настоящий сервер, чтобы оно мне не засирало память?


Попробуй sudo telinit 3

Если сработает, надо будет добавить пункт в загрузчик и при загрузке можно будет выбирать.
#172 #571942
>>571900
А какой эффект я должен наблюдать? Ничего не произошло.
Файла /etc/inittab нет.
Это для дебиана наверное, в убунте по-другому.
Прокомментируй это http://igorka.com.ua/2010-04-06/otklyuchit-zagruzku-graficheskogo-rezhima-v-ubuntu-910/
Мужик говорит отредактировать /etc/init/gdm.conf и прописать "and runlevel [5]"
Но это тоже старая статья, там девятая убунту.

Я пока потренируюсь в нано, а то потом не смогу вернуть все назад без гедита и саблайма.
52 Кб, 604x340
#173 #571950
Что делать, если ты просто не можешь?

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

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

Может стоит пропустить этот остаток задач и продолжать учить остальное? Или без этого никуда?

Обидно просто, столько времени проебываю и туплю и в итоге никуда не двигаюсь.
#174 #571953
>>571942
А нет, тоже не работает. Нет такого файла gdm.conf.
Попробую еще такой вариант
http://forum.ubuntu.ru/index.php?topic=99298.msg754852#msg754852
#175 #571958
>>569049 (OP)
Аноны, подскажите плиз по wordpress.

Хочу вывести список пользователей, но не всех, а только тех, у кого стоит галочка в произвольном поле в профиле.

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

Вот данный код: http://pastebin.com/MRX04PMC

Я так понял, что можно сделать нужные мне изменения, путём внесения дополнительных параметров в функцию "get_users()"

Судя по документации: https://codex.wordpress.org/Function_Reference/get_users

Я добавляю meta_key, который у меня называется "test", добавляю значение meta_value, которое равно у меня "1" и добавляю meta_compare, где ставим "=". Если я правильно понял, данная модификация выведет пользователей со значением 1 в произвольном поле профиля пользователя.

Но не получается. Вообще всё перестаёт выводиться: http://pastebin.com/90CYx0wq

Подскажите пожалуйста, что я делаю не так. Или как по другому ещё можно вывести только пользователей со значением 1 в произвольном поле test в профиле?

P.S.: Произвольные поля в профиль добавлял через плагин Types.
#176 #571975
>>571942

sudo init 3

Эффект: графическая оболочка закрывается.

Еще можно попробовать перейти в консоль через Alt + Ctrl + F1 и оттуда выполнить эту команду.

>>571950

Запостить код и попросить подсказку.
#177 #571980
>>571942

Если Убунта перешла на systemd то та статья про upstart уже не актуальна. Вот тут

http://www.freedesktop.org/wiki/Software/systemd/FrequentlyAskedQuestions/
http://www.dynacont.net/documentation/linux/Useful_SystemD_commands/

пишут надо попробовать

systemctl isolate multi-user.target

Технологии в линуксе меняются быстрее чем ты их успеваешь изучить.
83 Кб, 600x600
#178 #571991
>>571975
Числа с прописью

https://ideone.com/DtZfAY

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

Еще, я не понял зачем ты сделал функцию, чтобы вводить ворд1,2,3 снаружи function inclineWord($number, $word1, $word2, $word5 если все равно там постоянно будет "рубль, рубля, рублей", поэтому просто занес эти переменные в функцию и на входе функции оставил только $number.

А также, что делать потом, когда нужно будет превращать числа в словесный вариант?

По сколько правил дохуя, то я подумал посчитать количество символов в числе, а потом для каждого числа сделать свой код, типа "если символов 1, то сделать так, если 2, то так, если 3 то так... Если 7, то так.

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

Калькулятор

https://ideone.com/iFhFA2

Прошу подсказки, вот не знаю, что писать там, по идее мне нужно сделать как-то, чтобы если выпал, допустим, минус, то мне нужно сделать какое-то действие, но как его делать то, если мне доступно только число до минуса, а число после минуса я смогу получить только в следующей итерации.
#179 #571996
>>571980
Все поломалось, пишу с виндовс (((
Отписался в тред линукса, но там хрен дождешься помощи, выручай.

Пытался отключить графику, изменил в /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash" на "text", как советуют здесь
http://forum.ubuntu.ru/index.php?topic=99298.msg754852#msg754852

Сначала все было хорошо, запустил графику startx.
Затем решил вернуть все как было, заменил обратно "text" на "quiet spash"
Теперь после ребута бесконечно запрашивает пароль. Ввожу пароль, на пару секунд черный экран с мигающим курсором, и снова появляется окошко с вводом пароля. Что за дела?
Могу теперь только зайти через виртуальный терминал.

Да, кстати, что меня удивило, когда в первый раз запустился без графики и вызвал startx, запустилась lxde, а не xfce, которой я пользуюсь постоянно. Вдруг это важно.
#180 #571999
Ну и конечно же только в 5 утра читая уже 10 статью я вдруг замечаю в чем смысл этих прототипных методов. А в том блин что они не внутри класса!1!
#181 #572004
В конце этого лета сдуру засел за похапэ, понравилось inb4 говноед, отрицать не буду, ах, да, 24лвл, гуманитарный червь-пидор, ДС. В общем, таки дополз до того уровня, когда можно задумываться о говноработке за копейки, прошел все шаги из ОП-поста.
Плюсом к собственно похапэ имею базовый набор быдловебкодера (цэсэс, аштиэмэль, 3/5.
В общем, два с половиной вопроса:
Первый - филосовский, его можно не читать:1) сильно я проебался, выбрав похапэ? Пишу хорошо, красиво, соблюдаю все гласные и негласные правила, самому нравится, но я не против того, чтобы меня обзывали обезьяно, быдлокодером и т.п., мне лишь бы работа была и платили
2) Что нужно в первую очередь подтянуть, чтобы не краснеть за собеседованиях, в какую сторону развиваться? В общем, что курить дальше?
3) И самое главное - как/чем набить портфолио? Я об этом даже и не задумывался.
#182 #572035
ПОСОНЫ АЙ НИД ХЕЛП!!! Делаю задачку про файлообменник начал делать еще летом, но потом из-за учебы забросил, ЛЕТОМ ВСЕ РАБОТАЛО, при записи данных в базу выдается ошибка SQLSTATE[HY000] [2002] Подключение не установлено, т.к. конечный компьютер отверг запрос на подключение. При этом данные в базу записываются, ошибки в логах базы нет. Я так понял это ошибка связана с PDO?
#183 #572043
>>571577
Та же проблема была с твигом и слимом. При загрузке слима через композер он вообще не подключается хз.
#184 #572049
>>571349
Вот блин, тогда нужно делать по несколько запросов к бд и таблицам. При загрузке файла:
1. Создать юзера в бд. Взять куки и по ним проверить, нет ли в таблице юзеров уже этого юзера с этой кукой и не зареген ли он. Если юзера нет, то сгенерить ему кук и положить его в таблицу.
2. Взять из таблицы юзеров по сгенеренной куке присвоенный ему айди.
3. Передать этот айди в таблицу с файлами в колонку user_id.
4. При отображении файла взять по колонке user_id из таблицы файлов и по id из таблицы юзеров название юзера. Если логин юзера не задан, то писать Анонимус в авторах файла. Тоже с комментами.

Какая-то тормозная жесть выходит.

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

>>571337
нет, я все прекрасно понимаю, мне сама верстка не нравится. Уж поверь мне я начинал с верстки, даже зная один лишь синтакс пхп уже тогда пхп мне нравился гораздо больше, как инстурмент программирования, верстку себе оставьте жалкие дизинеры.
#185 #572059
>>571991
убогий код недоучки, функции хоть освой.
#186 #572080
>>572004
Тут уже сто раз объясняли, что чисто-пхпшники с начальными знаниями никому не нужны. Учи js и просись за еду фулстек-макакой. В портфолио покажи задачи из оппоста - файлообменник и сайт с тестами.
#187 #572081
>>571991
Вот смотри я решил от нехуй делать, и установи нормальное ИДЕ и компилятор, идеон глаза режет.
https://ideone.com/SZoDin
#188 #572082
>>572080
че думаешь два вшивеньких сайта один из которых на микрофреймворке (еще и неизвестно, как написанных) это достаточно для трудоустрйоства?
#189 #572083
>>572059

Я ща расплачусь, не обижай меня, плиз
#190 #572084
>>572081
У меня пхп шторм стоит.

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

Ну и зачем ты все решил, блять, за меня? Может ты и работать за меня планируешь?
#191 #572088
>>572084
решил за тебя, чтобы показать тебе какой ты дурачок)
а вообще хочешь научиться делать сайты - иди и делай сайты, по видео с утюба, по мануалам, все попутно освоишь и не будешь делать таких дурацких ошибок, как повторяющийся код без функций.
sage #192 #572089
>>572035
Вопрос снят, в gite нашел ветку где все работает, теперь осталось только найти отличия.
#193 #572091
>>572088

Ты решил за меня второе задание, но повторяющийся код, как я понял, в первой ссылке, почему ты там не показал как правильно?
#194 #572150
>>572091
php функции за тебя тоже я гуглить должен?
#195 #572190
Зачем мне лефт джойном возвращать ВСЕ таблицы из левой таблицы, если мне нужно только вернуть поля из таблиц, где колонка одной равно колонка другой. Ты что ебанутый? Советует хуйню, лишь бы выебнуться.
#196 #572239
Анон, у меня есть задание написать гостевуху используя mvc и ajax. Вроде несложно, но я где-то кажеться туплю с обработкой ajax-ответа.
Смотри, у меня есть простая страница, на которой отображаються сообщения оставленные посетителями. Форму сообщения я отправляю через ajax. Как мне, без перезагрузки страницы обновить дерево сообщений? Единственное что я придумал, это отдавать обратно массив json, который потом обрабатывать js функцией, отрисовывающей сообщения на странице, но это какое-то сильно умножение сущностей получаеться.
Можешь что-то посоветовать?
#197 #572252
>>572239
Возвращай html жи.
#198 #572255
>>571005
В макдаке работаешь?
мимо-кое-кто
#199 #572259
>>572252
Но ведь неправильно (вроде-бы) формировать в контроллере html и потом его выводить в вьюхе. Меня за такое на собеседовании сразу домой пошлют
#200 #572303
>>572259
Какая разница возвращаешь ты из контроллера целую страницу или часть. Ну и попгугли про разновидности MVC (MVVM, MVP например)
#201 #572307
>>572239
Зашей шаблон прямо в html-код, затем в js подставляй в него переменные.

<script type="text/template" id="myTemplate">
<div class="msg-container">
<div class="msg-author"> {{author}} </div>
<div class="msg-text"> {{text}} </div>
</div>
</script>

Заменяешь плейсхолдеры значениями, полученными из json.
39 Кб, 1175x679
#202 #572336
Мне кажется, что это говнокод какой-то.
#203 #572346
>>572336

> Foo


> строки длиннее 80 символов


> простыня на 25 строк подряд



Интуиция тебя не обманывает
#204 #572349
>>572150
один вопрос, нахуй тогда ты за меня решал второе задание? почему как в случае с первым не подсказал куда смотреть? за то когда прошу показать как правильно делать первое ты мне говоришь гуглить. Ты совсем даун?
39 Кб, 1175x679
#205 #572351
>>572346
а как сделать? создать новый класс, в который поместить работу с этими классами?
#206 #572352
>>572349
какой впечатлительный шкальник. любую работу с повторяющимся кодом ты можешь вынести в функцию finction array($a) {foreach($a as $c){echo $c['d']}}
echo array($kek);
echo array($kek2);
почему я должен такие прописные истины объяснять, и тебе уже говорили, функции юзать вместо повторов, но ты же необучаемый.
#207 #572354
>>572349

Ты можешь пока порешать что-то еще, ОП придет, проверит твои задачи и даст тебе нормальные советы.

По этой >>571991 задаче один из вариантов решения такой:

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

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

Ты можешь попробовать это расписать так: допустим у нас строка 25 + 34 - 17 = . Вот как она обрабатывается

Текущий Символ | результат | накопитель | операция
---------------
2 0 2 ?
5 0 25 ?
+ 25 0 +
3 25 3 +
4 25 34 +
- 59 0 -
1 59 1 -
7 59 17 -
= 42 0 =

Другой вариант: разбить выражение на массив чисел и операций регуляркой и вычислить в цикле.
#207 #572354
>>572349

Ты можешь пока порешать что-то еще, ОП придет, проверит твои задачи и даст тебе нормальные советы.

По этой >>571991 задаче один из вариантов решения такой:

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

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

Ты можешь попробовать это расписать так: допустим у нас строка 25 + 34 - 17 = . Вот как она обрабатывается

Текущий Символ | результат | накопитель | операция
---------------
2 0 2 ?
5 0 25 ?
+ 25 0 +
3 25 3 +
4 25 34 +
- 59 0 -
1 59 1 -
7 59 17 -
= 42 0 =

Другой вариант: разбить выражение на массив чисел и операций регуляркой и вычислить в цикле.
87 Кб, 1200x1600
#208 #572357
>>572352
Хорошо, я необучаемый, я понял о чем ты говоришь, но не совсем понимаю как это применить в своем коде, вот тебе кусок кода где повторяется код. Сделай так, чтобы была функция.

Вот код - https://ideone.com/guLlzx .
#209 #572359
>>572351

Да. Ты можешь сделать высокоуровневый класс-сервис, который будет находиться выше уровня мапперов и вызывать их методы.
46 Кб, 400x533
#210 #572362
>>572354

>если это знак, и мы видим его впервые, запоминаем его


>если же не впервые, то выполняем запомненную ранее операцию



Не совсем понимаю как это реализовать.
Занести знак в виде строчки в переменную? Как его запомнить? И потом использовать.
#211 #572364
>>571996
Вылечился, удалив файл .Xauthority

В общем, вот что у меня получилось с заданием про сервис продажи музыки.
Условие (утонуло где-то в прошлом треде) http://pastebin.com/FJwFWYnZ

Сущности базы: http://pastebin.com/ShT7CjdE

Пока только первый запрос

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


SELECT c1.id, c1.name, c1.release_year, c3.track_base_price, cc.local_track_price FROM content c1
JOIN content c2 ON c1.track_album = c2.id
JOIN content_performer cp ON c1.id = cp.content_id
JOIN performer p ON p.id = cp.performer_id
JOIN category c3 ON c1.category_id = c3.id
LEFT JOIN category_country ON cc.category_id = c3.id
JOIN user u ON cc.country_id = u.country_id
WHERE c.release_year = 2012 OR c.name = 'track_name' OR c2.name = 'album_name'
OR p.artist_full_name LIKE '%name%' OR p.group_name LIKE '%name%' AND u.id = 'user_id'
#212 #572370
>>572364

Чем отличается Tariff от Subscrption? Надо писать комментарии в таких неочевидных местах.

> Audition


Как понять бесплатное, платное это прослушивание если да, то по какому тарифу?

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

> User_subscription


> - expired


Лучше дата начала (и может быть конца). А поле expired по моему избыточное и может быть определено на основе первичных данных.
#213 #572375
>>572370
Тарифом я назвал условия, которые лейбл ставит на свою продукцию. А именно общее кол-во треков, доступных пользователю на бесплатном периоде, лицензионные отчисления, отчисления за бесплатные прослушивания.
Подписка насколько я понимаю относится не к лейблу, а к нашему интернет-магазину, там хранятся типы акаунтов: бесплатный, подписка на опред.кол-во времени (duration).
user_subsription отвечает за историю покупок подписок. Да, наверное лучше хранить дату покупки, и к ней прибавлять длительность покупки.

Вообще я плохо понимаю условие задания, что за отчисления, что за условия.
Сложнее понять условие задачи, чем ее решить. Хотя наверное это всегда так.
#214 #572383
>>572375

Магазин платит лейблу-издателю альбома лицензионные отчисления (роялти) в таких случаях:

- прослушивание трека пользователем (на бесплатном и платном тарифе роялти может быть разными)
- покупка трека пользователем
- покупка альбома пользователем

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

Роялти может зависеть от страны пользователя (так как цена разная, то и роялти может быть разным, например лейбл может согласиться брать меньшее роялти при условии более низкой цены в бедных странах). Также, лейбл может запретить продажу (на уровне категорий по моему) в определенных странах.
#215 #572384
>>572375

Запреты на продажу по странам могут использоваться например для релиза альбома в хорошо и много платящей стране на несколько недель раньше чем в плохо платящей.
#216 #572462
>>572357
https://ideone.com/F239Ru
Решение через ООП, ты какой-то глупый мальчик, желающий привлечь к себе внимание трусиками, как видишь обладательницы мокренькой дырочки могут быть гораздо умнее тебя. Наверное эта мысль тебя унижает и ты решил запостить эту картинку, чтобы самоутвердиться, как и полагается безмозглому шкальнику с перманентным спермотоксикозом и прыщами на ебле.
#217 #572465
>>572462

Тролль уходи
48 Кб, 604x604
#218 #572483
>>572462
лол, мой код по длине будет такой же длины как и твой если я возвращать буду сразу строку, а не переменную со строкой - https://ideone.com/guLlzx

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

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

побежал рыдать в подушку
#219 #572537
Имеет ли смысл оформлять шаблоны в .tpl?
151 Кб, 300x180
#220 #572546
Привет. Можете объяснить, почему в алгоритме сортировки пузырьком нужны именно два цикла for?
И вообще, как компьютер понимает, сколько раз нужно перепроходить массив? Т.е., как я понимаю, внутренний цикл for отвечает за проход по элементам массива, а за что отвечает внешний цикл?
#221 #572553
>>572546
Внешний перебирает все элементы массива. Внутренний "поднимает пузырек" на сколько возможно.
#222 #572568
>>572081

Вот зачем ты пришел сюда самоутверждаться? Смотри, мы меняем в твоем коде выражение, добавив несколько слагаемых, и все перестает работать: https://ideone.com/otEbN4

Тебе еще рано кому-то давать советы. Для начала изучи PHP.
#223 #572573
>>572462

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

Также, switch нельзя использовать так, как ты пытаешься. Попробуем например добавить проверку на 0: https://ideone.com/4AyGnP

Упс. Не работает.

Тебе рано учить других. Тебе самому надо язык изучить сначала. И код выравнивать научиться а то какая-то даунская лестница получается.
#224 #572605
А где у нас изучают веб-дисигн?

Как сделать зачеркнутым только текст, а пробелы оставить?

как не надо делать
#225 #572613
>>572088

>а вообще хочешь научиться делать сайты - иди и делай сайты


А зачем тогда задачки в шапке?
Кстати, вот после этих задач уже можно на джуна идти?
http://archive-ipq-co.narod.ru/i-am-smart.html
https://github.com/codedokode/pasta/blob/master/student-list.md
https://github.com/codedokode/pasta/blob/master/interview-tasks.md
#226 #572622
ОП, мне таки и не ответили, попробую тебя спросить в твоем треде, ты меня уже когда-то выручал:
https://2ch.hk/pr/res/561925.html
164 Кб, 531x750
#227 #572657
12 задача по JS на ООП.
https://ideone.com/fiKf5c

Методы в прототипный стиль переделал.
Добавки перенес в объект.
Проверки сделал по твоему совету отдельными функциями. Они работают, но ведь их нужно вызывать отдельно. Зачем это? Не правильнее ли было сразу при создании класса выдавать ошибки, если они есть, а не проверять их отдельно?
#228 #572739
Друзья.

Хочу изучить какой-нибудь фреймворк. Ибо заебало.

Стоит выбор между:
Zend
Symfony
Yii
Laravel

Больше смотрю в сторону Zend или Symfony (ибо вакансий в моём городе на них больше)

Что посоветуется? Плюсы, минусы. Опыт работы.
#229 #572902
Есть тут те кто обучался по курсам "Специалиста"? Есть различия между 2010 -15 годами? Хорошо учиться по ним?
#230 #572946
>>572902
Был анон которому понравилось. Как по мне так сильно не очень. Все оооооочень растянуто. Дибильные кривляния препода тоже заебывают.
#231 #572956
>>572946
Вроде как рекомендуют все, как полному дауну с нуля подойдет. Совмещая с книжками и документацией думаю оптимальный вариант
#232 #572961
>>572956
Ну и оп-задачки конечно же
#233 #572965
мокрые дырочки this thread
#234 #572979
>>572573
А я его и не учу, я лишь говорю, что он долбоеб и доказываю это практически. Свитчи можно и на елсы заменить.
#235 #572981
>>572613
Мне тоже интересно зачем задачки, если этот долбоеб не может ни в классы ни в функции, да еще и попросил решить вторую задачу после решенной первой. Типичное школобыдло.
25 Кб, 604x340
#236 #572984
>>572979

>доказываю

#237 #572987
>>572613
дебильные вопросы, конечно нет.
>>572568
ебать тебе печет манька, если любой код изменить - он перестает работать, вот это открытие, правда?
36 Кб, 604x403
#238 #572990
>>572981

>тебе уже говорили, функции юзать вместо повторов


>вот тебе кусок кода, покажи как


>пишет ответ на ООП



не устаю с тебя проигрывать
#239 #572995
>>572990
я и показал как, ООП лучше повторов.
98 Кб, 1024x1024
#240 #573009
А PhpStorm-10.0 еще не научились лечить?
#241 #573021
>>572383

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


Ну тогда избавляемся от таблицы tariff, переносим следующие атрибуты в таблицу category_country
- tracks_total (макс.кол-во треков доступно для прослушивания при наличии подписки)
- tracks_total_free (... во время пробного периода)
- track_perday (макс.кол-во прослушиваний одного трека в день)
- track_perday_free (... во время пробного периода)
- purchase_royalty (отчисления за покупки)
- audition_royalty (отчисления за бесплатные прослушивания)

Второй запрос

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


Под "доступными" подразумеваются надо полагать те альбомы и треки, на которые не истек лимит прослушиваний. Те, которые запрещены в данной стране, отсеиваются условием WHERE category_country.available = 'y'.
Прослушивания сохраняются в таблицу audition. Условие для проверки исчерпания лимита прослушиваний будет выглядеть как-то так:
SELECT x FROM content c1
JOIN content c2 ON c1.track_album = c2.id
JOIN category c3 ON c2.category_id = c3.id
JOIN category_country c4 ON c3.id = c4.category_id
JOIN audition a ON c1.id = a.track_id
WHERE (SELECT COUNT(*) FROM audition WHERE user_id = 'uid' AND audition.date = CURDATE()) <
(
IF("проверяем тип подписки" = 'premium',
SELECT c5.track_perday FROM category_country c5 WHERE c3.id = c5.category_id AND c5.country_id=(SELECT country_id FROM user WHERE user_id = 'uid') ),
SELECT c5.track_perday_free FROM category_country c5 WHERE c3.id = c5.category_id AND c5.country_id=(SELECT country_id FROM user WHERE user_id = 'uid') ),
)
AND (то же самое для проверки tracks_total).
Хотя еще не учел длительность подписки.
Короче, это какой-то пздц. Вроде бы ничего сложного, если разбить на мелкие части, но удержать в голове целую картину, все эти связи, таблицы и т.д., немного проблематично.
Я лучше пока вернусь к заданиям попроще.
#241 #573021
>>572383

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


Ну тогда избавляемся от таблицы tariff, переносим следующие атрибуты в таблицу category_country
- tracks_total (макс.кол-во треков доступно для прослушивания при наличии подписки)
- tracks_total_free (... во время пробного периода)
- track_perday (макс.кол-во прослушиваний одного трека в день)
- track_perday_free (... во время пробного периода)
- purchase_royalty (отчисления за покупки)
- audition_royalty (отчисления за бесплатные прослушивания)

Второй запрос

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


Под "доступными" подразумеваются надо полагать те альбомы и треки, на которые не истек лимит прослушиваний. Те, которые запрещены в данной стране, отсеиваются условием WHERE category_country.available = 'y'.
Прослушивания сохраняются в таблицу audition. Условие для проверки исчерпания лимита прослушиваний будет выглядеть как-то так:
SELECT x FROM content c1
JOIN content c2 ON c1.track_album = c2.id
JOIN category c3 ON c2.category_id = c3.id
JOIN category_country c4 ON c3.id = c4.category_id
JOIN audition a ON c1.id = a.track_id
WHERE (SELECT COUNT(*) FROM audition WHERE user_id = 'uid' AND audition.date = CURDATE()) <
(
IF("проверяем тип подписки" = 'premium',
SELECT c5.track_perday FROM category_country c5 WHERE c3.id = c5.category_id AND c5.country_id=(SELECT country_id FROM user WHERE user_id = 'uid') ),
SELECT c5.track_perday_free FROM category_country c5 WHERE c3.id = c5.category_id AND c5.country_id=(SELECT country_id FROM user WHERE user_id = 'uid') ),
)
AND (то же самое для проверки tracks_total).
Хотя еще не учел длительность подписки.
Короче, это какой-то пздц. Вроде бы ничего сложного, если разбить на мелкие части, но удержать в голове целую картину, все эти связи, таблицы и т.д., немного проблематично.
Я лучше пока вернусь к заданиям попроще.
#242 #573036
>>572987

>дебильные вопросы


Почему?
А как понять, когда уже можно идти на джуна?
#243 #573039
>>573021

Мне не очень нравится подзапрос в WHERE, если тебе нужен подзапрос то лучше использовать EXISTS, они как минимум чуть лучше оптимизированы (MySQL не ищет все строки, а просто проверяет их наличие или отсутствие).

И там где c5.country_id =(подзапрос) правильнее наверно сделать JOIN, или вообще на строне приложения заранее выбрать нужное значение.

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


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

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

WHERE (category_id NOT IN (?))
#244 #573040
>>573009
Нет. Да и нахуя он нужен? Изменений мизер + новые баги.
#245 #573154
Аноны, мне пока некогда проверить все, так что решайте пока задачки дальше.

>>573009

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

>>572995

ООП там вообще не нужен.

>>572987

Что ты тут забыл? Если ты действительно бы хотел помочь, ты бы написал полезный ответ, который что-то объясняет. Также, ты сам плохо разбираешься в программировании (это видно из твоего неграмотного кода) и помочь вряд ли мог бы даже если захотел.

Значит ты не хочешь никому помогать, а преследуешь какие-то другие цели.

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

Не надо так делать. У нас медленный тред и никаких горячих споров тут не получится. Я уверен, большиство анонов просто проигнорировали твои посты (что легко проверить, сопоставив число анонов в треде и число отвечающих тебе). Тебе лучше пойти в какой-то другой раздел, где людей больше.
#246 #573180
>>572657

Разумеется, все замечания которые я написал, они не просто так, а имеют какую-то причину.

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

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

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

То есть код должен выглядеть примерно так:

function Hamburger(size, stuffing) {
this.validateSize(size);
this.validateStuffing(stuffing);
...

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

По коду

> this.toppingsArr = {


> toppingSause: 0,


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

this.toppings[Hamb.TOPING_ZZZZ] = true;

Так добавление нового вида добавки не потребует правки кода в этом месте.

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

Почему ты выбрал словарь для хранения добавок, а не обычный массив?

> if (topping == Hamburger.TOPPING_SAUCE) {


> this.toppingsArr.toppingSause++;


> }


> if (topping == Hamburger.TOPPING_MAYO) {


> this.toppingsArr.toppingMayo++;


> }


Тут нужен более обобщенный код, не перечисляющий каждый вид добавки

Далее, функция Hamburger.prototype.addTopping написана неправильно. Вот как она сделана у тебя:

- добавить добавку
- проверить правильность переданных аргументов

А вот как надо:

- проверить правильность переданных аргументов
- добавить добавку

Ты понимаешь в чем разница? Во втором случае при передаче неправильных аргументов объект остается неизменным и в корректном состоянии. В первом случае он переходит в некорректное состояние (то есть число добавок в нем становится больше разрешенного).

Мой вариант лучше защищен от ошибок. Это называется exception safety, безопасность относительно исключений. В моем варианте если объект выбросил исключение, им все равно можно пользоваться так как я гарантирую что он остается в корректном состоянии.

В первом варианте нет exception safety. Если объект выбросил исключение, то им дальше пользоваться нельзя так как не гарантий что он в корректном состоянии.

Я вижу, ты в коде попытался добиться exception safety, вручную сбрасывая число добавок до 1 при ошибке. Но это лишнее усложнение, достаточно просто поставить проверку в начало функции и это будет не нужно.

> Hamburger.prototype.calculateCalories = function () {


Всю эту кучу ифов лучше заменить на словарь, хранящий цену и калорийность разных начинок и добавок. Тогда добавление новых видов добавок потребует лишь добавить константу, элемент с ценой и калориями в словарь и может быть в условие валидации.
#246 #573180
>>572657

Разумеется, все замечания которые я написал, они не просто так, а имеют какую-то причину.

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

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

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

То есть код должен выглядеть примерно так:

function Hamburger(size, stuffing) {
this.validateSize(size);
this.validateStuffing(stuffing);
...

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

По коду

> this.toppingsArr = {


> toppingSause: 0,


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

this.toppings[Hamb.TOPING_ZZZZ] = true;

Так добавление нового вида добавки не потребует правки кода в этом месте.

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

Почему ты выбрал словарь для хранения добавок, а не обычный массив?

> if (topping == Hamburger.TOPPING_SAUCE) {


> this.toppingsArr.toppingSause++;


> }


> if (topping == Hamburger.TOPPING_MAYO) {


> this.toppingsArr.toppingMayo++;


> }


Тут нужен более обобщенный код, не перечисляющий каждый вид добавки

Далее, функция Hamburger.prototype.addTopping написана неправильно. Вот как она сделана у тебя:

- добавить добавку
- проверить правильность переданных аргументов

А вот как надо:

- проверить правильность переданных аргументов
- добавить добавку

Ты понимаешь в чем разница? Во втором случае при передаче неправильных аргументов объект остается неизменным и в корректном состоянии. В первом случае он переходит в некорректное состояние (то есть число добавок в нем становится больше разрешенного).

Мой вариант лучше защищен от ошибок. Это называется exception safety, безопасность относительно исключений. В моем варианте если объект выбросил исключение, им все равно можно пользоваться так как я гарантирую что он остается в корректном состоянии.

В первом варианте нет exception safety. Если объект выбросил исключение, то им дальше пользоваться нельзя так как не гарантий что он в корректном состоянии.

Я вижу, ты в коде попытался добиться exception safety, вручную сбрасывая число добавок до 1 при ошибке. Но это лишнее усложнение, достаточно просто поставить проверку в начало функции и это будет не нужно.

> Hamburger.prototype.calculateCalories = function () {


Всю эту кучу ифов лучше заменить на словарь, хранящий цену и калорийность разных начинок и добавок. Тогда добавление новых видов добавок потребует лишь добавить константу, элемент с ценой и калориями в словарь и может быть в условие валидации.
#247 #573185
Есть один кусок кода, который не могу понять почему неправильно работает. Новичок.
$sql = "SELECT `articul` FROM `h78162_a`.`cash`";;
$query=$mysqli->query($sql);
$row=mysqli_fetch_assoc($query);
$array = array($row);
Почему последняя строка может возвращать лишь один артикул, а не все значения в таблице? То есть возникает массив только с одним значением артикула. Как сделать все значения в массиве?
Если делаю вот так, то выводит все значения
while($row){
echo $row['articul'];}
#248 #573191
>>572622

Все эти усложнения лишь запутывают пользователя и не нужны. Если у тебя у статьи может быть ровно 1 категория, используй категории, если несколько то исплоьзуй теги.

> Например, на автомобильном сайте по типу статьи и по производителю


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

Насчет того как делать URL есть простое правило: 1 страница = 1 URL. не может быть 2 одинаковых страниц с разными URL, не может быть 2 разных страницы с одним URL. Твоя схема навигации должна это учитывать.

Ну и традиционно URL рассматривают как путь по разделам, вроде

/news/politics/some-new.html - раздел новости, подраздел политика, страница новости

Вот мой урок с обзором схем URL на примерах: https://gist.github.com/codedokode/772a4ccc03e41d6b7cba

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


Живой человек вряд ли

> Вроде избавляет от лишних полей в БД, но вместо поиска по varchar будет полнотекстовый индекс и поиск по большим текстовым полям.


Ты мешаешь все в кучу. Какая база данных, мы вроде систему URL проектируем? Проектируй схему URL не оглядываясь на БД, она тут вообще никаким боком не относится.

Схема URL на яндекс-маркете очень адекватная.

> https://market.yandex.ru/product/123456/spec?hid=567839&track=tabs


Сразу все понятно: это продукт с id = 123456, страница характеристик. Дополнительные параметры видимо используются для статистики.

> видишь менюшку сверху? И менюшку справа? Обрати внимание, категории пересекаются, они разных типов. Вот тебе двойная навигация.


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

Если то-то непонятно, задавай конкретные вопросы.
#248 #573191
>>572622

Все эти усложнения лишь запутывают пользователя и не нужны. Если у тебя у статьи может быть ровно 1 категория, используй категории, если несколько то исплоьзуй теги.

> Например, на автомобильном сайте по типу статьи и по производителю


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

Насчет того как делать URL есть простое правило: 1 страница = 1 URL. не может быть 2 одинаковых страниц с разными URL, не может быть 2 разных страницы с одним URL. Твоя схема навигации должна это учитывать.

Ну и традиционно URL рассматривают как путь по разделам, вроде

/news/politics/some-new.html - раздел новости, подраздел политика, страница новости

Вот мой урок с обзором схем URL на примерах: https://gist.github.com/codedokode/772a4ccc03e41d6b7cba

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


Живой человек вряд ли

> Вроде избавляет от лишних полей в БД, но вместо поиска по varchar будет полнотекстовый индекс и поиск по большим текстовым полям.


Ты мешаешь все в кучу. Какая база данных, мы вроде систему URL проектируем? Проектируй схему URL не оглядываясь на БД, она тут вообще никаким боком не относится.

Схема URL на яндекс-маркете очень адекватная.

> https://market.yandex.ru/product/123456/spec?hid=567839&track=tabs


Сразу все понятно: это продукт с id = 123456, страница характеристик. Дополнительные параметры видимо используются для статистики.

> видишь менюшку сверху? И менюшку справа? Обрати внимание, категории пересекаются, они разных типов. Вот тебе двойная навигация.


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

Если то-то непонятно, задавай конкретные вопросы.
#249 #573194
>>572613

Эти задачи надо как минимум показать на проверку и исправить все замечания. Если ты их сделал и не показал то это не считается (даже если код работает), так как никто не видел твой код и не может сказать, усвоил ли ты принципы ООП, MVC или нет.

>>572605

Так же где и обычный дизайн. В британке может?

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


Окружить каждое слово тегами

>>572546

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

>>572537

Не понял вопрос. Ты про расширение файла? Я бы советовал phtml для PHP-шаблонов

>>572483

Твой код по ссылке какой-то запутанный. Зачем там массивы? Эта функция пишется в 2 или 3 ифа:

if (число заканчивается на 2, 3,4 и это не 11-19 ) {
вернуть одну форму слова;
}

if (число заканчивается на 1 и это не 11-19 ) {
вернуть другую форму слова;
}

И так далее.
#249 #573194
>>572613

Эти задачи надо как минимум показать на проверку и исправить все замечания. Если ты их сделал и не показал то это не считается (даже если код работает), так как никто не видел твой код и не может сказать, усвоил ли ты принципы ООП, MVC или нет.

>>572605

Так же где и обычный дизайн. В британке может?

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


Окружить каждое слово тегами

>>572546

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

>>572537

Не понял вопрос. Ты про расширение файла? Я бы советовал phtml для PHP-шаблонов

>>572483

Твой код по ссылке какой-то запутанный. Зачем там массивы? Эта функция пишется в 2 или 3 ифа:

if (число заканчивается на 2, 3,4 и это не 11-19 ) {
вернуть одну форму слова;
}

if (число заканчивается на 1 и это не 11-19 ) {
вернуть другую форму слова;
}

И так далее.
#250 #573209
Анон, который делает счетчик посещений на редис. Есть предложение сделать счетчик отдельной независимой от Юи и (может быть) клиента редиса библиоеткой. Чтобы его можно было подключить к любому проекту через композер. Подробно расписывать пока некогда, потому пишу кратко.

Зачем?

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

Затраты по времени примерно такие:

- создать новый репозиторий = 10 мин
- сделать composer.json = 10 мин
- сделать readme с понятным описанием = 1 час
- рефакторинг кода с вынесением зависимостей = 2 часа
- сделать пример подключения (в качестве документации) = 1час
- подключить к основному проекту сайта объявлений через композер = 10 мин

Конечно хорошая библиотека еще должна быть покрыта тестами, но это требует времени (разобраться с тестами = 6 ч, написать и отладить = 8 ч) и я не знаю, есть ли оно у тебя.

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

>>572483

Это скучающий тролль тебе пишет. Самое лучшее это игнорировать посты с провокациями (их легко определить по стилю текста и попытке разжечь спор) и ждать пока ОП проверит твой код. ну и решать задачки чтобы время зря не тратить.
#250 #573209
Анон, который делает счетчик посещений на редис. Есть предложение сделать счетчик отдельной независимой от Юи и (может быть) клиента редиса библиоеткой. Чтобы его можно было подключить к любому проекту через композер. Подробно расписывать пока некогда, потому пишу кратко.

Зачем?

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

Затраты по времени примерно такие:

- создать новый репозиторий = 10 мин
- сделать composer.json = 10 мин
- сделать readme с понятным описанием = 1 час
- рефакторинг кода с вынесением зависимостей = 2 часа
- сделать пример подключения (в качестве документации) = 1час
- подключить к основному проекту сайта объявлений через композер = 10 мин

Конечно хорошая библиотека еще должна быть покрыта тестами, но это требует времени (разобраться с тестами = 6 ч, написать и отладить = 8 ч) и я не знаю, есть ли оно у тебя.

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

>>572483

Это скучающий тролль тебе пишет. Самое лучшее это игнорировать посты с провокациями (их легко определить по стилю текста и попытке разжечь спор) и ждать пока ОП проверит твой код. ну и решать задачки чтобы время зря не тратить.
#251 #573214
>>571991

> Еще, я не понял зачем ты сделал функцию, чтобы вводить ворд1,2,3 снаружи function inclineWord($number, $word1, $word2, $word5 если все равно там постоянно будет "рубль, рубля, рублей"



А как ты склоняешь другие слова, например «тысяч» и «миллионов»? Еще 2 функции накопипастишь?

В твоей функции слишком сложный код. Склонение слов в русском языке определяется так:

- если число от 11 до 19 или кончается на 5-9 то ...
- иначе если оно кончается на 1 то ..
- иначе оно кончается на 2-4 и ...

То есть реально там 2 или 3 ифа будет, проверябщих последнюю или 2 последних цифры.

Попробуй упростить код.
#252 #573216
>>571991

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



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

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



Можно сделать примерно так:

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

Вот и вся задача.

Собирать фразу (сто двадцать три) из слов удобно, складывая числа в массив.
#253 #573218
>>571740

Да, правильно, максимум из X и Y. Оптимальная траектория кошки такая: двигаемся по диагонали пока не окажемся на одной прямой, затем по прямой.
#254 #573221
>>571727

Нет. ЧТобы понимать паттерны, нужно иметь пример кода где они нужны. Сами по себе их учить бесполезно.

Обычно паттерны стоит изучать либо когда у тебя большой опыт, либо когда ты работаешь с фреймворком и там какие-то из них используются.
#255 #573228
>>573185

Тебе по моему надо сначала язык PHP выучить, циклы.

Ну вот смотри, ты пишешь:

> Если делаю вот так, то выводит все значения


> while($row){


> echo $row['articul'];}


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

Потому я и пишу что тебе сначала наверно надо изучить цикл while, потом почитать документацию по mysqli_fetch_assoc (или например найти хорошую, поодробную статью про mysqli). Если ты это сделаешь то наверно и сам поймешь почему.

Может быть конечно ты знаешь циклы, просто опечатался и там был другой код. Тогда тебе надо почитать учебник или документацию по mysqli. Вот в твоем коде, ты можешь объяснить каждую строчку, что она берет, что делает и что возвращает? как работает функция mysqli_fetch_assoc? Если не знаешь то надо сначала изучить.

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

Ну и еще, ты зачем-то смешиваешь ООП и процедурную версию mysqli.
#256 #573237
>>573191
Ну вот посмотри, как mobile-review сделан. У них есть типы обозреваемых материалов - статьи, обзоры, сравнения и т. д. под каждую отдельный раздел и есть тип обозреваемого материала - андроид, айос, девайсы, телефоны, планшеты... под это в другой менюшке тоже под каждое раздел. Вот такая вот получается двойная навигация, когда я хочу посмотреть все андроид-устройства или только все сравнения и соответственно использую разные менюшки. Или хочу посмотреть все сравнения андроид-устройств (хотя тут уже лучше тегами, наверное)
#257 #573241
>>571727
код нужно не читать, а перепечатывать и смотреть, как работает. у меня месяц на это ушло.
#258 #573290
>>573237

Ну а в чем проблема?

/reviews/ - все обзоры
/reviews/android/ - все обзоры андроида
/all/android/ - все (статьи, обзоры и тд), что относится к андроиду
/reviews/android/some-review - конкретная статья
#259 #573292
>>573241

Зря вы Зандстру целиком перепечатывает. Если у вас мало опыта вы большинство не поймете. Лучше сделайте студентов, файлообменник, сайт на Юи, исправьте все замечания и тогда вам паттерны будут ближе, и может к этому моменту вы даже некоторые будете знать.
#260 #573312
Как работают плейсхолдеры? Делается регулярка типа ^:[a-z0-9]+ и по ней плейсхолдер заменяют на соответствующую переменную?
#261 #573315
Хочу задрочить верстку на практике но не пойму с чего начинать, ну то есть я выучил синтаксис, свойства, все дела. Вот как ставится задача верстале на настоящей работе? Смотрю уроки на ютубе там все берут что-то типа скриншота сайта типа заранее нарисованного дизайнером дальше это особым образом режут в фотошопе ну и поехали сверху вниз каждый кусок заворачивать в теги и применять к ним стили. Это норм практика будет? И где б таких "скриншотов" скачать чтоб не совсем примитив и чтоб современно стильно модно выглядел дизайн.
#262 #573321
>>573290
Ебать, не сделаешь же в меню пункт "все"?
Плюс, категорий каждого типа может быть десяток, это что, сто вариантов в .htaccess прописывать? Вот так, как ты описал - это правда логичнее и правильнее, чем делать две независимые категории?
Может вообще ВСЕ категории сделать на тегах? Просто если к твоему варианту добавить теги, то /tags/android и /all/android по сути будет вести на один и тот же набор материалов, нормально ли это?
#263 #573322
>>573321
Или наоборот принципиально отказываться от тегов типа материала и типа статьи. Например, не будет тега "ноутбуки" или "windows" - это тоже как-то пиздец.
#264 #573323
>>573315
Нарезать в фотошопе не твоя задача. Тебе уже дают PSD файл, а ты делаешь его копию-сайт. В ОП посте есть курс штмл\ксс, выполни все задания и в конце тебя как раз ждет такой PSD файл, по которому ты будешь делать макет сайта.
#265 #573367
Оп, посмотри задачу на jQ UI:
http://plnkr.co/edit/7VYoU4KXe3mKV6G4spjd?p=preview

Не совсем понял что должно происходить при даблклике по названию города в списке. Т.е. мы получаем возможность таким образом отредактировать город, но что это за собой должно повлечь? Трансформацию элемента списка в инпут, который тоже обладает автокомплитом?
Каким образом из списка добавленных городов сделать форму, чтобы ее отправить на сервер? Пока из идей - добавить в конец списка сабмит, и при клике конвертировать жикверей все элементы списка в инпуты, что будет уродливо и наверное неверно.
#266 #573517
>>573312

Ты про плейсхолдеры в PDO? В mysqli? В какой-то другой библиотеке?

Некоторые базы данных поддерживают плейсхолдеры нативно, то есть драйвер посылает отдельно запрос с плейсхолдерами, отдельно данные. Данные в запрос подставляются на стороне базы.

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

Если же база не поддерживает плейсхолдеры, то драйвер на стороне PHP экранирует данные, вставляет в запрос и посылает собранный запрос.

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

В любом случае в PDo можно включить EMULATE_PREPARE и тогда он будет заниматься подстановкой в любом случае.

> Делается регулярка типа ^:[a-z0-9]+


Там код на Си, и он по моему обходится без реглярок, посимвольно анализирует запрос. Ну и данные перед вставкой экранируются.
#267 #573526
>>573315

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

> Вот как ставится задача верстале на настоящей работе?


Бывает дают макет, бывают на словах объясняют («тут надо бы меню покрупнее сделать и чуть вправо сдвинуть»).

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


Нет, неправильный порядок. Сначала ты смотришь на макет и пишешь семантичный (осмысленный) HTML-код, который содержит все основные блоки, текст, праивльно размеченный тегами. А только потом пишешь CSS чтобы этот код выглядел как требуется. И по мере написания подставляешь нарезанные картинки.

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

>>573321

Ты чего злой такой?

> Ебать, не сделаешь же в меню пункт "все"?


А где я написал что его надо сделать?

> Плюс, категорий каждого типа может быть десяток, это что, сто вариантов в .htaccess прописывать?


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

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

> Просто если к твоему варианту добавить теги, то /tags/android и /all/android по сути будет вести на один и тот же набор материалов, нормально ли это?


нет, у одной страницы должен быть один URL, а не два.

> Может вообще ВСЕ категории сделать на тегах?


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

>>573322

Не очень понимаю. ЧТо нам мешает сделать свойства «тип материала» (статья, обзор) и «категория» (андроид, ноутбуки ) и тд? Теги используются когда нужно отнести материал к нескольким категориям. Или ты на вордпресс ориентируешсяь? Тогда надо было так и писать, а не сбивать людей с толку.

>>573323

Нарезать задача верстальщика. Так же как и выбрать оптимальный формат картинок например.
#267 #573526
>>573315

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

> Вот как ставится задача верстале на настоящей работе?


Бывает дают макет, бывают на словах объясняют («тут надо бы меню покрупнее сделать и чуть вправо сдвинуть»).

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


Нет, неправильный порядок. Сначала ты смотришь на макет и пишешь семантичный (осмысленный) HTML-код, который содержит все основные блоки, текст, праивльно размеченный тегами. А только потом пишешь CSS чтобы этот код выглядел как требуется. И по мере написания подставляешь нарезанные картинки.

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

>>573321

Ты чего злой такой?

> Ебать, не сделаешь же в меню пункт "все"?


А где я написал что его надо сделать?

> Плюс, категорий каждого типа может быть десяток, это что, сто вариантов в .htaccess прописывать?


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

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

> Просто если к твоему варианту добавить теги, то /tags/android и /all/android по сути будет вести на один и тот же набор материалов, нормально ли это?


нет, у одной страницы должен быть один URL, а не два.

> Может вообще ВСЕ категории сделать на тегах?


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

>>573322

Не очень понимаю. ЧТо нам мешает сделать свойства «тип материала» (статья, обзор) и «категория» (андроид, ноутбуки ) и тд? Теги используются когда нужно отнести материал к нескольким категориям. Или ты на вордпресс ориентируешсяь? Тогда надо было так и писать, а не сбивать людей с толку.

>>573323

Нарезать задача верстальщика. Так же как и выбрать оптимальный формат картинок например.
#268 #573565
>>573367

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


Хороший вопрос. Можно загружать город в существующий инпут (тогда хорошо бы и менять надпись на кнопке), можно превращать в инпут.

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


Самый простой - к каждому городу добавлять input hidden с его id, а список городов обернуть тегом form.

Замеченные баги:

Шлется дофига запросов (смотри вкладку Network). Например, если очистить поле ввода, то шлется запрос с пустым значением q. Если быстро печатать, то на каждую букву шлется запрос. Так не должно быть. При пустом поле запрос слать не надо, также надо сделать ограничение на частоту отправки запросов, например не чаще раза в 400 мс. Или например если значение поля не менялось в течение 400 мс.

Вываливается слишком много вариантов, больше 20, человек не способен столько прочесть. Ограничься 7-8 значениями.

По коду. Определения функций у тебя зачем-то внесены внутрь $(), зачем? Не надо так делать. Также, у тебя внутри $() гигансткая простыня на 106 строк, функции не должны быть такими огромными. Для начала попробуй вынести вложенные функции наружу.

Сборку HTML-кода для нового города лучше делать не вручную, а с помощью шаблона, размещенного в HTML-коде, как описано тут: https://learn.javascript.ru/templates

Ты не обязан использовать готовый шаблонизатор, можешь написать велосипед на основе String.replace и регулярки. А можешь взять какой-нибудь готовый микрошаблонизатор.

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

Имена функций должны начинаться с глагола и иметь вид сделайЧтоТо. Не NewCityString а например insertNewCity.

Вместо того чтобы вешать обработчик на каждую кнопку закрытия, лучше повесить один обработчик на список через $.on(...). Ты ведь знаешь про всплытие событий?

> google.maps.event.addDomListener(window, 'load', initialize)


не рекомендую использовать событие load . Оно срабатывает после полной загрузки страницы, скриптов, стилей , картинок и достаточно однйо подвисшей картинки чтобы это событие тоже откладывалось на потом. Ты запускаешь свой код по событию DOM ready, может быть это и не требуется? Разберись как работает код гуглокарт и почему там эта строчка.

> new NewCityString(cityName);


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

> $('#city').on('input autocompleteselect', function(e) {


У jQuery UI Autocomplete есть опция где можно указать функцию-коллбек. Перехватывать события в обход нее неправильно. Почитай документацию по этому виджету.

При отправке нового запроса надо отменять старый. Также, при отправке jsonp надо включить кеширование (Jquery.ajax по умолчанию его отключает но тут то случай где оно полезно).

> getCts


Не надо так сокращать, названия должны быть понятными

> var geocoder = new google.maps.Geocoder();


Я думаю, незачем создавать по геокодеру на каждый новый город. Это точно необходимо?

Также, хорошо бы сделать код более разделенным на компоненты и готовым к повторному использованию. Например инпут с выбором города вполне можно сделать как отдельный компонент (например jquery-плагин) так, чтобы его можно было подключить и в других местах. Сейчас у тебя монолитный код, который заточен только под эту задачу и который нельзя повторно использовать.
#268 #573565
>>573367

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


Хороший вопрос. Можно загружать город в существующий инпут (тогда хорошо бы и менять надпись на кнопке), можно превращать в инпут.

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


Самый простой - к каждому городу добавлять input hidden с его id, а список городов обернуть тегом form.

Замеченные баги:

Шлется дофига запросов (смотри вкладку Network). Например, если очистить поле ввода, то шлется запрос с пустым значением q. Если быстро печатать, то на каждую букву шлется запрос. Так не должно быть. При пустом поле запрос слать не надо, также надо сделать ограничение на частоту отправки запросов, например не чаще раза в 400 мс. Или например если значение поля не менялось в течение 400 мс.

Вываливается слишком много вариантов, больше 20, человек не способен столько прочесть. Ограничься 7-8 значениями.

По коду. Определения функций у тебя зачем-то внесены внутрь $(), зачем? Не надо так делать. Также, у тебя внутри $() гигансткая простыня на 106 строк, функции не должны быть такими огромными. Для начала попробуй вынести вложенные функции наружу.

Сборку HTML-кода для нового города лучше делать не вручную, а с помощью шаблона, размещенного в HTML-коде, как описано тут: https://learn.javascript.ru/templates

Ты не обязан использовать готовый шаблонизатор, можешь написать велосипед на основе String.replace и регулярки. А можешь взять какой-нибудь готовый микрошаблонизатор.

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

Имена функций должны начинаться с глагола и иметь вид сделайЧтоТо. Не NewCityString а например insertNewCity.

Вместо того чтобы вешать обработчик на каждую кнопку закрытия, лучше повесить один обработчик на список через $.on(...). Ты ведь знаешь про всплытие событий?

> google.maps.event.addDomListener(window, 'load', initialize)


не рекомендую использовать событие load . Оно срабатывает после полной загрузки страницы, скриптов, стилей , картинок и достаточно однйо подвисшей картинки чтобы это событие тоже откладывалось на потом. Ты запускаешь свой код по событию DOM ready, может быть это и не требуется? Разберись как работает код гуглокарт и почему там эта строчка.

> new NewCityString(cityName);


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

> $('#city').on('input autocompleteselect', function(e) {


У jQuery UI Autocomplete есть опция где можно указать функцию-коллбек. Перехватывать события в обход нее неправильно. Почитай документацию по этому виджету.

При отправке нового запроса надо отменять старый. Также, при отправке jsonp надо включить кеширование (Jquery.ajax по умолчанию его отключает но тут то случай где оно полезно).

> getCts


Не надо так сокращать, названия должны быть понятными

> var geocoder = new google.maps.Geocoder();


Я думаю, незачем создавать по геокодеру на каждый новый город. Это точно необходимо?

Также, хорошо бы сделать код более разделенным на компоненты и готовым к повторному использованию. Например инпут с выбором города вполне можно сделать как отдельный компонент (например jquery-плагин) так, чтобы его можно было подключить и в других местах. Сейчас у тебя монолитный код, который заточен только под эту задачу и который нельзя повторно использовать.
#269 #573567
>>573367

Еще:

> count: 1000


Не будь жадным

> q: $(this).val(),


Стоит еще делать $.trim перед отправкой.
#270 #573593
>>573526
Нене, бро, я не злой, извини, если что-то резко сказал. Нет, не под вордпресс, мне логика всего этого интересна. Хм, переадресация на уровне фреймворка? Так бывает? Ну, красивые урлы, я про них.
#271 #573600
А throw new Error() действует как return? То есть код после него перестает выполняться?
#272 #573601
>>573600

Да. Почитай как работают исключения. После throw управление переходит вверх к ближайшему catch , а если его нет, программа завершается.
#273 #573602
>>573209
Невнимательно прочитал и сначала подумал, что ты хочешь меня заставить написать универсальный клиент-обертку.
Если только команды для счетчика, то это еще ничего.
Я так прикинул, мне понадобятся обертки для шести команд редиса, ну и конфигурация подключения для каждого клиента.
Три класса: один собственно для манипуляций с редисом, второй для работы с mysql, ну и третий для всего остального.

Прям для всех клиентов наверное слишком жирно (их там 13 штук), хватит 3 самых популярных и надежных для начала (Predis, PhpRedis и Rediska). Если грамотно спроектировать, то остальные можно будет потом добавлять по желанию, расширять код кому нужно.

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

Читать дальше http://pastebin.com/BMXGeGka
Вакаба как всегда увидела слово из спам-листа.

О, и пастбин меня заставил вводить капчу.
Your paste has triggered our automatic SPAM detection filter. This happens when links or certain keywords are detected in a paste. It can also happen if you are creating a lot of items in a short period of time. To confirm you are not a bot, please fill out the captcha below.

Может они на домен третьего уровня агрятся? Тест http://rediska.geometria-lab.net/api/0-5-10/index.html
#274 #573608
>>573602

Меня пастебин просит ввести капчу в 100% случаев - видимо IP подозрительный.

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


Нет, универсальную реализацию алгоритма счетчика. Идея такая: мы разбиваем код на 2 части: универсальную (часть A) и относящуюся к конкретному сайту (назовем ее часть B, или адаптер). Что делать с редисом, я окончательно не решил, тут есть 2 варианта:

1) абстрагироваться от конкретной библиотеки-клиента и разрешить любую
2) выбрать одну, например редиску, и работать только с ней

Вариант 1 конечно универсальнее но чуть сложнее.

В универсальной части реализуется сам алгоритм, при это там:

- нет никакого упоминания конкретного сайта или фрйемворка
- нет работы с БД и указания на тип БД (так как ясен пень у каждого сайта она разная, кто-то исплоьзует PDO, кто-то mysqli, кто-то вообще смелый и в MongoDB все хранит)
- (по желанию) нет указания на конкретную библиотеку для работы с редисом

То есть только алгоритм, абстрагированный от всех зависимостей. Он общается с внешним миром (редис, база) через часть B. То есть когда ему надо сбросить данные в БД, он не делает это напрямую, а вызвыает часть B, где есть реализаия этого метода под конкретный сайт с конкретными именами таблиц.

Часть B может быть одним классом, а может не одним. Тут надо подумать как лучше.

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

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

В общем это хорошая возможность поучиться проектировать ООП-библиотеки.

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

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

> Прям для всех клиентов наверное слишком жирно (их там 13 штук)


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

> хватит 3 самых популярных и надежных для начала (Predis, PhpRedis и Rediska)


Если сложно то можно даже меньше.

> Какой-то итератор, какой-то буффер сокета.


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

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

Итератор - это объект для перебора значений какого-то списка. В PHP есть набор встроенных итераторов: http://php.net/manual/ru/class.iterator.php и встроенный интерфейс для них. Любой класс, реализующий этот интерфейс. можно использовать в стандартном цикле foreach для перебора значений итератора.

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

В версии 5.5 добавили генераторы - они позволяют делать примерно то же, но проще, одной функцией, без реализации 6 методов.
#274 #573608
>>573602

Меня пастебин просит ввести капчу в 100% случаев - видимо IP подозрительный.

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


Нет, универсальную реализацию алгоритма счетчика. Идея такая: мы разбиваем код на 2 части: универсальную (часть A) и относящуюся к конкретному сайту (назовем ее часть B, или адаптер). Что делать с редисом, я окончательно не решил, тут есть 2 варианта:

1) абстрагироваться от конкретной библиотеки-клиента и разрешить любую
2) выбрать одну, например редиску, и работать только с ней

Вариант 1 конечно универсальнее но чуть сложнее.

В универсальной части реализуется сам алгоритм, при это там:

- нет никакого упоминания конкретного сайта или фрйемворка
- нет работы с БД и указания на тип БД (так как ясен пень у каждого сайта она разная, кто-то исплоьзует PDO, кто-то mysqli, кто-то вообще смелый и в MongoDB все хранит)
- (по желанию) нет указания на конкретную библиотеку для работы с редисом

То есть только алгоритм, абстрагированный от всех зависимостей. Он общается с внешним миром (редис, база) через часть B. То есть когда ему надо сбросить данные в БД, он не делает это напрямую, а вызвыает часть B, где есть реализаия этого метода под конкретный сайт с конкретными именами таблиц.

Часть B может быть одним классом, а может не одним. Тут надо подумать как лучше.

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

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

В общем это хорошая возможность поучиться проектировать ООП-библиотеки.

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

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

> Прям для всех клиентов наверное слишком жирно (их там 13 штук)


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

> хватит 3 самых популярных и надежных для начала (Predis, PhpRedis и Rediska)


Если сложно то можно даже меньше.

> Какой-то итератор, какой-то буффер сокета.


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

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

Итератор - это объект для перебора значений какого-то списка. В PHP есть набор встроенных итераторов: http://php.net/manual/ru/class.iterator.php и встроенный интерфейс для них. Любой класс, реализующий этот интерфейс. можно использовать в стандартном цикле foreach для перебора значений итератора.

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

В версии 5.5 добавили генераторы - они позволяют делать примерно то же, но проще, одной функцией, без реализации 6 методов.
#275 #573610
>>573602

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

Это конечно бесполезное применение, так как задачу проще решить обычным циклом или рекурсией. В PHP встроены более полезные итераторы, например итератор по файлам в папке, в том числе рекурсивный: http://php.net/manual/ru/class.recursivedirectoryiterator.php

Ну и я написал, итераторы используют для экономии памяти, а еще их используют для абстракции перебора списка. То есть если мы хотим сделать функцию, принимающую на вход какой-то абстрактный список (а не только массив), мы можем указать в тайп-хинте интерфейс Iterator, и она будет работать с любой его реализцией (в том числе ArrayIterator который является оберткой над массивом).
13 Кб, 307x211
#276 #573618
Такое правда могут спросить на собеседовании?
#277 #573622
>>573180

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



Разобрался. Сделал как надо.

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


>Тут нужен более обобщенный код, не перечисляющий каждый вид добавки



Переделал в массив. Если добавляется добавка, она добавляется в массив, а если в массиве уже есть, то выдается ошибка.

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

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



Лучше заменить да, но вот как это использовать? Нужно как-то соединить размер, начинку и добавку с ключами объекта, в котором хранятся калории и цены. Но как это сделать не понимаю. Ведь если делать построчно типа высчитываем цену if (size == x) price +=arr.y.price, то смысл в этом теряется, длина и сложность кода становится еще больше чем с кучей ифов.

https://ideone.com/XWczdX
105 Кб, 916x498
#278 #573626
Охуеть, блять - это говно, а не книга ответов на вопросы с собеседований. Лучше тред почаще читать.
#279 #573627
>>573622

> join(Hamburger.TOPPING_SAUCE);


Это не добавление в массив, почитай про методы массива

https://learn.javascript.ru/array-methods
https://learn.javascript.ru/array

> indexOf(topping)


Этот метод возвращает не true/false а число

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


У тебя уже есть обозначение добавки - константа. Используй ее как ключ объекта.
#280 #573628
>>573626

> Интерфейс это такой же абстрактный класс


дальше можно не читать. Алсо паста

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

Интерфейс это набор требований к классу. «требование» здесь значит требование чтобы в классе был определенный метод.

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

Допустим мы делаем сайт где можно ставить лайки постам и комментам. Допустим у нас есть классы User, Post и Comment.

Вот у нас есть пост и коммент, мы можем увеличить число лайков, допустим методом increaseLikeCount и узнавать сколько у них лайков методом getLikeCount, то есть у них есть что-то общее, но как описать это в коде? Как сказать что эти 2 класса в отличие от других умеют работать с лайками?

Второй пример, мы хотим сделать функцию, которая допустим ставит лайк от определенного пользователя определенному посту или комментарию:

function addLike(User $user, $object) ...

Мы сказали что $user должен быть объектом класса User, а как сказать что $object должен быть классом, умеющим работать с лайками?

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

interface Likeable
{
public function increaseLikeCount( );
public function getLikeCount( );
}

Теперь укажем в коде что посты и комменты можно лайкать:

class Post implements Likeable { ... }
class Comment implements Likeable { ... }

на этом этапе php проверит, не забыли ли мы реализовать в классах упомянутые методы. Если забыли — выдаст ошибку. Как удобно!

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

function addLike(User $user, Likeable $object) { ... }

заметь что благодаря интферйесам наш код стал расиряем. Допустим завтра мы добавим класс Photo который тоже можно лайкать. Если он будет реализовывать интерфейс Likeable то функция вроде addLike сможет работать и с ним без переписывания кода.

В общем интерфейс представляет какую-то способность класса и требует от него реализовать определенные методы.
#280 #573628
>>573626

> Интерфейс это такой же абстрактный класс


дальше можно не читать. Алсо паста

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

Интерфейс это набор требований к классу. «требование» здесь значит требование чтобы в классе был определенный метод.

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

Допустим мы делаем сайт где можно ставить лайки постам и комментам. Допустим у нас есть классы User, Post и Comment.

Вот у нас есть пост и коммент, мы можем увеличить число лайков, допустим методом increaseLikeCount и узнавать сколько у них лайков методом getLikeCount, то есть у них есть что-то общее, но как описать это в коде? Как сказать что эти 2 класса в отличие от других умеют работать с лайками?

Второй пример, мы хотим сделать функцию, которая допустим ставит лайк от определенного пользователя определенному посту или комментарию:

function addLike(User $user, $object) ...

Мы сказали что $user должен быть объектом класса User, а как сказать что $object должен быть классом, умеющим работать с лайками?

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

interface Likeable
{
public function increaseLikeCount( );
public function getLikeCount( );
}

Теперь укажем в коде что посты и комменты можно лайкать:

class Post implements Likeable { ... }
class Comment implements Likeable { ... }

на этом этапе php проверит, не забыли ли мы реализовать в классах упомянутые методы. Если забыли — выдаст ошибку. Как удобно!

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

function addLike(User $user, Likeable $object) { ... }

заметь что благодаря интферйесам наш код стал расиряем. Допустим завтра мы добавим класс Photo который тоже можно лайкать. Если он будет реализовывать интерфейс Likeable то функция вроде addLike сможет работать и с ним без переписывания кода.

В общем интерфейс представляет какую-то способность класса и требует от него реализовать определенные методы.
#281 #573630
>>573036
на джунов-хуюнов делить только быдло, набивающее себе цену. Знать нужно вообще все, тут уже не раз перечисляли, никому не нужны профаны-недоучки, которые только синтаксис освоили и сделали две задачки от опа.
#282 #573631
>>573626
Различия начнешь понимать, если перепечатаешь паттерны из книги в шапке.
#283 #573632
>>572359
Зачем тогда нужен контролллер, если у тебя все классы сводятся и обрабатываются в другом классе?
#284 #573699
С php не так много работал и давно это было, но вот понадобилось написать веб скрапер именно на нём. Посоветуйте, как это лучше всего сделать - мб, есть какой-нибудь удобный фрэймворк для всего этого. Или если такового нету, то чем лучше всего делать большое количество http реквестов?
#285 #573899
Анон, такой вопрос по работе .htaccess: мне надо чтоб все запросы перенаправлялись на индес, поэтому я в .htaccess прописал
RewriteEngine On

RewriteBase /
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteCond %{SCRIPT_FILENAME} !-f

RewriteRule ^(.*)$ index.php?$1 [L,QSA]
однако, при попытке обратиться к, например, несуществующему адресу, меня просто кидает на 404 страницу, не заходя в индекс вообще. Что за хуйня?
#286 #573934
>>573899
А почему тебя должно кидать на индекс? Пропиши перенаправление для 404 ошибки, либо рендери во фреймворке страницу, которая будет выводиться при ошибке.
#287 #573936
Вынес кое-что в классы, так лучше? или надо прямо в методах создавать объекты классов?
#289 #573949
Аноны, можно ли сделать так, чтобы текст в нужно месте красиво всплывал через 5-10 сек, после входа пользователем на сайт? Если да - то как? Я так понял, что как-то через animation, но там сложно что-то(
#290 #574005
>>573949
javascript
#291 #574201
>>573899

Веб-сервер перезапустил? .htaccess в какую папку положил? что в адресной строке браузера?

>>573632

В контроллере остается разбор параметров запроса (GET/POST), вызов шаблона для вывода.

Алсо не забудь код на проверку показать. Я на скриншотах вижу вещи, которые можно сделать лучше. И HTMl кода в контроллере не должно быть.
#292 #574211
Как мне записать массив ошибок $error[0] и тд в условиях? Пример:
if(1 != 1) {
//записываем в массив текст
}
И так несколько условий, а потом вывод в html странице foreach.
#293 #574240
анон, у меня проблема с выборкой из бд. суть в чем: имеется метод для получения строк из БД. ему передаются параметры в качестве условий и исходя из них собирается запрос.

$db = new PDO('mysql:host='.$this->host.';dbname='.$this->dbname.";charset=utf8",$this->user,$this->password);

\t\t\t$conditions = array();

\t\t\t$sql = "SELECT id,rate,login, date, message FROM post";

\t\t\tif(isset($params['column'])&&isset($params['value']))
\t\t\t{
\t\t\t\t$sql = $sql." WHERE ? = ?";
\t\t\t\tarray_push($conditions,$params['column']);
\t\t\t\tarray_push($conditions,$params['value']);
\t\t\t}

\t\t\tif(isset($params['order']))
\t\t\t{
\t\t\t\t$sql = $sql." ORDER BY ?";
\t\t\t\tarray_push($conditions,$params['order']);
\t\t\t\tif(isset($params['desc']))
\t\t\t\t{
\t\t\t\t\t$sql=$sql." ?";
\t\t\t\t\tarray_push($conditions,$params['desc']);
\t\t\t\t}
\t\t\t}

\t\t\t$sth = $db->prepare($sql,array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
\t\t\t$sth->execute($conditions);

так вот, если я передаю пустой массив в качестве параметра, то есть запрос - обычная выборка, то всё норм получается, а если запрос содержит условие, например, для столбца "login" то запрос выполняется, но результат пустой. В чём может быть хуйня?
#293 #574240
анон, у меня проблема с выборкой из бд. суть в чем: имеется метод для получения строк из БД. ему передаются параметры в качестве условий и исходя из них собирается запрос.

$db = new PDO('mysql:host='.$this->host.';dbname='.$this->dbname.";charset=utf8",$this->user,$this->password);

\t\t\t$conditions = array();

\t\t\t$sql = "SELECT id,rate,login, date, message FROM post";

\t\t\tif(isset($params['column'])&&isset($params['value']))
\t\t\t{
\t\t\t\t$sql = $sql." WHERE ? = ?";
\t\t\t\tarray_push($conditions,$params['column']);
\t\t\t\tarray_push($conditions,$params['value']);
\t\t\t}

\t\t\tif(isset($params['order']))
\t\t\t{
\t\t\t\t$sql = $sql." ORDER BY ?";
\t\t\t\tarray_push($conditions,$params['order']);
\t\t\t\tif(isset($params['desc']))
\t\t\t\t{
\t\t\t\t\t$sql=$sql." ?";
\t\t\t\t\tarray_push($conditions,$params['desc']);
\t\t\t\t}
\t\t\t}

\t\t\t$sth = $db->prepare($sql,array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
\t\t\t$sth->execute($conditions);

так вот, если я передаю пустой массив в качестве параметра, то есть запрос - обычная выборка, то всё норм получается, а если запрос содержит условие, например, для столбца "login" то запрос выполняется, но результат пустой. В чём может быть хуйня?
#294 #574243
>>574240
http://codebin.org/view/aa29f59a
вот нормальный код с подсветкой синтаксиса
#295 #574249
>>574240
ну ты поглядел бы какой запрос генерится с параметрами.
#296 #574253
>>574240

PDO::ERRMODE_EXCEPTION включен? Если нет то включи. Может тогда и текст ошибки появится.

также посмотри что за запрос получается.

Также, в этой ситуации лучше использовать плейсхолдеры с именами, а не вопросики, так как с вопросиками проще перепутать число или их порядок. Более того, для сборки запроса по частям есть паттерн Query Builder и библиотеки которые его реализуют (например: Doctrine DBAL). Надо использовать их, а не изобретать велосипед.
#297 #574255
>>574249
SELECT id,rate,login, message FROM post WHERE ? = ?
вот такой запрос передается в execute
#298 #574260
>>573627

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

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

https://ideone.com/nnDZkD
#299 #574262
>>574253
не сгенерило ошибку, запрос потому что сам по себе-то выполняется и не возвращает false
#300 #574266
>>574255

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

Твой запрос превращается в WHERE 'name' = 'Ivan' вместо WHERE name = 'Ivan'

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

В твоем случае имя поля в $params['column'] надо проверять по списку допустимых полей.
#301 #574269
>>574266
а, то есть мне стоит завести массив $names_whitelist и проверять наличие вставляемого имени колонки в нём?
#302 #574271
>>574260

> "BIG": {price: 100, calories: 40},


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

Проверка параметров функции на правильность должна идти самой первой, а не в середине или конце.

> Hamburger.prototype.addTopping


Это надо сделать универсальнее, чтобы добавление 2 новых видов добавок не требовало переделывать код.

> this.pricesAndCalorics[this.toppings].calories;

#303 #574275
>>574260

> this.pricesAndCalorics[this.toppings].calories;


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

Сам код надо чуть переупорядочить так:

- конструктор
- константы
- методы
#304 #574291
>>574271

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



Ну вроде как имеет, это ведь значение константы. Я не понимаю как ее туда записать. Если пытаться вместо "BIG" в ключ записать константу как есть Hamburger.SIZE_BIG то браузер выдает ошибку о том, что точка запрещена, а если обернуть в кавычки или написать просто SIZE_BIG, то это уже не тот ключ, что константа.
#305 #574294
#306 #574299
Как сделать, чтобы при $app->error() рендерился шаблоны с еррором? куда вообще этот $app->error записывается в слиме и ведет?
#307 #574303
>>573608
Набросал пока на скорую руку, зацени
https://github.com/nsdvw/visit-counter/tree/master/src
Базу потом сделаю, сегодня устал, не привык так много работать. Пока только PDO.
#308 #574305
Я так понимаю, нужно вот это прописать вначале,
$app->error(function (\Exception $e) use ($app) {
$app->render('error.php');
});
а потом просто вызывать метод $app->error(); на случай ошибки и исключения через ифы? и оно автоматом на еррор.пхп перенаправится? просто не могу ща проверить.
#309 #574307
>>574291
define("GREETING", "Hello you.", true);
echo GREETING; // outputs "Hello you."
echo Greeting; // outputs "Hello you."
#310 #574308
>>574255

>WHERE ? = ?


чот кекнул (?_?)
#311 #574327
https://github.com/nsdvw/file-sharing
слушай, где ты учился так каждый пиксель высчитывать, сепараторы с директориями добавлять и байты в степень возводить. шарага какая-то?
#312 #574331
>>574291

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

>>574299

http://docs.slimframework.com/errors/500/

Эта функция либо вызвает либо задает обработчик PHP-ошибок.

>>574303

> https://github.com/nsdvw/visit-counter/blob/master/src/VisitCounter.php#L20


Вот это плохо место. У твоего класса есть зависимость - клиент редис. Вместо того чтобы использовать одобренный архитекторами принцип DI ( https://gist.github.com/codedokode/e1d31a31b37d5f635057 ) ты сам создаешь эту зависимость прямо в конструкторе. Вот к чему это приводит (помни что пользователь твоей библиотеки не может править ее код: у него нет доступа к твоему гитхабу):

- пользователь твоей библиотеки не может добавить поддержку нового драйвера редиса сам
- пользователь твоей библиотеки не может подсунуть свой драйвер. Например он написал свой класс, унаследовав его от Rediska и добавив туда какие-то полезные функции (например логгирование запросов). Он не может использовать свой класс с твоей библиотекой.
- твоя библиотека создает новое соединение с редисом а не использует существующее
- пользователь твоей библиотеки не может вызывать какие-то методы у объекта драйвера редиса, так как он хранится в protected поле.
- ну и код выглядит плохо на мой взгляд. Твой класс кроме подсчета посещений занимается какими-то побочными вещами вроде создания клиента редиса

Все эти проблемы решаются использованием DI, то есть объект драйвера передается в конструктор.

В качестве драйвера БД используется только PDO?

> const PER_TRANSACTION = 1000;


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

> $keyPrefix = 'visitCounter'


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

> public function appendToQueue($pageID, $userIP, $expire = 0, $keyValue = '')


Во-первых, это странный метод который выдет наружу реализацию очереди. По моему он должен называться «учесть посещение» а не «добавить в очередь». Во-вторых, почему в него передаются 2 послежних параметра? Почему я чтобы учесть просмотр страницы, должен передавать expire и keyValue? Не вижу логики.

Насчет адаптеров редиса. Во-первых их надо переименовать, желательно добавив слово «адаптер». Во-вторых, они должны быть объединены либо абстрактным классом либо интерфейсом. Вот представь что я хочу написать новый адаптер. Где список требований которые я должен реализовать?

> https://github.com/nsdvw/visit-counter/blob/master/src/VisitCounter.php#L69


> $sql = "UPDATE $tblName SET $columnName = $columnName + $count


Предлагаю попробовать абстрагироваться от базы данных. Давай просто представим что у нас есть некое абстрактное хранилище, а как оно реализовано - mySQL, PostgreSQL, MongoDB, текстовый файлик - не наша проблема. Может быть класс станет универсальнее.
#312 #574331
>>574291

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

>>574299

http://docs.slimframework.com/errors/500/

Эта функция либо вызвает либо задает обработчик PHP-ошибок.

>>574303

> https://github.com/nsdvw/visit-counter/blob/master/src/VisitCounter.php#L20


Вот это плохо место. У твоего класса есть зависимость - клиент редис. Вместо того чтобы использовать одобренный архитекторами принцип DI ( https://gist.github.com/codedokode/e1d31a31b37d5f635057 ) ты сам создаешь эту зависимость прямо в конструкторе. Вот к чему это приводит (помни что пользователь твоей библиотеки не может править ее код: у него нет доступа к твоему гитхабу):

- пользователь твоей библиотеки не может добавить поддержку нового драйвера редиса сам
- пользователь твоей библиотеки не может подсунуть свой драйвер. Например он написал свой класс, унаследовав его от Rediska и добавив туда какие-то полезные функции (например логгирование запросов). Он не может использовать свой класс с твоей библиотекой.
- твоя библиотека создает новое соединение с редисом а не использует существующее
- пользователь твоей библиотеки не может вызывать какие-то методы у объекта драйвера редиса, так как он хранится в protected поле.
- ну и код выглядит плохо на мой взгляд. Твой класс кроме подсчета посещений занимается какими-то побочными вещами вроде создания клиента редиса

Все эти проблемы решаются использованием DI, то есть объект драйвера передается в конструктор.

В качестве драйвера БД используется только PDO?

> const PER_TRANSACTION = 1000;


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

> $keyPrefix = 'visitCounter'


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

> public function appendToQueue($pageID, $userIP, $expire = 0, $keyValue = '')


Во-первых, это странный метод который выдет наружу реализацию очереди. По моему он должен называться «учесть посещение» а не «добавить в очередь». Во-вторых, почему в него передаются 2 послежних параметра? Почему я чтобы учесть просмотр страницы, должен передавать expire и keyValue? Не вижу логики.

Насчет адаптеров редиса. Во-первых их надо переименовать, желательно добавив слово «адаптер». Во-вторых, они должны быть объединены либо абстрактным классом либо интерфейсом. Вот представь что я хочу написать новый адаптер. Где список требований которые я должен реализовать?

> https://github.com/nsdvw/visit-counter/blob/master/src/VisitCounter.php#L69


> $sql = "UPDATE $tblName SET $columnName = $columnName + $count


Предлагаю попробовать абстрагироваться от базы данных. Давай просто представим что у нас есть некое абстрактное хранилище, а как оно реализовано - mySQL, PostgreSQL, MongoDB, текстовый файлик - не наша проблема. Может быть класс станет универсальнее.
#313 #574335
>>574303

> https://github.com/nsdvw/visit-counter/blob/master/src/RedisClient.php#L9


> public function __construct($options)


Это плохое решение так как этот конструктор тут не нужен. зачем конструктор абстрактному классу? Плюс, ты все равно не можешь заставить его вызывать. Лучше просто убери его вместе с функией setInstance.
#314 #574343
>>574305

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

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

Если ты не разбираешьяс в исключениях на 100% то сначала прочти по ним урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a
#315 #574362
>>574303

Ну и немножечко информации для расширения кругозора. Почему нам приходится писать адаптеры под редис клиенты и драйверы БД? потому что в мире PHP много драйверов БД и клиентов редиса. PRO, mysqli, + встроенные в фреймворки обертки над ними.

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

Аналогичная ситуация и с другими компонентами, например каждый фреймворк изобретает свои классы для работы с кешем, логгирования, хранения информации о GET/POST переменных (класс Request).

В противоположность PHP, в некоторых других языках такие стандарты есть. В Яве есть JDBC (чем-то напоминает PDO), https://en.wikipedia.org/wiki/Java_Database_Connectivity , первоначально это была сторонняя библиотека, но потом на ее основе сделали стандарт JSR 54.

В Питоне есть PEP 0249 который описывает интерфейс драйвера для работы с БД: https://www.python.org/dev/peps/pep-0249/

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

В PHP аналогичный процесс, увы, только начинается. У нас пока только есть спецификации на логгер: http://www.php-fig.org/psr/psr-3/ и на информацию о HTTP запросе/ответе: http://www.php-fig.org/psr/psr-7/

И еще в разработке PSR-6 определяющий интерфейс для кеша и интерфейс для DI контейнеров.

Соответственно, если например тебе где-то понадобится логгер, лучше всего предпочесть PSR-3 совместимый интерйфес - тогда любая совместимая библиотека сможет работать с твоим кодом.
#316 #574447
>>574271
>>574275

>> "BIG": {price: 100, calories: 40},


>И где тут константа, я не вижу?



Теперь видно. Иные способы добавления элементов в объект я как-то не учел сразу.

>Проверка параметров функции на правильность должна идти самой первой, а не в середине или конце.



Понял, логично, переделал во всех местах.

>> Hamburger.prototype.addTopping


>Это надо сделать универсальнее, чтобы добавление 2 новых видов добавок не требовало переделывать код.



Я так понял заменить индивидуальные ошибки на одну общую. Сделано. Теперь при введении новых добавок код трогать не потребуется.

>>this.pricesAndCalorics[this.toppings].calories;


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



Упростил как-то мутно по-моему через переменную.

>Сам код надо чуть переупорядочить...



Готово.

Я еще думаю, что можно сделать отдельные массивы, хранящие размеры\начинки\добавки чтобы укоротить код в валидаторах, ведь если ввести много новых по длине кода это будет выгоднее.
#316 #574447
>>574271
>>574275

>> "BIG": {price: 100, calories: 40},


>И где тут константа, я не вижу?



Теперь видно. Иные способы добавления элементов в объект я как-то не учел сразу.

>Проверка параметров функции на правильность должна идти самой первой, а не в середине или конце.



Понял, логично, переделал во всех местах.

>> Hamburger.prototype.addTopping


>Это надо сделать универсальнее, чтобы добавление 2 новых видов добавок не требовало переделывать код.



Я так понял заменить индивидуальные ошибки на одну общую. Сделано. Теперь при введении новых добавок код трогать не потребуется.

>>this.pricesAndCalorics[this.toppings].calories;


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



Упростил как-то мутно по-моему через переменную.

>Сам код надо чуть переупорядочить...



Готово.

Я еще думаю, что можно сделать отдельные массивы, хранящие размеры\начинки\добавки чтобы укоротить код в валидаторах, ведь если ввести много новых по длине кода это будет выгоднее.
#318 #574481
>>574343
трай кэтч эксепшн я знаю, и фроу нью эксепшн знаю, непонятно, куда это все "логируется" и что выводится в случае ошибки на экран - пустота?_?.
#319 #574482
А вы вообще заметили, какой ОП высокомерный пидорас в этом треде. ТЫ НЕ РАЗБИРАЕШЬСЯ, да еще и ЕСЛИ. И тут же кидает две строчки на гитхабе с прогнившим, заржавевшим старым кодом, примеры которого я уже раз пяцот видел. Еще и с таким высокомерным видом, будто этот пидр галактику открыл. Наверное это единственный способ поиметь моральную компенсацию за то, что этот лах тратит тут свое время на огромные полотна, адресованные школоте.
332 Кб, 1262x2222
someApprentice #320 #574491
Все, исправил все:

https://github.com/someApprentice/Cat-and-Mouse

Несколько вопросов:

Когда срабатывает исключение https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Mouse.php#L88 выдается ошибка:

>Fatal error: Uncaught exception 'Exception' with message ' - They Die ~((‡> <br>' in C:\Program Files\xampp\www\Classes\Mouse.php:88 Stack trace: #0 C:\Program Files\xampp\www\index.php(30): Mouse->move() #1 {main} thrown in C:\Program Files\xampp\www\Classes\Mouse.php on line 88



Погуглив я узнал что это из-за отсутствия конструкции try\catch, но ты по моему говорил что можно без нее обойтись. Как тут поступить?

https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Mouse.php#L20
https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Mouse.php#L25
Как сокращать такие длинные условия?

>>574482
Зависть - плохое чувство.
#321 #574494
>>574491

Исключение говорит об ошибке в твоей программе (попытка сходить мертвым животным). Следовательно ловить его не нужно. Нужно исправить ошибку.
#322 #574503
Не понимаю как происходить отправка формы через метод post. При субмите автоматически помещаются значения всех инпутов, текстэрий и тд в массив пост? А если я поместил несколько инпутов в таблицу внутри формы, как мне их передать?
#323 #574566
А у вас конфы нет?
И вы не помогаете на счёт гита?
Никак не могу с ним разобраться, а везде меня игнорируют.
#324 #574593
>>574566

помогаем

>>574503

Данные не идут напрямую в _POST. Ты все путаешь.

https://webref.ru/html/form
http://htmlbook.ru/samhtml5/formy/otpravka-dannykh-formy

Браузер при отправке собирает данные из всех полей внтури формы в виде пар element_name=element_value, и в случае POST отправляет в теле HTTP-запроса на сервер.

А вот уже на сервере, когда запусается PHP скрипт, он читает поступившие теле запроса данные, анализирует их и заполняет массив _POST/_GET.

http://php.net/manual/ru/language.variables.external.php

Тебе бы стоило почитать где-нибудь про протокол HTTP (не знаю правда хорошей статьи).

> А если я поместил несколько инпутов в таблицу внутри формы, как мне их передать?


Не понял этот вопрос. А как таблица влияет на возможность передавать данные форм?

Или ты имеешь в виду что у них одинаковые имена? Это конечно плохо.

Тогда надо использовать массивы в POST: http://php.net/manual/ru/faq.html.php#faq.html.arrays
#324 #574593
>>574566

помогаем

>>574503

Данные не идут напрямую в _POST. Ты все путаешь.

https://webref.ru/html/form
http://htmlbook.ru/samhtml5/formy/otpravka-dannykh-formy

Браузер при отправке собирает данные из всех полей внтури формы в виде пар element_name=element_value, и в случае POST отправляет в теле HTTP-запроса на сервер.

А вот уже на сервере, когда запусается PHP скрипт, он читает поступившие теле запроса данные, анализирует их и заполняет массив _POST/_GET.

http://php.net/manual/ru/language.variables.external.php

Тебе бы стоило почитать где-нибудь про протокол HTTP (не знаю правда хорошей статьи).

> А если я поместил несколько инпутов в таблицу внутри формы, как мне их передать?


Не понял этот вопрос. А как таблица влияет на возможность передавать данные форм?

Или ты имеешь в виду что у них одинаковые имена? Это конечно плохо.

Тогда надо использовать массивы в POST: http://php.net/manual/ru/faq.html.php#faq.html.arrays
#325 #574699
>>574331

>keyPrefix ... надо ли это значение передавать через конструктор или же лучше сделать метод-сеттер? В чем разница между этими вариантами?


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

Про DI читал в теории, но без практических примеров не понимал применения. Теперь (кажется) разобрался.
Переписал код. Добавил адаптер для объекта соединения с базой.

>Почему я чтобы учесть просмотр страницы, должен передавать expire и keyValue?


Expire вынес в конфиг адаптера редиса. keyValue убрал. Насчет значения ключа, то я подумал, что в дальнейшем код можно будет расширить, и он будет учитывать не только уникальные посещения, но и кол-во посещений данным юзером. Например 'VisitCounter:123:127.0.0.1'=>7.
Впрочем, я пока не думал, как это реализовать, так что лучше не забегать вперед, и добавить параметр, когда он реально понадобится.
Хорошо, пока удалил его. Кстати, заметил что гитхаб съедает слова, начинающиеся со значка $ в комментариях. Вот я сделал коммит с комментарием "Remove $value parameter from considerVisit method". Слово $value пропало, наверное это связано с особенностями баша, там же тоже переменные начинаются с доллара?

Ну в общем вторая попытка. Давай я на словах опишу что я пытался натворить.

В глобальном коде теперь необходимо перед созданием собственно объекта счетчика создать и настроить все его зависимости: клиент редиса, адаптер редиса, объект соединения с базой, адаптер базы.
Это должно выглядеть так:
$rediska = new Rediska($options);
$redisAdapter = new VisitCounter\RediskaAdapter($rediska, array('keyPrefix'=>'VisitCounter', 'keyExpire'=>3600x24x30);
$pdo = new PDO($dsn, $user, $pass);
$dbAdapter = new VisitCounter\PdoAdapter($pdo, array('pk'=>'id', 'tblName'=>'ad', 'colName'=>'visitCounter'));
$visitCounter = new VisitCounter\VisitCounter($redisAdapter);
$visitCounter->setDb($dbAdapter); // подключение нужно не всегда, например для обновления счетчика в редисе оно не нужно

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

Так вот, система классов теперь выглядит так: есть основной класс VisitCounter. У него есть зависимости от базы данных и от клиента редиса. Даем ему объекты-адаптеры для редиса и для базы. У объектов-адаптеров в свою очередь зависимость от нативных объектов (rediska и pdo например).
Все адаптеры должны иметь одинаковый интерфейс (собственно я сделал абстрактный класс). У класса RedisAdapter есть несколько абстрактных методов, которые должен реализовать программист, который хочет расширить этот класс и написать адаптер для конкретного клиента (например PhpRedis).
У класса DbAdapter есть один абстрактный метод save, который нужно реализовать.

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

https://github.com/nsdvw/visit-counter/tree/master/src
#325 #574699
>>574331

>keyPrefix ... надо ли это значение передавать через конструктор или же лучше сделать метод-сеттер? В чем разница между этими вариантами?


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

Про DI читал в теории, но без практических примеров не понимал применения. Теперь (кажется) разобрался.
Переписал код. Добавил адаптер для объекта соединения с базой.

>Почему я чтобы учесть просмотр страницы, должен передавать expire и keyValue?


Expire вынес в конфиг адаптера редиса. keyValue убрал. Насчет значения ключа, то я подумал, что в дальнейшем код можно будет расширить, и он будет учитывать не только уникальные посещения, но и кол-во посещений данным юзером. Например 'VisitCounter:123:127.0.0.1'=>7.
Впрочем, я пока не думал, как это реализовать, так что лучше не забегать вперед, и добавить параметр, когда он реально понадобится.
Хорошо, пока удалил его. Кстати, заметил что гитхаб съедает слова, начинающиеся со значка $ в комментариях. Вот я сделал коммит с комментарием "Remove $value parameter from considerVisit method". Слово $value пропало, наверное это связано с особенностями баша, там же тоже переменные начинаются с доллара?

Ну в общем вторая попытка. Давай я на словах опишу что я пытался натворить.

В глобальном коде теперь необходимо перед созданием собственно объекта счетчика создать и настроить все его зависимости: клиент редиса, адаптер редиса, объект соединения с базой, адаптер базы.
Это должно выглядеть так:
$rediska = new Rediska($options);
$redisAdapter = new VisitCounter\RediskaAdapter($rediska, array('keyPrefix'=>'VisitCounter', 'keyExpire'=>3600x24x30);
$pdo = new PDO($dsn, $user, $pass);
$dbAdapter = new VisitCounter\PdoAdapter($pdo, array('pk'=>'id', 'tblName'=>'ad', 'colName'=>'visitCounter'));
$visitCounter = new VisitCounter\VisitCounter($redisAdapter);
$visitCounter->setDb($dbAdapter); // подключение нужно не всегда, например для обновления счетчика в редисе оно не нужно

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

Так вот, система классов теперь выглядит так: есть основной класс VisitCounter. У него есть зависимости от базы данных и от клиента редиса. Даем ему объекты-адаптеры для редиса и для базы. У объектов-адаптеров в свою очередь зависимость от нативных объектов (rediska и pdo например).
Все адаптеры должны иметь одинаковый интерфейс (собственно я сделал абстрактный класс). У класса RedisAdapter есть несколько абстрактных методов, которые должен реализовать программист, который хочет расширить этот класс и написать адаптер для конкретного клиента (например PhpRedis).
У класса DbAdapter есть один абстрактный метод save, который нужно реализовать.

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

https://github.com/nsdvw/visit-counter/tree/master/src
#326 #574729
>>574699

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



Хотя ты и прав, но я имел в виду не это. Вряд ли эту настройку надо будет менять после создания объекта. Более того, в случае ее смены по ходу дела объект скорее всего может работать некорректно.

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

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

Потому ты должен подумать что ты хочешь сделать обязательным а что нет.

И я не говорил кстати что тут надо использовать сеттер. Лишь предложил подумать.

> Вот я сделал коммит с комментарием "Remove $value parameter from considerVisit method". Слово $value пропало, наверное это связано с особенностями баша, там же тоже переменные начинаются с доллара?


Ты уверен что это гитхаб съел а не баш у тебя? Проверить можно добавив echo перед комадой, например

echo git commit ....

И стоит брать сообщение в одиночные кавычки. Тогда переменные там не подставляются.

> $redisAdapter = new VisitCounter\RediskaAdapter($rediska, array('keyPrefix'=>'VisitCounter', 'keyExpire'=>3600x24x30);


Почему префикс и срок хранения - свойства адаптера? Эти настройки применимы только к редиске или к любому драйверу редиса? Какие у тебя аргументы за помещение их в адаптер?

> Много кода, некрасиво как-то.


Нормально. Зато мы получаем универсальную библиотеку. Любой может дописать свои адаптеры.

А дальше пользователь может например поместить этот код в функцию. Или прописать в DI контейнер своего фреймворка. Или унаследовать твой класс и в нем жестко вписать зависимости. Главное, что DI дает нам свободу выбора.

В Сифмони например никто не пишет эти new, а прописывают классы и зависимости в конфиг DI контейнера и создают через

$container->get('visitCounter');

> я еще толком не разобрался с самим DI


DI это когда зависимости передают снаружи: через конструктор, сеттер, и странный способ под названием interface injection. Сами способы описаны например у Фаулера в довольно большой и непростой статье: http://www.martinfowler.com/articles/injection.html#FormsOfDependencyInjection

Я уверен что ты и раньше применял DI может быть не зная об этом. Например передавая объект PDO в класс работы с БД TableGateway.

> Все адаптеры должны иметь одинаковый интерфейс (собственно я сделал абстрактный класс)


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

> У класса DbAdapter есть один абстрактный метод save, который нужно реализовать.


Можно еще назвать его вроде StorageAdapter чтобы не говорить что нам нужна именно БД. Хотя это будет путать людей наверно.

> if ($this->client->exists($uniqueVisit)) return;


> $this->client->set($uniqueVisit, $keyValue, $this->client->keyExpire);


Это не атомарное действие. Другой процесс может успеть добавить ключ после того как мы сделали exists но до того как мы выполнили set. Можно ли сделать это (проверка + установка) атомарно без сильного усложнения кода и больших затрат времени?

> foreach (array_count_values($data) as $key => $value) {


Нужно переименовать все 3 переменных. $data должно называться напимер visitsByObjectId или objectIds в зависимости от того что оно там хранит.

В конструктор надо добавить минимальную проверку значений (1 if + throw достаточно).

Также в адаптере редиса аж 6 (!) методов. Нельзя ли уменьшить их число без усложнения кода и затрат времени? Может абстрагироваться как-то. Может конечно и не стоит.
#326 #574729
>>574699

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



Хотя ты и прав, но я имел в виду не это. Вряд ли эту настройку надо будет менять после создания объекта. Более того, в случае ее смены по ходу дела объект скорее всего может работать некорректно.

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

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

Потому ты должен подумать что ты хочешь сделать обязательным а что нет.

И я не говорил кстати что тут надо использовать сеттер. Лишь предложил подумать.

> Вот я сделал коммит с комментарием "Remove $value parameter from considerVisit method". Слово $value пропало, наверное это связано с особенностями баша, там же тоже переменные начинаются с доллара?


Ты уверен что это гитхаб съел а не баш у тебя? Проверить можно добавив echo перед комадой, например

echo git commit ....

И стоит брать сообщение в одиночные кавычки. Тогда переменные там не подставляются.

> $redisAdapter = new VisitCounter\RediskaAdapter($rediska, array('keyPrefix'=>'VisitCounter', 'keyExpire'=>3600x24x30);


Почему префикс и срок хранения - свойства адаптера? Эти настройки применимы только к редиске или к любому драйверу редиса? Какие у тебя аргументы за помещение их в адаптер?

> Много кода, некрасиво как-то.


Нормально. Зато мы получаем универсальную библиотеку. Любой может дописать свои адаптеры.

А дальше пользователь может например поместить этот код в функцию. Или прописать в DI контейнер своего фреймворка. Или унаследовать твой класс и в нем жестко вписать зависимости. Главное, что DI дает нам свободу выбора.

В Сифмони например никто не пишет эти new, а прописывают классы и зависимости в конфиг DI контейнера и создают через

$container->get('visitCounter');

> я еще толком не разобрался с самим DI


DI это когда зависимости передают снаружи: через конструктор, сеттер, и странный способ под названием interface injection. Сами способы описаны например у Фаулера в довольно большой и непростой статье: http://www.martinfowler.com/articles/injection.html#FormsOfDependencyInjection

Я уверен что ты и раньше применял DI может быть не зная об этом. Например передавая объект PDO в класс работы с БД TableGateway.

> Все адаптеры должны иметь одинаковый интерфейс (собственно я сделал абстрактный класс)


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

> У класса DbAdapter есть один абстрактный метод save, который нужно реализовать.


Можно еще назвать его вроде StorageAdapter чтобы не говорить что нам нужна именно БД. Хотя это будет путать людей наверно.

> if ($this->client->exists($uniqueVisit)) return;


> $this->client->set($uniqueVisit, $keyValue, $this->client->keyExpire);


Это не атомарное действие. Другой процесс может успеть добавить ключ после того как мы сделали exists но до того как мы выполнили set. Можно ли сделать это (проверка + установка) атомарно без сильного усложнения кода и больших затрат времени?

> foreach (array_count_values($data) as $key => $value) {


Нужно переименовать все 3 переменных. $data должно называться напимер visitsByObjectId или objectIds в зависимости от того что оно там хранит.

В конструктор надо добавить минимальную проверку значений (1 if + throw достаточно).

Также в адаптере редиса аж 6 (!) методов. Нельзя ли уменьшить их число без усложнения кода и затрат времени? Может абстрагироваться как-то. Может конечно и не стоит.
#327 #574733
>>574699

Возможно адаптеры стоит вынести в отдельные папки, а то сейчас они лежат вперемешку.
#328 #574773
>>574729

>Почему префикс и срок хранения - свойства адаптера? Эти настройки применимы только к редиске или к любому драйверу редиса? Какие у тебя аргументы за помещение их в адаптер?


Настройки применимы к любому драйверу редиса. Аргументы уровня "свойства должны быть, но не знал куда засунуть". Ну а куда? Срок хранения ключей и префикс относятся к редису, значит это свойства класса адаптера редиса. Класс счетчика занимается более глобальными вещами, его дело манипулировать адаптерами, а не настраивать их. Я себе представляю аналогию между контроллером и моделями в mvc.
Хотя мне не хватает дальновидности, может ты сможешь привести аргументы, почему так нельзя делать, какие негативные последствия это может повлечь.

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


Ну у интерфейса например не может быть свойств и реализованных методов (тех же сеттеров).
Я мог конечно вынести абстрактные методы в интерфейс, а затем имплементировать его абстрактным классом. Но зачем?
Какие есть "против" пока не представляю. Поэтому сделал один абстрактный класс.

>Также в адаптере редиса аж 6 (!) методов


А что, это много? Для любой команды редиса придется писать обертку, потому что разработчики клиентов оригинальничают, и называют методы своих классов как захотят. Лучше всего сделано в predis, там метод всегда пишется точно так, как в самом редисе.
Мало того, у редиски еще и создается отдельный объект для ключа.
Например, чтобы взять диапазон из списка (LRANGE) нужно прописать
$key = new Rediska_Key_List('mylist');
$res = $key->getValues([0], [-1]);
Тогда как у Predis это предсказуемая команда $client->lrange($list, $start, $end);
Что здесь можно сделать? Я вижу выход только в написании метода-обертки для каждой команды.
Понадобится не 6, а 60, придется писать шестьдесят.

>Можно ли сделать это (проверка + установка) атомарно без сильного усложнения кода и больших затрат времени?


Первыми в голову приходят транзакции.
А нет, вспомнил, что у команды set есть какая-то опция для проверки существования ключа.
NX -- Only set the key if it does not already exist
Нужно только посмотреть, как это реализовано в клиентах.
Вот не вижу, как это реализовать в редиске, например. Апи:
setValue (line 24)
Set key value
access: public
boolean setValue ($value $value)
$value $value

Что делать, добавлять транзакцию?
#328 #574773
>>574729

>Почему префикс и срок хранения - свойства адаптера? Эти настройки применимы только к редиске или к любому драйверу редиса? Какие у тебя аргументы за помещение их в адаптер?


Настройки применимы к любому драйверу редиса. Аргументы уровня "свойства должны быть, но не знал куда засунуть". Ну а куда? Срок хранения ключей и префикс относятся к редису, значит это свойства класса адаптера редиса. Класс счетчика занимается более глобальными вещами, его дело манипулировать адаптерами, а не настраивать их. Я себе представляю аналогию между контроллером и моделями в mvc.
Хотя мне не хватает дальновидности, может ты сможешь привести аргументы, почему так нельзя делать, какие негативные последствия это может повлечь.

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


Ну у интерфейса например не может быть свойств и реализованных методов (тех же сеттеров).
Я мог конечно вынести абстрактные методы в интерфейс, а затем имплементировать его абстрактным классом. Но зачем?
Какие есть "против" пока не представляю. Поэтому сделал один абстрактный класс.

>Также в адаптере редиса аж 6 (!) методов


А что, это много? Для любой команды редиса придется писать обертку, потому что разработчики клиентов оригинальничают, и называют методы своих классов как захотят. Лучше всего сделано в predis, там метод всегда пишется точно так, как в самом редисе.
Мало того, у редиски еще и создается отдельный объект для ключа.
Например, чтобы взять диапазон из списка (LRANGE) нужно прописать
$key = new Rediska_Key_List('mylist');
$res = $key->getValues([0], [-1]);
Тогда как у Predis это предсказуемая команда $client->lrange($list, $start, $end);
Что здесь можно сделать? Я вижу выход только в написании метода-обертки для каждой команды.
Понадобится не 6, а 60, придется писать шестьдесят.

>Можно ли сделать это (проверка + установка) атомарно без сильного усложнения кода и больших затрат времени?


Первыми в голову приходят транзакции.
А нет, вспомнил, что у команды set есть какая-то опция для проверки существования ключа.
NX -- Only set the key if it does not already exist
Нужно только посмотреть, как это реализовано в клиентах.
Вот не вижу, как это реализовать в редиске, например. Апи:
setValue (line 24)
Set key value
access: public
boolean setValue ($value $value)
$value $value

Что делать, добавлять транзакцию?
23 Кб, 669x173
#329 #574776
Нубский вопросик.
Вот контроллер читает пост/гет массив и что-то делает. Я не люблю кучи if/else, можно ли это завернуть в няшный switch/case ? У меня не получилось.
Тапками прошу не кидать, я только учусь
16 Кб, 402x303
#330 #574808
>>574776
не благодари
#331 #574827
>>574773

Там раньше была отдельная команда http://redis.io/commands/setnx

Делаем поиск по SETNX: https://github.com/Shumkov/Rediska/search?utf8=%E2%9C%93&q=setnx

Что-то есть.

Ну и даже если готового метода нет наверняка можно вызвать команду явно.

Транзакцией по моему SETNX реализовать невозможно. Или как-то с помощью WATCH? Тогда наверно можно.

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

Остальное проверю позже.
#332 #574828
>>574776

Можно. Нужно вынести содержимое ифов в отдельные методы.

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

>>574808

Увы, это плохой совет. Там проблема в том что он пишет все одной длинной простыней и надо это исправлять разбивая на функции. И что он обрабатывает данные от 5 форм в одном экшене.

Свитч тут скорее запутывает, 5 if/else будут смотреться компактнее по моему.
#333 #574834
анон, у меня к тебе вопрос: пишу простенький сайт по MVC архитектуре и тут встаёт проблема: я передаю имя контроллера, экшн и еще прочие параметры в $_GET массиве. Конечно же, я их экранирую и прочее, но встал такой вопрос с формированием ссылок без потери параметров: в какую сторону гуглить/копать, чтобы формировать ссылки с GET параметрами, причем их количество и значения неизвестны. То есть я хочу избавиться от обскурных конструкций такого вида
codebin.org/view/d9286a90
#335 #574838
>>574834

А зачем тебе 4 переменных, хранящих сортировку? Используй одну переменную $order.

Формирование ссылок удобно вынести в класс например под названием UrlHelper. Метод может иметь вид

public function getUserTableUrl($order = null, $orderDirection= 1, $page = 1)
{
...
}

Допустим тебе надо дать ссылку на страницу где выводится отсортированный по email список пользователей, 3-я страница. Легко и просто:

$url = $urlHelper->getUserTableUrl('email', 1, 3);

> if((count($_GET)==0)||(count($_GET)==1&&isset($_GET['order'])))


Ты тут чего-то нагородил лишнего.

Ну и для формирования ссылок с параметрами удобно использовать стандартную функцию http_build_query, а не изобретать велосипед. Она заодно сама все как нужно заэкранирует.
#336 #574840
>>574838
это ссылки для выбора по какому полю сортировать
#337 #574841
>>574834

> $loginSort = $mailSort = $rateSort = $dateSort = $_SERVER['SCRIPT_NAME']."?";


Зачем так писать, почему не прописать ссылку на скрипт явно?

> foreach ($_GET as $key => $value) {


Непонятно зачем все параметры копировать. А если кто-то допишет &asasas=asas ты это тоже в ссылку скопируешь?
#338 #574842
>>574841
ну лишние параметры просто проигнорируются по идее, но я лучше сейчас вот это перепишу через http_build_query
#339 #574860
Оп, а ты пасты выкладываешь только когда в треде звучит вопрос по соответствующей тематике? А можно получить их сразу все? Хочется перед собеседованиями заполнить пробелы и расширить кругозор.
#340 #574869
еще такой вопрос о принципах построения MVC сайтов: сайт по моему заданию считай состоит из одного контроллера и нескольких экшенов к нему. Но тем не менее я помимо корневых классов model, view, controller создал отдельные model_main, controller_main, view_main и вопрос по наполнению этих классов:
1) метод для формирования SQL запросов исходя из входного массива стоило разместить непосредственно в model или в model_main? лично я разместил в model, а в model_main оставил только метод отправки содержимого формы на сервер и проверку капчи гугловской.
2) непосредственно controller у меня остался почти пустым, только конструктор без параметров, все экшены я обрабатываю в controller_main
3)нормально ли, что в view_main нет описания класса-наследника от View а только смесь php кода и разметки, формирующая вывод. и обращающаяся к классу View для формирования разметки выводимых постов и индекса для навигации?

собственно, что можете сказать об этом: что мне стоит поправить и как?
64 Кб, 640x480
#341 #574883

>чел кошек-мышек пол-года делает

#342 #574978
>>574828
Я еще не знаю, как правильно. Пытаюсь познать pure шаблонизацию.
У меня там и кнопки и ссылки обрабатываются и в зависимости от нажатого выполняются действия и выбирается шаблон страницы. Типа точка входа. В конце все это собирается воедино.

include 'head.html.php'; //подгружаем основной шаблон
include $page; //подгружаем тело страницы
include '../views/footer.inc.html.php'; //подгружаем футер


>>574808
Оригинально, но не няшно.
30 Кб, 640x480
#343 #574992
>>574883
Это норма.
#344 #575011
Аноны, кто знает английский, смотрите, уязвимость в VBulletin из-за того что они делали unserialize() с пришедшими от пользователя данными:http://blog.checkpoint.com/2015/11/05/check-point-discovers-critical-vbulletin-0-day/

Пара функций serialize()/unserialize() преобразует любые PHP-значения (включая массивы и объекты) в строку и обратно.

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

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

Кстати, я помню, пару лет назад похожую проблему нашли в фреймворке ruby on rails - там тоже пользователь мог создать произвольный объект на сервере.

>>574840

Тебе не нужно 4 ссылки и 4 переменных. Тебе достаточно иметь функцию которая их сгенерирует когда понадобится.

>>574860

Большинство тут:

https://github.com/codedokode/pasta
https://gist.github.com/codedokode

Ну и еще одна небольшая паста про то что стоит подучить перед собеседованием:

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

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

PHP: перечитай мануал, любят спрашивать тонкости языки типа преобразования одного типа в другой или правил сравнения типов (сработает ли if ("foo" == 0) { } или if ("1 person" == true) ? ). По ООП любят вопросы из серии «что выведет эта дебильная программа где мы переопределяем в наследнике приватный метод публичным с тем же именем», опять же спасает чтение мануала.

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

Если требуют знания фреймворков, могут спросить как реализовать штуку X (например древовидные категории, хотя это продвинутый вопрос) в фрейморке.

MySQL и SQL вообще: любят вопросы по теории баз данных и SQL: транзакции, внешние ключи, нормализация, виды джойнов, индексы (это у более продвинутых). Могут попросить сделать хитрый SQL запрос типа найти в таблице записи которые встречаются больше N раз или найти записи которые есть в одной таблице и нет в другой.

JS: тонкости вроде преобразования типов, чему равно [] + {} + "hello", вопросы по прототипам, вопросы по замыканиям, вопросы по передаче значений по ссылке (объекты всегда передаются по ссылке, примитивы копируются). Некоторые подвохи освещены в моих задачах по JS, некоторые в learn.javascript.ru

HTML/CSS: тут подвохи вряд ли будут, разве что могут спросить как реализовать ту или иную вещь (например вертикальное выравнивание или прибитый к низу футер) и обычно там много вариантов.
#344 #575011
Аноны, кто знает английский, смотрите, уязвимость в VBulletin из-за того что они делали unserialize() с пришедшими от пользователя данными:http://blog.checkpoint.com/2015/11/05/check-point-discovers-critical-vbulletin-0-day/

Пара функций serialize()/unserialize() преобразует любые PHP-значения (включая массивы и объекты) в строку и обратно.

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

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

Кстати, я помню, пару лет назад похожую проблему нашли в фреймворке ruby on rails - там тоже пользователь мог создать произвольный объект на сервере.

>>574840

Тебе не нужно 4 ссылки и 4 переменных. Тебе достаточно иметь функцию которая их сгенерирует когда понадобится.

>>574860

Большинство тут:

https://github.com/codedokode/pasta
https://gist.github.com/codedokode

Ну и еще одна небольшая паста про то что стоит подучить перед собеседованием:

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

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

PHP: перечитай мануал, любят спрашивать тонкости языки типа преобразования одного типа в другой или правил сравнения типов (сработает ли if ("foo" == 0) { } или if ("1 person" == true) ? ). По ООП любят вопросы из серии «что выведет эта дебильная программа где мы переопределяем в наследнике приватный метод публичным с тем же именем», опять же спасает чтение мануала.

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

Если требуют знания фреймворков, могут спросить как реализовать штуку X (например древовидные категории, хотя это продвинутый вопрос) в фрейморке.

MySQL и SQL вообще: любят вопросы по теории баз данных и SQL: транзакции, внешние ключи, нормализация, виды джойнов, индексы (это у более продвинутых). Могут попросить сделать хитрый SQL запрос типа найти в таблице записи которые встречаются больше N раз или найти записи которые есть в одной таблице и нет в другой.

JS: тонкости вроде преобразования типов, чему равно [] + {} + "hello", вопросы по прототипам, вопросы по замыканиям, вопросы по передаче значений по ссылке (объекты всегда передаются по ссылке, примитивы копируются). Некоторые подвохи освещены в моих задачах по JS, некоторые в learn.javascript.ru

HTML/CSS: тут подвохи вряд ли будут, разве что могут спросить как реализовать ту или иную вещь (например вертикальное выравнивание или прибитый к низу футер) и обычно там много вариантов.
#345 #575015
>>574869

> не менее я помимо корневых классов model, view, controller


Имена классов пишут с большой буквы, также не уверен что тебе так уж нужен View.

> создал отдельные model_main, controller_main, view_main


Вот это говорит о том что ты не понял MVC. Что такое model_main? Модель обычно в простых приложеиях делается из расчета 1 модель на 1 таблицу БД. У тебя таблица main называется?

Контроллеры делаются из расчета 1 контроллер на 1 раздел сайта.

Зачем ты сделал и что лежит в view_main я не понял.

Думаю, ты не очень понял MVC.

> метод для формирования SQL запросов исходя из входного массива


Почитай урок про паттерны работы с БД, в простом приложении подойдет TableGateway: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md

> непосредственно controller у меня остался почти пустым,


Может он не особо и нужен?

> нормально ли, что в view_main нет описания класса-наследника от View а только смесь php кода и разметки,


Нет. В Классах не может быть HTML-разметки, она должна быть в шаблонах.

> что мне стоит поправить и как?


У нас есть задача на список студентов с подробными комментариями: https://github.com/codedokode/pasta/blob/master/student-list.md

Почитай их и скорее всего придется переделать все.
#345 #575015
>>574869

> не менее я помимо корневых классов model, view, controller


Имена классов пишут с большой буквы, также не уверен что тебе так уж нужен View.

> создал отдельные model_main, controller_main, view_main


Вот это говорит о том что ты не понял MVC. Что такое model_main? Модель обычно в простых приложеиях делается из расчета 1 модель на 1 таблицу БД. У тебя таблица main называется?

Контроллеры делаются из расчета 1 контроллер на 1 раздел сайта.

Зачем ты сделал и что лежит в view_main я не понял.

Думаю, ты не очень понял MVC.

> метод для формирования SQL запросов исходя из входного массива


Почитай урок про паттерны работы с БД, в простом приложении подойдет TableGateway: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md

> непосредственно controller у меня остался почти пустым,


Может он не особо и нужен?

> нормально ли, что в view_main нет описания класса-наследника от View а только смесь php кода и разметки,


Нет. В Классах не может быть HTML-разметки, она должна быть в шаблонах.

> что мне стоит поправить и как?


У нас есть задача на список студентов с подробными комментариями: https://github.com/codedokode/pasta/blob/master/student-list.md

Почитай их и скорее всего придется переделать все.
#346 #575016
>>574978

> Я еще не знаю, как правильно.


для каждой страницы свой экшен или контроллер. Если у тебя 5 форм то делаешь 5 экшенов или контроллеров.

Ну и почитай советы к задаче про студентов - многие из них применимы к твоему приложению: https://github.com/codedokode/pasta/blob/master/student-list.md
453 Кб, 130x163
#347 #575017
Пропердолил phpstorm + vagrant + xdebug до рабочего состояния. С теплом вспомнил турбо паскаль, где все "из коробки".
#348 #575027
>>575017

А вагрант-то зачем?
#349 #575034
>>575027
Потому что это новая для меня штуковина с интересными возможностями, которую я еще не пердолил. Что за странные впросы.
#350 #575036
>>574447
>>574451

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

Старый вариант, еще не проверенный. https://ideone.com/HYPC12
Новый вариант с массивами. https://ideone.com/GlvJrE
#351 #575046
https://gist.github.com/codedokode/58ebc90bd006baf4b35c
Кто-нибудь может сделать 8 задание?
У меня ломается вёрстка когда примечание длиннее основного текста.
#352 #575070
>>575046

Пример кода хорошо бы показать, где и что ломается.
#353 #575075
>>575036

Новый вариант неплох, почти все готово. Вот что еще можно улучшить:

> stuffingsArr


Arr это плохое слово, так как во-первых, такого слова нет (есть array и незачем экономить 2 буквы ценой читабельности), во-вторых, оно не добавляет смысла. Лучше назвать stuffings или stuffingTypes

> this.pricesAndCalorics[Hamburger.SIZE_BIG] = ....


> this.pricesAndCalorics[Hamburger.SIZE_SMALL] = ...



Зачем копипастить this.pricesAndCalorics в каждой строчке? Сохрани это в переменную с простым именем, например p, и добавляй элементы в нее.

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

Вынеси-ка создание этой таблицы цен из конструктора, а то он громоздкий какой-то.

> Hamburger.prototype.calculateCalories = function () {


Тут выравнивание почему-то лестницей сделано.
#355 #575088
>>575077

А что ты имеешь в виду под «ломается»? Абзац уезжает вниз? Против этого есть только одно средство: поместить несколько примечаний внутрь одного aside.

Так что с этим бороться не требуется.

Лучше заливать код на сервис вроде jsfiddle, jsbin чтобы можно было сразу просмотреть результат.

> box-sizing: content-box;


Разве не такое стоит по умолчанию?

И вот это по моему плохая штука:

> {


> box-sizing: inherit;


как минимум это приведет к масштабированию картинок (img) если у них есть паддинг или бордер и задан размер. Также, некоторые элементы будут вести себя не как ожидается, это сделает код менее понятным. Если тебе так нужен box-sizing, то ставь его только на конкретные элементы где он нужен и ставь вендорные префиксы для более старых браузеров.

Ну и вообще стили со звездочкой плохая штука.

Ну и все наши задачи решаются и без box-sizing.

Поля надо делать через паддинг на родителе, в примечаниях к задаче это написано по моему.
#356 #575095
>>575075

Переделал.

https://ideone.com/UHnGCj

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


Не осилил. Сделал через this. и метод.

>Тут выравнивание почему-то лестницей сделано.


А каким стандартом вообще пользоваться, а то я все наугад делаю.
#357 #575096
>>574992
Скажет потом на собеседовании: вот, смотрите, я 2д игру на 7 клеточек пол-года делал.
#358 #575104
>>575096

Каждый учится в комфортном ему темпе. А на собеседовании это рассказывать и не требуется.
39 Кб, 1513x350
#359 #575107
>>575088

>А что ты имеешь в виду под «ломается»?


Каждое примечание должно быть на одном уровне со своим абзацем.
https://jsfiddle.net/vhbs77hm/
И спасибо за ответы и советы.
#360 #575110
>>575107

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

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

Также, у тебя плохо сделаны поля: https://jsfiddle.net/vhbs77hm/1/

Если кроме <p> добавить другие теги, то они уезжают влево.
#361 #575117
>>575011

>Большинство тут:



>https://github.com/codedokode/pasta


>https://gist.github.com/codedokode



Нет, я про другие. Вот недавно была паста про интерфейсы, еще раньше - про архитектуру веб-серверов. Есть еще что-то подобное?
#362 #575133
>>575104
Правильно, твой гитхаб все за тебя расскажет. Я то сам комфортный слоупок, но все это наводит меня на мысль, что если проект на одном только языке и фреймворке пишется по пол-года, то как вообще возможно писать, что ты знаешь овер дохулион ЯП - разве что по синтаксису проскочился. А еще наводит на мысль, что создание чего-то - это ммаксимум командное мероприятие, ибо в одиночку потребует дохуя обучения и времени.
#363 #575155
https://github.com/codedokode/pasta/blob/master/security/xsrf.md
Вот тут непонятно, если мы добавляем переменную токен в скрытое поле формы на сайте, то откуда мы эту переменную берем? Если мы берем ее из куки юзера, то ведь она будет соответствовать куке, ведь отправляет юзер хоть и с другого сайта, я что-то ничего не понял.
#364 #575199
В каких случаях лучше использовать исключения и нужно ли вообще их использовать?
#365 #575220
>>575199
Когда выполнение текущего хода программы далее невозможно и тебе надо выйти на уровень выше.
196 Кб, 480x320
112 Кб, 540x810
384 Кб, 1024x683
1986 Кб, 400x600
someApprentice #366 #575276
Я должен отписаться в этом треде чтобы заставить себя завтра сделать что-нибудь на Linux!!!
#367 #575293
>>575276
Удачи тебе, аноняш.
#368 #575309
>>575293
Спасибо, Котик
Я не подведу тебя!
#369 #575312
>>575309

>Спасибо, Котик


fix();
#370 #575313
У слима метод render автоматически ищет переданное ему имя файла в папке templates? Почему-то в документации про это ничего не написано. Если я. например, захочу переименовать папку, то он не находит файл, а полный путь ему передать нельзя.
#371 #575314
>>575312
Мда похоже макаба съедает utf-символы.
#372 #575316
>>575314
Хватит флудить, мразь.
176 Кб, 800x600
#373 #575323
Встречайте новую макаку в стае посоны.
До этого времени кодировал странички в хтмле + писал всякую мишуру на JS/JQuery, теперь расширю компетенцию на бекенд.
#374 #575331
>>575316
Быдлфорум там ===>
Тут у нас анонимная картинкопараша.
#375 #575337
>>575155

Если у юзера нет куки (он впервые к нам зашел) то генерируем длинный случайный код, ставим в куку и вписываем его же форму.

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

При проверке формы сравниваем код пришедший из формы с кодом в куке. Их совпадение подтверждает что форма отправлена с нашего сайта, а не с постороннего.

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

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


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

Если у нас есть сайт good.example.com который выставил куку с кодом, то сайт bad.example.com эту куку не видит. Потому он не может подставить код в форму. Если пользователь отправляет форму с сайта bad.example.com на good.example.com то код в форме не будет соответствовать куке, так как bad не может узнать какой код хранится у пользователя в куке.

Если что-то непонятно, уточняй.

Имей в виду, что эта защита защиащет только от одной ситуации: от скрытой отправки формы н наш сайт посторонней страницей от имени пользователя.
#376 #575338
>>575199

Урок https://gist.github.com/codedokode/65d43ca5ac95c762bc1a

>>575313

Эта папка задается в настройках слима, по моему viewPath или templatesPath, посмотри документацию.
#377 #575339
>>575337
А как быть уверенным, что 2 юзера не получат одинаковой куки, если они генерируются случайным образом?
мимошел
#378 #575340
мля, у меня в файлообменнике еще конь не валялся. Если по всем правилам мвк и классов фиксить, то хуй кто разберет. Я бы если сам не делал бы, не разобрал такую груду файлов с кучей зависимостей. Я в своих то папках уже с трудом ориентируюсь.
#379 #575341
>>575313
Все там написано.
http://docs.slimframework.com/configuration/overview/
$app->config(array(
'debug' => true,
'templates.path' => '../templates'
));

>>575331
Здесь тред полезной информации, а вы засоряете его своими тупыми постами и мешаете людям заниматься. Так что быдло (вернее тупой школьник) это ты.
#380 #575342
>>575341
Но я не школьник, а джуниор PHP девелопер.
Ну написал человек один раз про юникодные символы в макабе. Он же не еду тут обсуждает, ил биопроблеммы, зачем так агрится сразу?
#381 #575343
>>575337
Но ведь злоумышленник отправляет запрос посредством залогиненного юзера.Что если он добавит в форму поле с кукой и какой-нибудь html cookies request. Ведь отправляет он запрос через залогенного юзера, куки которого позволяют отправить запрос.
#382 #575360
Флаг httponly не позволит получить доступ к кукам из js.
http://php.net/manual/ru/function.setcookie.php
Так что проставить куку в поле формы на чужом сайте не получится.
#383 #575369
>>575339

Если последовательность длинная, например 16 цифр 0-9 и букв a-z то мы имеем 36 в 16 степени вариантов (гугл говорит что это 36^16 = 7.95866111 × 10^24 то есть почти 8 триллионов триллионов, так как 1 триллион = 10^12).

Это значительно больше чем число людей на земле, так что вероятность мала. И даже если 2 человека получат одну и ту же куку, что сломается?

>>575340

код должен быть понятным. Если это не так, придется его переделать.

>>575343

А ты понимаешь механизм работы кук в принципе?

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

Таким образом когда пользователь заходит на bad.example.com и загружает страницу с формой, то кука принадлежащая good.example.com не отправляется. Сервер bad ее не видит. И загруженная с него страница с формой тоже не может никак получить эту куку.

А вот когда заполненная форма отправляется с bad на good.example.com то браузер прикладывает к запросу куку. И сервер на good.example.com видит эту куку и видит что она не совпадает с кодом из формы.

> Что если он добавит в форму поле с кукой


Поле он добавить может, а вот какой код у этого юзера, он не знает, так как код хранится в куке доступной только для good.example.com.

> и какой-нибудь html cookies request.


Такого функционала в браузерах нету.

Вообще, в браузере идет изоляция именно на уровне отдельных доменов. Если где-то это бы нарушалось, то многие сайты могли бы быть взломаны.

То есть сайт A может подключать картинки/скрипты/стили и даже целые страницы (в ифрейме) с сайта B, может отправлять формы на сайт B, но не может никаким образом: видеть куки сайта B, видеть ответ на запрос отправленный на сайт B, видеть содержимое картинки/скрипта/стилей/страницы с сайта B, залезть внутрь принадлежащего сайту B ифрейма.

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

Эта изоляция называется same-origin policy. Можешь погуглить.

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

По идее конечно браузеры должны бы сами предотвращать подобную отправку форм. Например, перед отправкой формы спрашивать у сайта B, желает ли он принять форму с сайта A или нет? Но из соображений совместимости с древними сайтами это сделать пока не получится.
#383 #575369
>>575339

Если последовательность длинная, например 16 цифр 0-9 и букв a-z то мы имеем 36 в 16 степени вариантов (гугл говорит что это 36^16 = 7.95866111 × 10^24 то есть почти 8 триллионов триллионов, так как 1 триллион = 10^12).

Это значительно больше чем число людей на земле, так что вероятность мала. И даже если 2 человека получат одну и ту же куку, что сломается?

>>575340

код должен быть понятным. Если это не так, придется его переделать.

>>575343

А ты понимаешь механизм работы кук в принципе?

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

Таким образом когда пользователь заходит на bad.example.com и загружает страницу с формой, то кука принадлежащая good.example.com не отправляется. Сервер bad ее не видит. И загруженная с него страница с формой тоже не может никак получить эту куку.

А вот когда заполненная форма отправляется с bad на good.example.com то браузер прикладывает к запросу куку. И сервер на good.example.com видит эту куку и видит что она не совпадает с кодом из формы.

> Что если он добавит в форму поле с кукой


Поле он добавить может, а вот какой код у этого юзера, он не знает, так как код хранится в куке доступной только для good.example.com.

> и какой-нибудь html cookies request.


Такого функционала в браузерах нету.

Вообще, в браузере идет изоляция именно на уровне отдельных доменов. Если где-то это бы нарушалось, то многие сайты могли бы быть взломаны.

То есть сайт A может подключать картинки/скрипты/стили и даже целые страницы (в ифрейме) с сайта B, может отправлять формы на сайт B, но не может никаким образом: видеть куки сайта B, видеть ответ на запрос отправленный на сайт B, видеть содержимое картинки/скрипта/стилей/страницы с сайта B, залезть внутрь принадлежащего сайту B ифрейма.

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

Эта изоляция называется same-origin policy. Можешь погуглить.

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

По идее конечно браузеры должны бы сами предотвращать подобную отправку форм. Например, перед отправкой формы спрашивать у сайта B, желает ли он принять форму с сайта A или нет? Но из соображений совместимости с древними сайтами это сделать пока не получится.
#384 #575377
>>575360

Ты тоже не очень понимаешь как работают куки. Кука выставленная сайтом A отправляется только на сервер A и доступна только скриптам на странице сайта A (опция httpOnly отключает ее доступность для скриптов на странице сайта A и делает куку доступной только серверу A).

Независимо от флага httpOnly ни сайт B ни скрипты на загруженной с него странице не могут видеть куки сайта A.

Зачем тогда этот флаг? Он для защиты от XSS, когда злоумышленнику удалось как-то вставить свой яваскрипт-код на страницу сайта A (например из-за того что сервер выводит пришедшие от пользователя данные как есть, без экранирования). httpOnly в этом случае защитит от кражи куки, но не защитит от других действий, так как скрипт на странице сайта A может отправлять и видеть ответы на любые запросы к сайту A. Значит он может жать любые кнопки и вводить любые данные на сайте A от имени пользователя. А также читать содержимое любой страницы на сайте A. И перехватывать нажатия клавиш на этой странице.

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

Таким образом httpOnly защищает от кражи кук (и возможности хакеру залогиниться с другого компьютера), но не защищает от XSS в общем.
#385 #575382
>>575369
В том то и дело, что делаю я его по всем правилам, обработку всего всего рассовываю по классам и оставляю самый минимум в контроллерах (создание объектов и вызов методов). Но мне вот лично было бы понятнее, если бы все общей лапшой в контроллерах висело. А так у меня все везде по кусочкам и проекто разрастается до больших размеров.
#386 #575390
>>575382

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

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

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


Так это как раз не проблема, если все по кусочкам. Ну представь что мы хотим поправить страницу со списком новостей. Нам достаточно открыть 3 небольших файла:

- контроллер новостей
- модели, которые он вызывает (скорее всего модель новостей)
- шаблон страницы со списком

Остальные файлы нас вообще не интересуют.

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

А когда все в куче, гораздо неудобнее, надо просматривать кучу не относящегося к делу кода, причем хорошо еще если код работы с новостями собран в одном месте, а если он размазан по разным частям огромного файла?
#387 #575438
Что-то я охуеваю от документации слима. Абстракция на абстракции и абстракцией погоняет, порой я вообще не понимаю о чем речь идет. По сравнению с этим, офф. мануал по пхп кажется просто сверхдружелюбным с его практическими примерами. Боюсь представить что творится в серьезных фреймворках.
#388 #575443
>>574827
Не понимаю.
За команду set в редиске отвечает метод setValue, у него только один параметр $value
https://github.com/Shumkov/Rediska/blob/master/library/Rediska/Key.php#L24

Да, есть еще какие-то классы с префиксом "command", но я не понимаю как к ним обратиться.
Вижу нужный мне третий параметр $overwrite = true в методе create класса Rediska_Command_Set
https://github.com/Shumkov/Rediska/blob/39a0d41f61f24800aa0846d556d43f395a158540/library/Rediska/Command/Set.php#L25
Что мне с этим делать? Знаю только $key->setValue, не понимаю что за классы "command" и как с ними обращаться.
Кстати второй параметр $valueOrOverwrite = null тоже непонятно за что отвечает.

> Value or overwrite property for array of values. For default true.


Как понимать "value or overwrite property for array of values"? И почему написано "for default true", если там указано null?

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


Как?
#389 #575450
>>575443

> не понимаю что за классы "command" и как с ними обращаться.



В ООП-мире с этим все просто. Очевидно тебе надо

1) получить объект этого класса
2) вызвать нужный метод

Чтобы получить объект класса, есть 2 варианта:

1) найти какую-то функцию, которая его создает или возвращает
2) если ее нет, создать самому через new

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

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


> Как?


Посмотреть в коде как работает обычный setValue (или класс Command по моей ссылке) и как он в итоге превращается в команду SET и сделать так же.
#390 #575452
>>575443

> Кстати второй параметр $valueOrOverwrite = null тоже непонятно за что отвечает.



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

Если посмотреть внимательно на сигнатуру метода:

create($keyOrData, $valueOrOverwrite = null, $overwrite = true)

и на комментарии то мы видим 2 варианта его использования:

create(key, value, overwrite)
create([key => value], overwrite)

Это конечно пример плохого проектирования, и то что ты запутался, это доказательство что оно плохое. В такой ситуации правильно было сделать 2 отдельных метода. Не делай так, не делай аргументы которые могут иметь разное значение, это запутывает код и создает возможность сделать ошибку.
#391 #575456
>>575443

Еще. Вот это место

> https://github.com/nsdvw/visit-counter/blob/master/src/VisitCounter.php#L56


> protected function getQueueName()


> {


> return "{$this->client->getKeyPrefix()}Queue";


У тебя никаких сомнений не вызывает?
#392 #575457
>>575443

> https://github.com/nsdvw/visit-counter/blob/master/src/VisitCounter.php#L41


> protected function deleteFromQueue($queueName, $count)


Незачем тут передавать queueName наверно. Твой код создает впечатление что тут могут передаваться разные имена очередей, но в реальности имя там всегда одно и значит незачем его делать аргументом функции.
#393 #575458
>>575438

На мой взгляд он наоборот, максимально простой. А можешь привести пару примеров абстракций, и как можно было сделать без них?
#394 #575459
>>575452
Ага, то есть вместо того, чтобы пользоваться апи, я должен сидеть и полдня разбираться в последовательности вызовов в этой библиотеке? Замечательно.
Тебе не кажется, что библиотека на то и библиотека, что у нее должны быть только прокомментированные методы api, чтобы я ее установил и начал пользоваться, а не возился с ее внутренностями?

Попытался создать объект команды
$command = new Rediska_Command_Set(
$rediska,
'Set',
array('keyOrData'=>'test', 'valueOrOverwrite'=>'123', 'overwrite'=>false));

Выдает ошибку
Uncaught exception 'Rediska_Command_Exception' with message 'Argument 'keyOrData' not present for command 'Set'' in /vendor/geometria-lab/rediska/library/Rediska/Command/Abstract.php:388

>>575456
Не вызывает. Если бы вызывало, то наверное не сделал бы ошибку.
#395 #575460
>>575458
Вот, например http://www.slimframework.com/docs/concepts/middleware.html. Может я тупой, но не понятно что еще за middleware.
http://docs.slimframework.com/routing/middleware/ вот тут еще более менее понятно за route middleware поясняется, то есть это какие-то, определенные пользователем заранее, функции, которые передаются в функцию роутинга и вызываются до callable функции. Хотя практический смысл этого от меня ускользает.
#396 #575466
>>575459
А, там оказывается нужен был не ассоциативный массив, а обычный индексированный. Методом тыка выяснили это.
Кстати, чисто логически: я создаю объект класса Rediska_Command_Set, и мне нужно передать вторым аргументом название команды Set. Это значит, что при помощи класса Rediska_Command_Set можно создать не только команду Set, но и любую другую? Сомневаюсь.

Это мы только создали команду, а как ее выполнить? А, нашел метод execute, наверное он отвечает за выполнение.
Еще прописан магический метод __invoke, так что можно не выполнять execute, а обратиться к объекту как к функции $command()
51 Кб, 604x562
#397 #575476
>>575466

>__invoke



КВАС ВЕКС КВАС!))))))))))))0
#398 #575479
>>575476
Очень содержательный пост.
#399 #575499
>>575460

Middleware - это что-то вроде функции-обертки. Ты можешь завернуть весь процесс обработки запроса (который происходит при вызове $app->run()) в указанную тобой функцию-обертку.

То есть будет вызвана твоя функция-middleware, ей будет передано 3 аргмуента: request (запрос пришедший от пользователя, который надо обработать), response (объект, в который мы записываем ответ который надо отдать) и $next (в данном случае это функция из Слима которая обрабатывает запрос).

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

Функций-middleware можно добавить несколько.

Таким образом, получается что-то вроде луковицы, несколько оболочек-middleware, а в серединке функция фреймворка Слим, которая обрабатывает запрос.

Что можно сделать с помощью middleware? Вот несколько примеров:

- обертка, которая заменяет на странице русские буквы на транслит если передан параметр ?translit=on. При этом она запоминает что режим транслита включен, в куках. Для отключения надо открыть страницу с параметром ?translit=off

- обертка, которая закрывает доступ к сайту паролем

- обертка которая сжимает отдаваемые страницы (при этом выставляя правильные HTTP-заголовки так, что браузер сможет их разжать обратно)

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

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

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

- отдавать страницу-заглушку если сайт закрыт на техобслуживание

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

Конечно, это наверно можно сделать и без middleware, как-то прописав в коде сайта. Но в этом случае твой код будет работать только с этим сайтом и будет намертво в него вшит. А middlware - это отдельный компонент, который можно прикрутить к любому сайту на Слиме, выложить на гитхаб чтобы все им пользовались, и тд.

Middleware это не слимовская идея. Аналогичная система есть в других веб-фреймворках на других языках программирования, таких как Питон или Node.JS.

Чтобы проверить что ты все понял, предлагаю сделать 1-2 примеров Middleware, например то что про транслит и то что про защиту паролем. Не забудь использовать праивильные заголовки, коды ответа HTTP, чтобы ни в каких случаях не было багов и все соответствовало протоколу HTTP. Транслитерировать надо не любой контент а только если он имеет тип text/html (HTML страница). Не надо например пытаться что-то менять если код отдает картинку с типом image/png, так как получится битая картинка.
#399 #575499
>>575460

Middleware - это что-то вроде функции-обертки. Ты можешь завернуть весь процесс обработки запроса (который происходит при вызове $app->run()) в указанную тобой функцию-обертку.

То есть будет вызвана твоя функция-middleware, ей будет передано 3 аргмуента: request (запрос пришедший от пользователя, который надо обработать), response (объект, в который мы записываем ответ который надо отдать) и $next (в данном случае это функция из Слима которая обрабатывает запрос).

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

Функций-middleware можно добавить несколько.

Таким образом, получается что-то вроде луковицы, несколько оболочек-middleware, а в серединке функция фреймворка Слим, которая обрабатывает запрос.

Что можно сделать с помощью middleware? Вот несколько примеров:

- обертка, которая заменяет на странице русские буквы на транслит если передан параметр ?translit=on. При этом она запоминает что режим транслита включен, в куках. Для отключения надо открыть страницу с параметром ?translit=off

- обертка, которая закрывает доступ к сайту паролем

- обертка которая сжимает отдаваемые страницы (при этом выставляя правильные HTTP-заголовки так, что браузер сможет их разжать обратно)

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

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

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

- отдавать страницу-заглушку если сайт закрыт на техобслуживание

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

Конечно, это наверно можно сделать и без middleware, как-то прописав в коде сайта. Но в этом случае твой код будет работать только с этим сайтом и будет намертво в него вшит. А middlware - это отдельный компонент, который можно прикрутить к любому сайту на Слиме, выложить на гитхаб чтобы все им пользовались, и тд.

Middleware это не слимовская идея. Аналогичная система есть в других веб-фреймворках на других языках программирования, таких как Питон или Node.JS.

Чтобы проверить что ты все понял, предлагаю сделать 1-2 примеров Middleware, например то что про транслит и то что про защиту паролем. Не забудь использовать праивильные заголовки, коды ответа HTTP, чтобы ни в каких случаях не было багов и все соответствовало протоколу HTTP. Транслитерировать надо не любой контент а только если он имеет тип text/html (HTML страница). Не надо например пытаться что-то менять если код отдает картинку с типом image/png, так как получится битая картинка.
#400 #575501
>>575460

Еще иногда пишут что middleware можно использовать для защиты от CSRF (у меня есть урок на эту тему, CSRF это отправка заполненной злоумышленником формы с другой страницы на твой сайт от имени пользователя). Я считаю, нет, это плохая идея.

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

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

Потому только на middleware реализовать нормально и удобно защиту от CSRF не получится. Нужна поддержка со стороны приложения (middleware должно сообщать приложению результат проверки, но не блокировать запрос теряя введенные пользователем данные).
#401 #575508
>>575501

У Слима есть стороннее middleware для защиты от CSRF https://github.com/slimphp/Slim-Csrf/blob/master/src/Guard.php но обзор кода показвает что оно реализовано плохо:

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

> $token = hash("sha512", mt_rand(0, mt_getrandmax()));



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

- нет защиты GET-запросов
#402 #575551
>>571374

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

>>571442

Не очень понял, что такое «кнопка с переходом по ссылке»? Кнопка это штука которая запускает яваскрипт или отправляет форму. Ссылка это штука которая ведет на другую страницу.

>>571466

Не знаю, ты можешь попробовать почитать статьи для чайников «что такое MVC», но их авторы сами часто делают ошибки и путают людей. У меня есть краткое описание MVC в уроке:

https://github.com/codedokode/pasta/blob/master/student-list.md#mvc
https://github.com/never3ver/catsandmice #403 #575552
>>571499

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


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

> Похожа то она похожа, но стоит ли городить ради пары-тройки общих строчек целую функцию?


Ради пары-тройки не стоит.

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L51


> if ( .... $x > $this->getWidth()


Тут не >= должно быть?

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L61


> if ($critter instanceof Cat || $critter instanceof Mouse) {


Непонятен смысл строчки. Почему другие виды животных тут игнорируются? Вроде функция называется «получить содержимое клетки» и про кошек или мышек в ее названии ничего нету.

> TURNSBEFORESLEEP


TURNS_BEFORE_SLEEP

> https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L8


> public $sleepCounter = 0;


Зачем свойство публичное? Лучше всегда ставить как можно более ограниченный тип доступа.

> https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L46


> foreach ($this->world->getCritters() as $animal) {


Этот цикл надо заменить на вызов какого-нибудь метода из World, например getCellContent

> https://github.com/never3ver/catsandmice/blob/master/classes/Mouse.php#L85


> $distanceToCat = max($distances);


Это ошибка. Ты берешь расстояние до самой дальней кошки, но ведь опаснее всего та, которая ближе. Надо смотреть как близко к клетке самая ближняя кошка.

> $distanceToCat * 2 + $pathsQuantity;


Уверен что 2 - это достаточный вес?

И еще я заметил такую штуку. Допустим мы имеем ситуацию:

..
M.
.C

То есть кошка по диагонали от мышки. Мышка делает ход от кошки:

M.
..
.C

У кошки есть 2 варианта: встать под мышкой или по диагонали. У тебя она встает по диагонали, но выгоднее встать рядом. Думаю, надо кошке добавить в оценочную функцию фактор с маленьким весом, который при прочих равных будет выбирать ход на соседнюю с мышкой клеточку. Или можно подправить функцию оценки расстояния, чтобы нахождение на одной линии с мышкой было выгоднее чем нахождение по диагонали.

Так в общем, код неплох, меня устраивает, разве что комментариев как-то маловато.
https://github.com/never3ver/catsandmice #403 #575552
>>571499

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


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

> Похожа то она похожа, но стоит ли городить ради пары-тройки общих строчек целую функцию?


Ради пары-тройки не стоит.

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L51


> if ( .... $x > $this->getWidth()


Тут не >= должно быть?

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L61


> if ($critter instanceof Cat || $critter instanceof Mouse) {


Непонятен смысл строчки. Почему другие виды животных тут игнорируются? Вроде функция называется «получить содержимое клетки» и про кошек или мышек в ее названии ничего нету.

> TURNSBEFORESLEEP


TURNS_BEFORE_SLEEP

> https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L8


> public $sleepCounter = 0;


Зачем свойство публичное? Лучше всегда ставить как можно более ограниченный тип доступа.

> https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L46


> foreach ($this->world->getCritters() as $animal) {


Этот цикл надо заменить на вызов какого-нибудь метода из World, например getCellContent

> https://github.com/never3ver/catsandmice/blob/master/classes/Mouse.php#L85


> $distanceToCat = max($distances);


Это ошибка. Ты берешь расстояние до самой дальней кошки, но ведь опаснее всего та, которая ближе. Надо смотреть как близко к клетке самая ближняя кошка.

> $distanceToCat * 2 + $pathsQuantity;


Уверен что 2 - это достаточный вес?

И еще я заметил такую штуку. Допустим мы имеем ситуацию:

..
M.
.C

То есть кошка по диагонали от мышки. Мышка делает ход от кошки:

M.
..
.C

У кошки есть 2 варианта: встать под мышкой или по диагонали. У тебя она встает по диагонали, но выгоднее встать рядом. Думаю, надо кошке добавить в оценочную функцию фактор с маленьким весом, который при прочих равных будет выбирать ход на соседнюю с мышкой клеточку. Или можно подправить функцию оценки расстояния, чтобы нахождение на одной линии с мышкой было выгоднее чем нахождение по диагонали.

Так в общем, код неплох, меня устраивает, разве что комментариев как-то маловато.
52 Кб, 604x340
#404 #575559
https://vk.com/doc10585254_368366130?hash=352462ac8c349abb79&dl=7187cc8ffa9856bf86

Есть у кого манга про базы данных переведенная на русский? С английским у меня пока не очень. Не прям, чтобы вообще пиздец. pre intermediate
#405 #575572
>>571880

По поводу редиса, правильный ответ такой:

- нам нужен AOF лог чтобы как можно чаще (например раз в секунду) надежно сбрасывать в него накопившиеся изменения
- однако, если использовать только AOF то он будет расти до бесконечности (пока не закончится место или пока не сработает AOF rewrite), потому изредка, например раз в полчаса-час мы делам RDB-дамп, который позволяет нам начать AOF лог заново с момента сохранения RDB
- настраиваем maxmemory-policy чтобы данные никогда не выкидывались при нехватке памяти
- при ошибке записи на диск редис должен отказываться принимать изменения, чтобы приложение упало и сразу была видна ошибка

> Все это чудесно в теории, но где искать настройки?


Вдумчиво читаем https://raw.githubusercontent.com/antirez/redis/2.8/redis.conf

> Мне это все читать ради 2-3 строчек, которые мне реально понадобятся?


Да. Тебе же важно знать какие еще есть настройки.

>>By default Redis does not run as a daemon.


> А у меня почему-то запускается автоматически (ставил апт-гетом).


Это значит в твоем дистрибутиве его прикрутили в автозагрузку (что обычно и требуется).

>>daemonize no


> У меня прописано yes.


Это разработчики твоего дистрибутива сделали, логично.

> Как-то можно войти в систему минуя графический интерфейс, как на настоящий сервер, чтобы оно мне не засирало память?


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

Раньше там были bash-скрипты в /etc/rc.d/ и так называемые runlevel, а сейчас используют systemd. В нем каждый сервис описывается как «таргет», и можно указывать зависимости таргетов друг от друга. Например, приложению для работы может быть необходим запущенный mysql, apache и еще что-нибудь. А Апачу необходима работающая сетевая и дисковая подсистемы.

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

Процесс загрузки с systemd описан например тут: http://manpages.ubuntu.com/manpages/utopic/man7/bootup.7.html

Там упомянута нужная опция: systemd.unit=... Значит, ты можешь добавить в загрузчик grub новый пункт «загрузиться в CLI» с этой опцией, либо добавить эту опцию в пункт по умолчанию. Для этого надо отредактировать grub.conf и затем вызвать команду, которая сгенерирует новый загрузчик. Информацию, как это сделать думаю можно найти в сети.

Во время работы системы можно переключиться в консоль через Ctrl + Alt + F1..6 и в GUI через Alt + F7 по моему.

Кстати systemd можно использовать и для добавления в автозапуск каких-то твоих скриптов. А еще как супервизор, который будет автоматически их перезапускать при ошибках.
#405 #575572
>>571880

По поводу редиса, правильный ответ такой:

- нам нужен AOF лог чтобы как можно чаще (например раз в секунду) надежно сбрасывать в него накопившиеся изменения
- однако, если использовать только AOF то он будет расти до бесконечности (пока не закончится место или пока не сработает AOF rewrite), потому изредка, например раз в полчаса-час мы делам RDB-дамп, который позволяет нам начать AOF лог заново с момента сохранения RDB
- настраиваем maxmemory-policy чтобы данные никогда не выкидывались при нехватке памяти
- при ошибке записи на диск редис должен отказываться принимать изменения, чтобы приложение упало и сразу была видна ошибка

> Все это чудесно в теории, но где искать настройки?


Вдумчиво читаем https://raw.githubusercontent.com/antirez/redis/2.8/redis.conf

> Мне это все читать ради 2-3 строчек, которые мне реально понадобятся?


Да. Тебе же важно знать какие еще есть настройки.

>>By default Redis does not run as a daemon.


> А у меня почему-то запускается автоматически (ставил апт-гетом).


Это значит в твоем дистрибутиве его прикрутили в автозагрузку (что обычно и требуется).

>>daemonize no


> У меня прописано yes.


Это разработчики твоего дистрибутива сделали, логично.

> Как-то можно войти в систему минуя графический интерфейс, как на настоящий сервер, чтобы оно мне не засирало память?


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

Раньше там были bash-скрипты в /etc/rc.d/ и так называемые runlevel, а сейчас используют systemd. В нем каждый сервис описывается как «таргет», и можно указывать зависимости таргетов друг от друга. Например, приложению для работы может быть необходим запущенный mysql, apache и еще что-нибудь. А Апачу необходима работающая сетевая и дисковая подсистемы.

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

Процесс загрузки с systemd описан например тут: http://manpages.ubuntu.com/manpages/utopic/man7/bootup.7.html

Там упомянута нужная опция: systemd.unit=... Значит, ты можешь добавить в загрузчик grub новый пункт «загрузиться в CLI» с этой опцией, либо добавить эту опцию в пункт по умолчанию. Для этого надо отредактировать grub.conf и затем вызвать команду, которая сгенерирует новый загрузчик. Информацию, как это сделать думаю можно найти в сети.

Во время работы системы можно переключиться в консоль через Ctrl + Alt + F1..6 и в GUI через Alt + F7 по моему.

Кстати systemd можно использовать и для добавления в автозапуск каких-то твоих скриптов. А еще как супервизор, который будет автоматически их перезапускать при ошибках.
43 Кб, 512x512
#406 #575578
>>575559

>не знать английский


>2015

#407 #575579
>>575559

Там простые слова, она же для детей, попробуй гуглотранслейтом хотя бы переводить или slovari.yandex.ru
#408 #575585
>>575579
ладненько, буду так читать, авось и получится.
#409 #575620
Как при отправке формы в инсерте сконкатенировать постоянное значение и значение из поля формы? Что-то типа такого должно получиться:

insert into table (field1,field2) values (:field1,'YOBA' .:field2)
#410 #575623
>>575117
Бамп.
#411 #575652
>>575438
Что там не понимать? Все просто, как в бочке. Контроллеры, рендеры. Потому что сайты по мануалам с ютаба перепечатывать надо было, а не задачки на массивы решать, страдай терь.
#412 #575654
>>575390
Просто для постороннего человека он может и будет "понятным и читабельным", но не для меня его автора, который затратил в три раза больше времени, чтобы распихать все кусочки по файлам и папкам и классам. Т.е. я даже не знаю, понятно там что-то или нет, потеря времени сводит на нет все эти "структуированные" папочки.
#413 #575704
>>575117

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

>>575654

Откуда цифра в 3 раза больше времени? Допустим у тебя код занимает 1000 строк. Какая разница, это один файл на 1000 строк или 20 файлов на 50 строк? Затраты по времени примерно одни и те же.

И насчет усилий, не знаю, я на автомате пишу как надо и у меня не уходит дополнительных усилий на причесывание кода.
74 Кб, 604x604
#414 #575729
ОП, а на твою 13 задачу по JS такого же описания как на 12 не найдется?

Или хотя бы скажи правильно ли я ее понял.

Нам нужно создать класс "Электрическая сеть" который сначала пустой, а потом добавить методы к нему:
- добавить электростанцию (выработка)
- добавить солнечную панель (выработка)
- добавить жилой дом (кол-во квартир)
- добавить линию электропередач (сколько можно передать по линии, цена за 1 мегаватт) \\Кстати у всех одинаковая цена и возможность передать мегаватты или всем разную можно задать?

- посчитать баланс(время дня): выдаст:
а) нужно закупить Х, будет стоить У
б) можно продать Х, получим прибыли У
в) не хватает линий электропередач чтобы закупить (это сделать отдельным методом)

>Используй продвинутый ООП подход для решения задачи.
Я его уже на примере прошлой задачи изучил или где-то нужно еще о нем прочитать? А то слово "продвинутый" как-то пугает :3
#415 #575732
>>575729

> Нам нужно создать класс "Электрическая сеть" который сначала пустой, а потом добавить методы к нему:


Нет. Ведь это не позволит нам добавлять новые виды потребителей без переписывания кода и вообще некрасиво как-то. Откуда ЭлектроСеть знает все возможные виды элементов которые к ней можно подключить? Она не знает, это не ее дело, ее дело лишь считать баланс.

Метод, очевидно, должен быть такой: добавитьЭлементСети(элемент)

Перечитай пасту про решение ООП задач:

--------

Когда ты решаешь задачу на ООП, ты должен ответить на вопросы:

- какие есть сущности, для которых мы сделаем классы?
- какие у них есть свойства
- что мы хотим от них получить (какие у них должны быть методы)
- как сущности связаны?

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

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

> Кстати у всех одинаковая цена и возможность передать мегаватты или всем разную можно задать?


У всех разная.

> или где-то нужно еще о нем прочитать?


Вообще в этих задачах предполагалось что читатель знает ООП, и лишь изучает особенности его реализации в JS. Если ты хочешь еще задач на ООП, которые помогут лучше в нем разобраться, то можешь взять учебник по PHP из ОП-поста, открыть там главу про ООП, найти задачи «Вектор» и «Кошки-Мышки» и решить их на своем любимом языке, то есть на яваскрипте.
#415 #575732
>>575729

> Нам нужно создать класс "Электрическая сеть" который сначала пустой, а потом добавить методы к нему:


Нет. Ведь это не позволит нам добавлять новые виды потребителей без переписывания кода и вообще некрасиво как-то. Откуда ЭлектроСеть знает все возможные виды элементов которые к ней можно подключить? Она не знает, это не ее дело, ее дело лишь считать баланс.

Метод, очевидно, должен быть такой: добавитьЭлементСети(элемент)

Перечитай пасту про решение ООП задач:

--------

Когда ты решаешь задачу на ООП, ты должен ответить на вопросы:

- какие есть сущности, для которых мы сделаем классы?
- какие у них есть свойства
- что мы хотим от них получить (какие у них должны быть методы)
- как сущности связаны?

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

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

> Кстати у всех одинаковая цена и возможность передать мегаватты или всем разную можно задать?


У всех разная.

> или где-то нужно еще о нем прочитать?


Вообще в этих задачах предполагалось что читатель знает ООП, и лишь изучает особенности его реализации в JS. Если ты хочешь еще задач на ООП, которые помогут лучше в нем разобраться, то можешь взять учебник по PHP из ОП-поста, открыть там главу про ООП, найти задачи «Вектор» и «Кошки-Мышки» и решить их на своем любимом языке, то есть на яваскрипте.
#416 #575734
>>575620

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

>>575652

Еды здесь нет, тролль, и к тому же ты скучный и пишешь одно и то же весь тред.
#417 #575736
>>575456
Так что тут не так?
Тебя смущает вызов метода в кавычках или модификатор доступа?
Этот метод вызывается только внутри класса, поэтому protected уместен.

А вот почему вызов метода работает в двойных кавычках, сам не понял, но он работает.
#418 #575738
>>575736

Меня смущает то, что мы храним keyPrefix в адаптерах редиса, но используем в VisitCounter. Тебе это не напоминает нарушение инкапсуляции? Наверно, настройку логично хранить в том классе где она нужна?

Соответственно, надо рассмотреть варианты:

- перенести настройку в VisitCounter
- перенести получение и использование ключа в адаптер редиса. Например, сделав его более высокоуровневым, чтобы в нем были не методы «lrange», а «прочитать блок из очереди»
#419 #575739
>>575736

> А вот почему вызов метода работает в двойных кавычках, сам не понял, но он работает.


Потому что это разрешено правилами: http://php.net/manual/ru/language.types.string.php#language.types.string.parsing
#420 #575741
>>575732

Ничего себе там задачи. Они ведь намного сложнее ну уж точно объемнее чем эта на электросеть. Да и граждане сверху говорили что-то про полгода решения кошек-мышек. Нет, уж лучше их не буду пока трогать. Тем более, что они под другой язык написаны. Ведь после JS я собирался у тебя же здесь учить и PHP, вот тогда и решу. А за теорией если что загляну в JS тред или гугл.
#421 #575749
>>575738
Значит я не понимаю, что такое инкапсуляция. Определение читал сто раз, но не понимаю практического смысла.

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


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

Пример с википедии
https://ru.wikipedia.org/wiki/%D0%98%D0%BD%D0%BA%D0%B0%D0%BF%D1%81%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)

class A
{
private $a; // скрытое свойство
private $b; // скрытое свойство
private function DoSomething() //скрытый метод
{
//actions
}

public function ReturnSomething() //открытый интерфейс
{
//actions
}
}

> В этом примере закрыты свойства $a и $b для класса A с целью предотвращения повреждения этих свойств другим кодом, которому необходимо предоставить только права на чтение.


У меня так же свойство объявлено protected, и есть геттер, который возвращает его значение.

>перенести получение и использование ключа в адаптер редиса. Например, сделав его более высокоуровневым, чтобы в нем были не методы «lrange», а «прочитать блок из очереди»


А что тогда останется в главном классе счетчика, если все перенести в адаптеры? Может он тогда вообще не нужен?
#421 #575749
>>575738
Значит я не понимаю, что такое инкапсуляция. Определение читал сто раз, но не понимаю практического смысла.

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


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

Пример с википедии
https://ru.wikipedia.org/wiki/%D0%98%D0%BD%D0%BA%D0%B0%D0%BF%D1%81%D1%83%D0%BB%D1%8F%D1%86%D0%B8%D1%8F_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)

class A
{
private $a; // скрытое свойство
private $b; // скрытое свойство
private function DoSomething() //скрытый метод
{
//actions
}

public function ReturnSomething() //открытый интерфейс
{
//actions
}
}

> В этом примере закрыты свойства $a и $b для класса A с целью предотвращения повреждения этих свойств другим кодом, которому необходимо предоставить только права на чтение.


У меня так же свойство объявлено protected, и есть геттер, который возвращает его значение.

>перенести получение и использование ключа в адаптер редиса. Например, сделав его более высокоуровневым, чтобы в нем были не методы «lrange», а «прочитать блок из очереди»


А что тогда останется в главном классе счетчика, если все перенести в адаптеры? Может он тогда вообще не нужен?
p-5ch #422 #575750
ОП, посмотри Вектор пожалуйста:
https://github.com/p-5ch/vector
Я там еще из задачи про студентов пару вещей попробовал. Как то очень громоздко получилось.
#423 #575762
>>575749

В данном случае я имел в виду что если keyPrefix нужен только VisitCounter то логично его в нем и хранить и убрать публичные геттеры. таким образом, это свойство станет спрятано внутри VC (инкапсулировано) и все будет логично. Или же сделать, чтобы оно использовалось не в VC, а в адаптере редиса, опять-таки, будет логично.

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

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

> У меня так же свойство объявлено protected, и есть геттер, который возвращает его значение.


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

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

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


Посмотрим, будет не нужен - всегда можно удалить. Если архитектура хорошая, это особых проблем не вызовет.
#424 #575763
>>575749

Кстати, раз мы заговорили про ООП, архитектуру, то я просто должен дать тебе ссылку про выпечку хлеба на ООП (не помню, может уже давал раньше):

http://habrahabr.ru/post/153225/
#426 #575765
>>575741

Слушай ОП, а вообще веб программисту нужно знание ООП JS? Или это все на PHP пишется? Вообще есть ли смысл сейчас изучать ООП на примере JS или перейти к DOM, а с ООП дальше разбираться при изучении PHP?
#427 #575766
>>575765

Есть смысл больше упора делать на DOM и затем jQuery, ООП это более сложная тема. Но основы ООП (на уровне задач 11, 12) стоит знать так как в JS почти все это объекты.
119 Кб, 960x540
#428 #575787
Доброе утро, котятки.:3
126 Кб, 1024x768
#429 #575803
>>575787
Доброе утро, Котик! Я вот поставил Debian и немножко поигрался с консолью, но почему-то он тормазит под VirtualBox, хотя в настройках я выкрутил все на максимум. Сейчас пойду в магазин а потом буду либо гуглить, либо спршаивать тут В интернетах все такое сомнительное, пишут что-то докачивать, устанавливать - я думал Линукс будет чувствовать себя комфортно в любых средах (символПенгвинчика)

А в целом мне нравиться эта ОСь - выглядит приятно.

Все я побежал. Удачи!
#430 #575805
>>575787
так и не решил :(
#431 #575825
>>575803
Vmware лучше, там ничего не тормозит. А если ещё. VmTools поставятся, то вообще шикарно.
#432 #575846
>>575803
Зойчем ты Gnome3 поставил?
Ставь mate/xfce/lxde и не будет никаких тормозов
19 Кб, 367x802
#433 #575847
>>575704
Лишнее время у меня уходит на создание файлов, создание классов, потом расфасофка функций по методом, потом создание объектов классов, потом вызов их методов. Вот этот весь принцип ООП. Конечно, код в контроллерах слегка сокращается, но не намного.
А ведь мне еще валидатор, пейджер, класс для чекера кукисов для эдита и публичности файла. Конечно, так оно все будет логично красиво и структуировано, но времени тратится пиздец.
#434 #575891
>>571502
Я вообще не понимаю, как можно "выучить" это "от корки до корки" не сделав ни одного сайта, не зная МВК и ООП. Типа просто зубришь синтаксис без понимания его использования?
#435 #575901
http://docs.slimframework.com/routing/put/
Unfortunately, modern browsers do not provide native support for HTTP PUT requests. To work around this limitation, ensure your HTML form’s method attribute is “post”, then add a method override parameter to your HTML form like this:

смешной костыль. чего бы просто пост не использовать в контроллере для апдейта.
#436 #575907
Можете сказать, правильная ли регулярка для поиска <div class="img"></div>?
$regexp='|<div class=["]img["]>([^"]*)</div>|';
#437 #575913
Кстати, почитывая слим, почему бы не принимать пост запросы через такой метод? $paramValue = $app->request->post('paramName');
#438 #575933
Вы тут умные вещи обсуждаете, а я снова вкачусь с вопросом уровня домохозяйка/10 уж простите.
Вообще, стоит ли как следует упороться виртуалками + убунтой/дебианом/ или это нужно только для самообразования и лучше пока просто продолжать решать задачки, развивать мышление и т.п.?
7 Кб, 383x120
4 Кб, 241x114
3 Кб, 223x74
#439 #575939
Пишет кто-нибудь в Атоме? У меня нубский вопрос, но немогу нагуглить. У меня со сниппетами проблема. На 1-м пике, то что я пишу. Далее я нажимаю TAB и получаю хуйню на втором пике. А хочу, чтобы было как на пике 3. Т.е. не хочу разворачивать снипет для else, а перейти сразу в тело функции.
#441 #575946
>>575942
Я пробовал webstorm и она тормозит на моей нищепеке, думаю с phpstrom такаяже хуйня будет. А вообще, я хотел в js-тред написать, ошибся.
#442 #575956
>>575946
На моей нищепеке атом тормозит хуже штормов.
#443 #575958
>>575956
Ну хуй знает. Может штормы хуево оптимизированны под мой амд. Атом работает более-менее сносно.
sage #444 #575959
>>575946

>Я пробовал webstorm и она тормозит на моей нищепеке


Тут дело не совсем в пеке.

>>575956

>На моей нищепеке атом тормозит хуже штормов.


Кокой токой атом? Каторый скайп????
#445 #575960
>>575959

>Кокой токой атом?


https://atom.io/
6 Кб, 587x122
sage #446 #575966
>>575960
Благодарю за копетанство.
Вот сравнение одного из их поделия. Причём это интелижевское поделие ещё без плагинов, открытого жава проекта и жава системы сборки. Удачи.
#447 #575982
>>575939
кстати симпатичная ide, в сравнении с тем же phpstorm'ом

правда, а как код то запустить? чтобы результат глянуть
#448 #575987
>>575982
аннет, текстовый редактор, хуева
#449 #575989
>>575907
Зачем квадратные скобки вокруг ["] ?
Квадратными скобками задается диапазон, например [123] либо 1, либо 2, либо 3.
И там кстати могут быть не только двойные, но и одинарные кавычки, а может и не быть. Значит правильнее ['"]?
Пробелов между div и class может быть несколько, и даже не пробел, а символ табуляции или переноса строки.
Нужно \s+
#450 #576084
Охохох, неужели нет никакой консолечки для PHP?

Мне бы просто выяснить несколько ньюансов по мере их появления. Например вот щас переклинило: а пустой масив при приведение к булеву это тру или фалс? Типа что вернет if($_GET), если он пустой? Вернет тру, в таких случаях поможет var_dump((bool)$_GET). Ну это один из примеров.

А так получается нужно написать отдельный файл и провести там опыт. А была бы консолечка: пиздык-пиздык и готово, пока мысли не разбежались.
#451 #576085
>>576084

> Вернет тру


Вернет тру если есть хотя бы одна ячейка, хоть и пустая. Вот.
#452 #576087
>>576084
Есть.
#453 #576090
>>576087
Анус мамаши ставишь? Давай ссылки.
77 Кб, 683x1024
#454 #576095
Не могу заставить класс контроллера в Silex принимать параметр id.

Sorry, the page you are looking for could not be found.

Подскажи, пожалуйста, анон, поскорее.

Код index.php http://ideone.com/5lR8TU

Код контролера: http://ideone.com/LhmLxB
#455 #576130
>>576090
Я хамам в интернете не помогаю. Извинись и попроси по нормальному.
#456 #576137
>>575939
А я, вот, не люблю автодополнение. Отключил, и не знаю проблем с автодополнением. Единственный сниппет, который использую - генератор геттеров/сеттеров. Надо будет ещё xdebug прикрутить.
#457 #576148
>>576095

>$app->get('/product/{$id}', 'Controllers\IndexController::viewProduct')->bind('single.product');


>'/product/{$id}'


В этой строчке что-то не так. Чтобы увидеть, что именно - достаточно заглянуть на главную страницу сайта фреймворка.
#458 #576160
>>576130
Пошел нахуй, хомяк)))
#459 #576169
>>576130
Ты общаешься с разными людьми. Но я понял, что максимум что ты знаешь это про php cli, то есть нихуя ты не знаешь, уеба. А значит анус твоей мамаши уходит в зрительный зал.
#460 #576170
мухосранск-репортинг:
Мои соседи сейчас пилят дрова (на шестом этаже), а их дети играют в игру "кто не скачет, тот проиграл". Выходные же, каждый развлекается как может.

>>575763
Читал эту статью на хабре.
Не знаю, в чем ее цель (скорее всего пост юмористический, хотя нердский юмор очень специфичен) и к каким выводам подталкивает (скорее всего к использованию принципа KISS), но на данный момент соглашусь с кем-то из комментаторов в том, что нужно искать середину между этими двумя подходами. Один программист строит сложные схемы по шаблонам, в которых судя по всему плохо разбирается. Второй впадает в другую крайность, и сбрасывает весь код в "кучу", в которой разобраться кстати потом будет наверное не легче, чем в сложных диаграммах классов слева. Хотя добавить несколько лишних строк по требованию заказчика легко и быстро, это да.
В общем, мне кажется, что нужно придерживаться kiss, но и не забывать при явной необходимости про паттерны, все-таки они тоже не для мебели существуют.

>>575762

>Адаптер редиса - это переходник, подстраивающий разные драйвера под один общий интерфейс


А, ну тогда ладно, значит я плохо понимал, что такое адаптер и в чем его задача.
Я планировал все относящееся к редису (префикс ключей и их ttl) хранить в объекте адаптера редиса, а все относящееся к базе в объекте адаптера базы.
Если задача адаптера исключительно в том, чтобы подстроить драйвер под интерфейс, и ничего более, тогда я начинаю понимать суть твоих претензий.
И приведи еще примеры адаптеров, потому что тут не до конца ясно.

>>575764

>SOLID


Да, вот как раз мне непонятна "единая ответственность" Адаптера, поэтому код оказался немного размазан по классам, в этом проблема.
Я не могу четко сформулировать, в чем задача адаптера.

>принцип открытости/закрытости


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

Остальное нужно переварить, беглым прочтением не обойтись.
#460 #576170
мухосранск-репортинг:
Мои соседи сейчас пилят дрова (на шестом этаже), а их дети играют в игру "кто не скачет, тот проиграл". Выходные же, каждый развлекается как может.

>>575763
Читал эту статью на хабре.
Не знаю, в чем ее цель (скорее всего пост юмористический, хотя нердский юмор очень специфичен) и к каким выводам подталкивает (скорее всего к использованию принципа KISS), но на данный момент соглашусь с кем-то из комментаторов в том, что нужно искать середину между этими двумя подходами. Один программист строит сложные схемы по шаблонам, в которых судя по всему плохо разбирается. Второй впадает в другую крайность, и сбрасывает весь код в "кучу", в которой разобраться кстати потом будет наверное не легче, чем в сложных диаграммах классов слева. Хотя добавить несколько лишних строк по требованию заказчика легко и быстро, это да.
В общем, мне кажется, что нужно придерживаться kiss, но и не забывать при явной необходимости про паттерны, все-таки они тоже не для мебели существуют.

>>575762

>Адаптер редиса - это переходник, подстраивающий разные драйвера под один общий интерфейс


А, ну тогда ладно, значит я плохо понимал, что такое адаптер и в чем его задача.
Я планировал все относящееся к редису (префикс ключей и их ttl) хранить в объекте адаптера редиса, а все относящееся к базе в объекте адаптера базы.
Если задача адаптера исключительно в том, чтобы подстроить драйвер под интерфейс, и ничего более, тогда я начинаю понимать суть твоих претензий.
И приведи еще примеры адаптеров, потому что тут не до конца ясно.

>>575764

>SOLID


Да, вот как раз мне непонятна "единая ответственность" Адаптера, поэтому код оказался немного размазан по классам, в этом проблема.
Я не могу четко сформулировать, в чем задача адаптера.

>принцип открытости/закрытости


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

Остальное нужно переварить, беглым прочтением не обойтись.
#461 #576171
>>576160
>>576169
Каждый раз проигрываю с этих школьников)
#462 #576326
>>572049
>>571958

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

Ну и обрати внимание на эту строку:

> meta_key - The meta_key in the wp_usermeta table for the meta_value to be returned. See get_userdata() for the possible meta keys.


Проверь есть ли в wp_usermeta твое поле, по которому ты хочешь фильтрвать.

Также, в документации параметры передаются массивом, а у тебя в первом коде строкой:

> '&offset='.$offset.'&number='.$number);



Во втором примере кода ты передаешь огромный массив, но по моему ты передаешь лишние элементы. например элемент include описан так в документации:

> include - An array of IDs. Only users matching these IDs will be returned. Note


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

>>572049

> Какая-то тормозная жесть выходит.


Вроде нормальный алгоритм.

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


Тогда да, придется задавать юзеров без имени. Хорошо бы их помечать как-то например полем is_anonymous = 1 или is_registered = 0

>>572239

Тут есть варианты, можно с сервера вернуть JSON для новых собщений и рендерить их на клиенте, можно с сервера вернуть массив HTML-блоков и просто вставлять их в нужные места страницы.

>>572362

Да, там надо сделать несколько переменных, в которых хранится запомненный знак, накапливается число и тд.
#462 #576326
>>572049
>>571958

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

Ну и обрати внимание на эту строку:

> meta_key - The meta_key in the wp_usermeta table for the meta_value to be returned. See get_userdata() for the possible meta keys.


Проверь есть ли в wp_usermeta твое поле, по которому ты хочешь фильтрвать.

Также, в документации параметры передаются массивом, а у тебя в первом коде строкой:

> '&offset='.$offset.'&number='.$number);



Во втором примере кода ты передаешь огромный массив, но по моему ты передаешь лишние элементы. например элемент include описан так в документации:

> include - An array of IDs. Only users matching these IDs will be returned. Note


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

>>572049

> Какая-то тормозная жесть выходит.


Вроде нормальный алгоритм.

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


Тогда да, придется задавать юзеров без имени. Хорошо бы их помечать как-то например полем is_anonymous = 1 или is_registered = 0

>>572239

Тут есть варианты, можно с сервера вернуть JSON для новых собщений и рендерить их на клиенте, можно с сервера вернуть массив HTML-блоков и просто вставлять их в нужные места страницы.

>>572362

Да, там надо сделать несколько переменных, в которых хранится запомненный знак, накапливается число и тд.
#463 #576493
>>571996

Если иксы падают, в таких случаях стоит смотреть логи в /var/log, правда я не знаю какие именно, логи xdm или может еще что-то.

>>572004

Изучить учебник из ОП-поста мало, это лишь основы PHP. Хорошо бы до файлообменника хотя бы дойти.

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


Поищи в треде слово собеседование, там есть список.

> как/чем набить портфолио?


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

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

>>571005

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


Нет конечно, в таком случае у нас будет характеристика «максимальная скорость в км/ч», значения которой - обычные числа. Например:

car.setMaxSpeed(180); // задаем макс. скорость

Константы нужны когда если несколько вариантов значения, и его так просто не выразить числом, например автоматическая коробка/ручная, бензиновый двигатель или электрический. То, что меряется цифрами, конечно должно в виде цифр и храниться. Цены и калории не стоит хранить в константах. А тип начинки - стоит.

>>572739

Yii2, затем симфони 2
#463 #576493
>>571996

Если иксы падают, в таких случаях стоит смотреть логи в /var/log, правда я не знаю какие именно, логи xdm или может еще что-то.

>>572004

Изучить учебник из ОП-поста мало, это лишь основы PHP. Хорошо бы до файлообменника хотя бы дойти.

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


Поищи в треде слово собеседование, там есть список.

> как/чем набить портфолио?


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

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

>>571005

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


Нет конечно, в таком случае у нас будет характеристика «максимальная скорость в км/ч», значения которой - обычные числа. Например:

car.setMaxSpeed(180); // задаем макс. скорость

Константы нужны когда если несколько вариантов значения, и его так просто не выразить числом, например автоматическая коробка/ручная, бензиновый двигатель или электрический. То, что меряется цифрами, конечно должно в виде цифр и храниться. Цены и калории не стоит хранить в константах. А тип начинки - стоит.

>>572739

Yii2, затем симфони 2
#464 #576496
>>573593

Да, бывает. Ты сам можешь так сделать, например с помощью htaccess перенаправить все запросы на index.php (т.е. чтобы при обращении например по URL example.com/hello/world вызывался index.php), а в нем уже с помощью ифов и регулярок анализировать чему равен REQUEST_URI и выводить ту или иную страницу.

>>573618

У меня не спрашивали, но наверно могут.

>>573699

Не знаю, поищи библиотеки HTTP-клиентов.

>>573899

А как ты проверил что index.php не вызвается? Поставил die('Yes'); в начале? Возможно что у тебя не работает или отключен htaccess по каким-то причинам. Какая версия сервера? Что в конфиге Апача (httpd.conf)? Надеюсь, не сборка какая-нибудь?

htaccess разрешается/включается настройкой AllowOverride в конфиге по моему.

>>573936

В случае файлообменника мы создаем классы-сервисы как «синглтоны» в Слиме, там есть нужный функционал: http://docs.slimframework.com/di/overview/#singleton-resources

Незачем загромождать код контроллера.

ПРавильно ты сделал или нет, по маленькому кусочку кода на скриншоте я сказать не могу. Я же не знаю что у тебя в классе Cookie или Token. Но неправильно что ты делаешь класс для кук, в Слиме уже есть для этого функционал.

>>574211

> Как мне записать массив ошибок $error[0] и тд в условиях?


Внутри if работа с массивом делается так же как и в любом другом месте. А ты с массивами умеешь работать? Что-то я не понял суть вопроса.
#464 #576496
>>573593

Да, бывает. Ты сам можешь так сделать, например с помощью htaccess перенаправить все запросы на index.php (т.е. чтобы при обращении например по URL example.com/hello/world вызывался index.php), а в нем уже с помощью ифов и регулярок анализировать чему равен REQUEST_URI и выводить ту или иную страницу.

>>573618

У меня не спрашивали, но наверно могут.

>>573699

Не знаю, поищи библиотеки HTTP-клиентов.

>>573899

А как ты проверил что index.php не вызвается? Поставил die('Yes'); в начале? Возможно что у тебя не работает или отключен htaccess по каким-то причинам. Какая версия сервера? Что в конфиге Апача (httpd.conf)? Надеюсь, не сборка какая-нибудь?

htaccess разрешается/включается настройкой AllowOverride в конфиге по моему.

>>573936

В случае файлообменника мы создаем классы-сервисы как «синглтоны» в Слиме, там есть нужный функционал: http://docs.slimframework.com/di/overview/#singleton-resources

Незачем загромождать код контроллера.

ПРавильно ты сделал или нет, по маленькому кусочку кода на скриншоте я сказать не могу. Я же не знаю что у тебя в классе Cookie или Token. Но неправильно что ты делаешь класс для кук, в Слиме уже есть для этого функционал.

>>574211

> Как мне записать массив ошибок $error[0] и тд в условиях?


Внутри if работа с массивом делается так же как и в любом другом месте. А ты с массивами умеешь работать? Что-то я не понял суть вопроса.
#465 #576498
>>574481

> непонятно, куда это все "логируется" и что выводится в случае ошибки на экран - пустота?_?.


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

Непойманные исключения завершают программу и записываются в стандартный лог ошибок - туда же куда и другие виды ошибок. Расположение лога зависит от настроек php.ini: http://php.net/manual/ru/errorfunc.configuration.php#ini.error-log

По умолчанию при работе под Апачом ошибки сохраняются в лог ошибок Апача, его местополложение задается в конфиге Апача, по умолчанию в линуксе это /var/log/apache2/.., в винде - папка logs в папке Апача.

Вывод ошибок на экран управляется директивой php.ini display_errors: http://php.net/manual/ru/errorfunc.configuration.php

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

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

Если ты вместо заглушки слима ставишь свою, обязанность логгировать исключения ложится на тебя. для этого есть стандартная функция error_log: http://php.net/manual/ru/function.error-log.php

Повторим:

- настройка display_errors включает вывод ошибок и непойманных исключений на экран, никак не влияя на логи. На продакшене мы ее отключаем.
- настройка error_reporting позволяет игнорировать (и не писать в логи) некоторые виды ошибок. Этим пользуются только быдлокодеры которым лень их искать и исправлять.
- функция error_log() позволяет записать сообщение в стандартный лог ошибок

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

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

Вообще, механизм ошибок в PHP спроектирован не удачно. Правильно не делить ошибки на виды, а в любой непонятной ситуации выбрасывать исключение и завершать программу. Только так можно быть уверенным что ошибку заметят и исправят. Слим именно так и делает - он преобразует любые виды ошибок в исключения.
#465 #576498
>>574481

> непонятно, куда это все "логируется" и что выводится в случае ошибки на экран - пустота?_?.


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

Непойманные исключения завершают программу и записываются в стандартный лог ошибок - туда же куда и другие виды ошибок. Расположение лога зависит от настроек php.ini: http://php.net/manual/ru/errorfunc.configuration.php#ini.error-log

По умолчанию при работе под Апачом ошибки сохраняются в лог ошибок Апача, его местополложение задается в конфиге Апача, по умолчанию в линуксе это /var/log/apache2/.., в винде - папка logs в папке Апача.

Вывод ошибок на экран управляется директивой php.ini display_errors: http://php.net/manual/ru/errorfunc.configuration.php

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

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

Если ты вместо заглушки слима ставишь свою, обязанность логгировать исключения ложится на тебя. для этого есть стандартная функция error_log: http://php.net/manual/ru/function.error-log.php

Повторим:

- настройка display_errors включает вывод ошибок и непойманных исключений на экран, никак не влияя на логи. На продакшене мы ее отключаем.
- настройка error_reporting позволяет игнорировать (и не писать в логи) некоторые виды ошибок. Этим пользуются только быдлокодеры которым лень их искать и исправлять.
- функция error_log() позволяет записать сообщение в стандартный лог ошибок

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

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

Вообще, механизм ошибок в PHP спроектирован не удачно. Правильно не делить ошибки на виды, а в любой непонятной ситуации выбрасывать исключение и завершать программу. Только так можно быть уверенным что ошибку заметят и исправят. Слим именно так и делает - он преобразует любые виды ошибок в исключения.
https://github.com/someApprentice/Cat-and-Mouse #466 #576499
>>574491

> Как сокращать такие длинные условия?


Вынесением части условия в переменные с понятным именем:

$isInsideMap = $this->getWorld()->isInsideMap($forX, $forY);
$isOccupied (занята ли клетка) = $this->getWorld()->determineTheObject($forX, $forY);

if (!$isInsideMap || $isOccupied) {
...
}

(обрати внимание на знак «не» перед isInsideMap - у тебя его почему-то нет и наоборот, отсеиваются хорошие ходы).

Также, можно вынести проверку доступности клетки в отдельный метод:

if ($this->canMoveTo($x, $y)) {
...
}

Давай начнем с обзора класса Animal. Давай посмотрим на список абстрактных методов у животного:

- abstract function getSymbol();
- abstract function getAllMoves($x, $y);
- abstract function rateMoves($moves, $search);
- abstract public function move();

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

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

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

- public function returnWorldToTheAnimal($world) {
- public function deleteWorldFromTheAnimal() {
- public function getCoordinate() {
- public function getX() {
- public function getY() {
- public function getView() {
- public function getSpeed() {
- public function getFears() {
- public function getTracks() {
- public function isItDie() {
- public function getWorld() {
- public function searchAnimalsAroundByType(Animal $animal, array $types) {
- public function foundTheNearestAnimal($search) {
- public function isItNotOneOfTrack($x, $y, $tracks) {
- public function isItCorner($x, $y) {
- public function howManyMovesWillDoAnimal(Animal $animal, $distance) {
- public function chooseTheMovement($ratedMoves) {
....

И так далее. Не многовато ли? Есть необходимость вызывать все эти функции снаружи? Надо ставить как можно более ограниченный доступ. Вот у тебя тут 20 функций public и программист вынужден их все просматривать чтобы понять как класс работает. А было бы меньше public функций - было бы проще читать код.

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

Я приводил в треде пример про кофе-машину:

-------

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

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

--------

У тебя слишком много информации выставлено наружу. Это усложняет понимание кода.

https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L7

> protected $speed;


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

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

> public function returnWorldToTheAnimal($world) {


Нужен тайп хинт.

> $this->world = false; //Так правильно?


Обычно отсутствие объекта обозначают как null. false это «ложь» и используется как противоположность true. А null как раз специально и придуман чтобы обозначить отсутствие объекта.

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L51


> public function getFears() {


> return $this->fears;


Ошибка: объект не может обращаться к полям которых в нем нет. То, что они есть в потомках, не имеет значения. Надо либо добавить это поле в Animal либо перенести метод в наследника.

> public function searchAnimalsAroundByType(Animal $animal, array $types) {


Эту функцию логичнее поместить в World. Это его обязанность знать какие где животные и предоставлять информацию всем желающим.

> public function foundTheNearestAnimal($search) {


Здесь можно не создавать промежуточный массив, а сортировать список животных, вычисляя расстояние до каждого прямо в функции сравнения. Или же, можно еще укоротить код:

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

> public function isItNotOneOfTrack($x, $y, $tracks) {


1) имя запутанное. Почему нельзя сделать функцию isOneOfTrack, у которой более короткое и понятное название?
2) функция возвращает либо false либо объект. Но функции is... обычно возвращают true/false.

> abstract function rateMoves($moves, $search);


Почему так запутанно? В моем понимании функция оценки берет на вход координаты клеточки и возвращает оценку. Просто и понятно. А что принимает эта функция? Массив ходов и какой-то непонятный массив search. Тебе не кажется что это как-то сложнее получается? Ради чего усложняем функцию?

> $ratedMoves = array_shift($ratedMoves);


Вот это нехорошо. У тебя был в переменной массив ходов, а остался один ход. Для этих целей надо использовать разные переменные.

> public function KillTheAnimal() {


> return true;


Зачем возвращать что-то если всегда возвращается только true? Какую полезную информацию это дает вызвавшему метод?

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Cat.php#L84


> $this->world->isInsideMap($move['x'], $move['y']);


Зачем вызывать этот метод если ты не проверяешь, что он вернет?

> $animal->KillTheAnimal();


Этот метод назван неудачно. $mouse->killTheAnimal читается как «мышь, убей это животное», а не «мышь, ты убита». Надо дать другое название, например $mouse->setKilled (пометить убитой), $mouse->makeDead() (сделать мертвой) или $mouse->setIsDead() или $mouse->removeSelf() (удалить себя). killOneself не предлагаю, а то твой гитхаб закроют за пропаганду суицида.

Наконец еще можно при съедении животного сразу делать $world->remove... то есть обращаться не к животному, а к миру.

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Cat.php#L95


>return $move;
Не очень понятно зачем тут return, эти данные кому-то нужны? Мы не можем их получить через getX/Y?

> if (($forX > $x and $forY > $y) or ($forX > $x and $forY < $y)


Не понимаю что и зачем тут проверяется

> Нужна ли проверка is_a($object, "Animal")?


is_a не надо использовать, лучше использовать оператор instanceof. Думаю, проверка не нужна так как кроме животных на карте никого нет.

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Mouse.php#L39


Здесь не очень просто понять как считается число очков. Сделай отдельные факторы в отдельных переменных и складывай их в конце с весом:

rate = w1 × factor1 + w2 × factor2...

(только имена конечно нужны понятные).

> already have it object - {get_class($animal)}"


Функция get_class не вызовется, а будет ошибка из-за невозможности преобразовать $animal в строку

> public function isInsideMap($x, $y) {


Результат который возвращает функция противоположен ее названию
https://github.com/someApprentice/Cat-and-Mouse #466 #576499
>>574491

> Как сокращать такие длинные условия?


Вынесением части условия в переменные с понятным именем:

$isInsideMap = $this->getWorld()->isInsideMap($forX, $forY);
$isOccupied (занята ли клетка) = $this->getWorld()->determineTheObject($forX, $forY);

if (!$isInsideMap || $isOccupied) {
...
}

(обрати внимание на знак «не» перед isInsideMap - у тебя его почему-то нет и наоборот, отсеиваются хорошие ходы).

Также, можно вынести проверку доступности клетки в отдельный метод:

if ($this->canMoveTo($x, $y)) {
...
}

Давай начнем с обзора класса Animal. Давай посмотрим на список абстрактных методов у животного:

- abstract function getSymbol();
- abstract function getAllMoves($x, $y);
- abstract function rateMoves($moves, $search);
- abstract public function move();

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

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

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

- public function returnWorldToTheAnimal($world) {
- public function deleteWorldFromTheAnimal() {
- public function getCoordinate() {
- public function getX() {
- public function getY() {
- public function getView() {
- public function getSpeed() {
- public function getFears() {
- public function getTracks() {
- public function isItDie() {
- public function getWorld() {
- public function searchAnimalsAroundByType(Animal $animal, array $types) {
- public function foundTheNearestAnimal($search) {
- public function isItNotOneOfTrack($x, $y, $tracks) {
- public function isItCorner($x, $y) {
- public function howManyMovesWillDoAnimal(Animal $animal, $distance) {
- public function chooseTheMovement($ratedMoves) {
....

И так далее. Не многовато ли? Есть необходимость вызывать все эти функции снаружи? Надо ставить как можно более ограниченный доступ. Вот у тебя тут 20 функций public и программист вынужден их все просматривать чтобы понять как класс работает. А было бы меньше public функций - было бы проще читать код.

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

Я приводил в треде пример про кофе-машину:

-------

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

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

--------

У тебя слишком много информации выставлено наружу. Это усложняет понимание кода.

https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L7

> protected $speed;


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

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

> public function returnWorldToTheAnimal($world) {


Нужен тайп хинт.

> $this->world = false; //Так правильно?


Обычно отсутствие объекта обозначают как null. false это «ложь» и используется как противоположность true. А null как раз специально и придуман чтобы обозначить отсутствие объекта.

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L51


> public function getFears() {


> return $this->fears;


Ошибка: объект не может обращаться к полям которых в нем нет. То, что они есть в потомках, не имеет значения. Надо либо добавить это поле в Animal либо перенести метод в наследника.

> public function searchAnimalsAroundByType(Animal $animal, array $types) {


Эту функцию логичнее поместить в World. Это его обязанность знать какие где животные и предоставлять информацию всем желающим.

> public function foundTheNearestAnimal($search) {


Здесь можно не создавать промежуточный массив, а сортировать список животных, вычисляя расстояние до каждого прямо в функции сравнения. Или же, можно еще укоротить код:

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

> public function isItNotOneOfTrack($x, $y, $tracks) {


1) имя запутанное. Почему нельзя сделать функцию isOneOfTrack, у которой более короткое и понятное название?
2) функция возвращает либо false либо объект. Но функции is... обычно возвращают true/false.

> abstract function rateMoves($moves, $search);


Почему так запутанно? В моем понимании функция оценки берет на вход координаты клеточки и возвращает оценку. Просто и понятно. А что принимает эта функция? Массив ходов и какой-то непонятный массив search. Тебе не кажется что это как-то сложнее получается? Ради чего усложняем функцию?

> $ratedMoves = array_shift($ratedMoves);


Вот это нехорошо. У тебя был в переменной массив ходов, а остался один ход. Для этих целей надо использовать разные переменные.

> public function KillTheAnimal() {


> return true;


Зачем возвращать что-то если всегда возвращается только true? Какую полезную информацию это дает вызвавшему метод?

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Cat.php#L84


> $this->world->isInsideMap($move['x'], $move['y']);


Зачем вызывать этот метод если ты не проверяешь, что он вернет?

> $animal->KillTheAnimal();


Этот метод назван неудачно. $mouse->killTheAnimal читается как «мышь, убей это животное», а не «мышь, ты убита». Надо дать другое название, например $mouse->setKilled (пометить убитой), $mouse->makeDead() (сделать мертвой) или $mouse->setIsDead() или $mouse->removeSelf() (удалить себя). killOneself не предлагаю, а то твой гитхаб закроют за пропаганду суицида.

Наконец еще можно при съедении животного сразу делать $world->remove... то есть обращаться не к животному, а к миру.

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Cat.php#L95


>return $move;
Не очень понятно зачем тут return, эти данные кому-то нужны? Мы не можем их получить через getX/Y?

> if (($forX > $x and $forY > $y) or ($forX > $x and $forY < $y)


Не понимаю что и зачем тут проверяется

> Нужна ли проверка is_a($object, "Animal")?


is_a не надо использовать, лучше использовать оператор instanceof. Думаю, проверка не нужна так как кроме животных на карте никого нет.

> https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Mouse.php#L39


Здесь не очень просто понять как считается число очков. Сделай отдельные факторы в отдельных переменных и складывай их в конце с весом:

rate = w1 × factor1 + w2 × factor2...

(только имена конечно нужны понятные).

> already have it object - {get_class($animal)}"


Функция get_class не вызовется, а будет ошибка из-за невозможности преобразовать $animal в строку

> public function isInsideMap($x, $y) {


Результат который возвращает функция противоположен ее названию
#467 #576500
>>575095

> Не осилил. Сделал через this. и метод.


Я имею в виду, цены одинаковы для всех экземпляров класса. Значит их можно сделать статическим полем, полем которое принадлежит всему классу, а не в каждом объекте свое. То есть сделать чтобы было не this.caloriesAndPrices, а Hamburger.caloriesAndPrices, и метод который их создает, тоже чтобы принадлежал классу.

А так, код в общем выглядит верно.

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


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

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

Вот, что я нашел:

- стиль от автора учебника learn.js: https://learn.javascript.ru/coding-style . Мне в нем не нравится отступ в 2 пробела, это побуждает делать большую вложенность
- гугловский стайл гайд: https://google.github.io/styleguide/javascriptguide.xml - мне нравится тем, что каждое правило объясняется, почему так а не иначе
- стайл гайд jquery, мне не нравится тем что требует использовать архаичные и сбивающие с толку табы и использует дурацкие пробелы внутри скобок: http://contribute.jquery.org/style-guide/js/

>>575323

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

>>575466

> я создаю объект класса Rediska_Command_Set, и мне нужно передать вторым аргументом название команды Set. Это значит, что при помощи класса Rediska_Command_Set можно создать не только команду Set, но и любую другую?


А где написано что это выполняемая команда? Может это просто название. Надо посмотреть код и как этот $name используется.

> Еще прописан магический метод


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

>>575741

> А за теорией если что загляну в JS тред или гугл.


Не помогут тебе там, там мало кто нормально в ООП разбирается,а в гугле и подавно.
#467 #576500
>>575095

> Не осилил. Сделал через this. и метод.


Я имею в виду, цены одинаковы для всех экземпляров класса. Значит их можно сделать статическим полем, полем которое принадлежит всему классу, а не в каждом объекте свое. То есть сделать чтобы было не this.caloriesAndPrices, а Hamburger.caloriesAndPrices, и метод который их создает, тоже чтобы принадлежал классу.

А так, код в общем выглядит верно.

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


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

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

Вот, что я нашел:

- стиль от автора учебника learn.js: https://learn.javascript.ru/coding-style . Мне в нем не нравится отступ в 2 пробела, это побуждает делать большую вложенность
- гугловский стайл гайд: https://google.github.io/styleguide/javascriptguide.xml - мне нравится тем, что каждое правило объясняется, почему так а не иначе
- стайл гайд jquery, мне не нравится тем что требует использовать архаичные и сбивающие с толку табы и использует дурацкие пробелы внутри скобок: http://contribute.jquery.org/style-guide/js/

>>575323

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

>>575466

> я создаю объект класса Rediska_Command_Set, и мне нужно передать вторым аргументом название команды Set. Это значит, что при помощи класса Rediska_Command_Set можно создать не только команду Set, но и любую другую?


А где написано что это выполняемая команда? Может это просто название. Надо посмотреть код и как этот $name используется.

> Еще прописан магический метод


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

>>575741

> А за теорией если что загляну в JS тред или гугл.


Не помогут тебе там, там мало кто нормально в ООП разбирается,а в гугле и подавно.
#468 #576502
>>575787

О, анон учит PHP с планшетом, какая редкость. Код кстати пока неправильный, насколько я вижу.

>>575803

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


Тормозит командная строка или графический интерфейс? Если второе то проблема с драйвером (нет драйвера обеспечивающего быстрый вывод данных), надо найти и установить дополнения от виртуал бокса в дебиан. По моему диск с ними «вставляется» через меню вирьуальной машины - Install VBox Additions, а дальше запускаешь находящийся на нем скрипт.

Ну и если ты поставил его для изучения, GUI тебе не нужен, отключай и заходи через ssh, например с помощью putty. Паста про настройку сетевой карты для доступа снаружи: https://gist.github.com/codedokode/420c8c12a1edae25f0ec

>>575825
>>575846

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

>>575847

> Лишнее время у меня уходит на создание файлов, создание классов,


Босюь, мне трудно поверить что создать файл или написать class X {} занимает дольше нескольких секунд.

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

>>575901

Этот костыль нужен для прикручивания браузерного кода к REST-апи. Не переделывать же АПи из-за особенностей браузера.

>>575907

Плохая. Не надо парсить HTML регулярками. Используй DOM и основанные на нем библиотеки.

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

>>575913

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

>>575933

Можно установить и потихоньку осваивать командную строку, права на файла и прочие вещи, пригодится.

>>575966

Непонятно какой именно вид памяти отображется. Например если ты последние полчаса не трогал Атом, он мог выпасть в своп и цифра уменьшится. Непонятно почему процессов атома несколько. Неизвестно какие настройки выставлены для ява машины. Также, ты сравниваешь IDE которая анализирует код с примитивным текстовым редактором - очевидно IDE нужно больше данных держать в памяти.
#468 #576502
>>575787

О, анон учит PHP с планшетом, какая редкость. Код кстати пока неправильный, насколько я вижу.

>>575803

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


Тормозит командная строка или графический интерфейс? Если второе то проблема с драйвером (нет драйвера обеспечивающего быстрый вывод данных), надо найти и установить дополнения от виртуал бокса в дебиан. По моему диск с ними «вставляется» через меню вирьуальной машины - Install VBox Additions, а дальше запускаешь находящийся на нем скрипт.

Ну и если ты поставил его для изучения, GUI тебе не нужен, отключай и заходи через ssh, например с помощью putty. Паста про настройку сетевой карты для доступа снаружи: https://gist.github.com/codedokode/420c8c12a1edae25f0ec

>>575825
>>575846

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

>>575847

> Лишнее время у меня уходит на создание файлов, создание классов,


Босюь, мне трудно поверить что создать файл или написать class X {} занимает дольше нескольких секунд.

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

>>575901

Этот костыль нужен для прикручивания браузерного кода к REST-апи. Не переделывать же АПи из-за особенностей браузера.

>>575907

Плохая. Не надо парсить HTML регулярками. Используй DOM и основанные на нем библиотеки.

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

>>575913

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

>>575933

Можно установить и потихоньку осваивать командную строку, права на файла и прочие вещи, пригодится.

>>575966

Непонятно какой именно вид памяти отображется. Например если ты последние полчаса не трогал Атом, он мог выпасть в своп и цифра уменьшится. Непонятно почему процессов атома несколько. Неизвестно какие настройки выставлены для ява машины. Также, ты сравниваешь IDE которая анализирует код с примитивным текстовым редактором - очевидно IDE нужно больше данных держать в памяти.
#469 #576504
>>575989

Ты тоже занимаешься глупостью, не стоит парсить HTML регуляркой.

>>576084

Я делаю в командной строке

php -r 'var_dump(2 + 2);'

Но надо смотреть как бы со спецсимволами не накосячить. Также, у PHP есть интерактивный режим ( http://php.net/manual/ru/features.commandline.interactive.php ), плохо работает под виндой:

php -a

После этого вводишь выражение. Есть автодополнение (не под виндой).

Также, если сторонняя программа которая делает то, что тебе нужно (такие программы называются REPL = Read, Evaluate, Print Loop) под названием Boris: http://habrahabr.ru/post/179145/

Еще есть PsySH: http://psysh.org/

Предлагаю сравнить и поделиться опытом с анонами.

>>576095

> '/product/{$id}'


Знак доллара не лишний?

>>576130

Не помогаешь - тогда уходи

>>576170

> Если задача адаптера исключительно в том, чтобы подстроить драйвер под интерфейс, и ничего более


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

> И приведи еще примеры адаптеров, потому что тут не до конца ясно.


Ну не знаю, мне кажется как раз «адаптер» редиса и есть хороший пример реализации паттерна. Адаптеры используются как раз в таких ситуациях, когда есть несколько библиотек, не имеющих единого интерфейса. Мы организовываем этот интерфейс с помощью адаптеров.

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

Примеры: адаптеры для разных драйверов БД (mysqli/PDO), разных кешей, адаптеры для превращения твоей библиотеки в плагин для фреймворка.

Можешь еще в гугле попробовать посмотреть: https://www.google.ru/search?q=%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD+%D0%B0%D0%B4%D0%B0%D0%BF%D1%82%D0%B5%D1%80&newwindow=1&gbv=1&sei=jbU_VtfRIsiqsgHh5b3ACg

> Я не могу четко сформулировать, в чем задача адаптера.


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

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


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

В случае твоей библиотеки, надо иметь возможность совместить ее с новым драйвером редиса или базы данных, или поменять какие-то настройки, не трогая код самой библиотеки. Ну то есть люди будут подключать ее через тот же композер и ничего в ней изменить напрямую не могут (и не должны).
#469 #576504
>>575989

Ты тоже занимаешься глупостью, не стоит парсить HTML регуляркой.

>>576084

Я делаю в командной строке

php -r 'var_dump(2 + 2);'

Но надо смотреть как бы со спецсимволами не накосячить. Также, у PHP есть интерактивный режим ( http://php.net/manual/ru/features.commandline.interactive.php ), плохо работает под виндой:

php -a

После этого вводишь выражение. Есть автодополнение (не под виндой).

Также, если сторонняя программа которая делает то, что тебе нужно (такие программы называются REPL = Read, Evaluate, Print Loop) под названием Boris: http://habrahabr.ru/post/179145/

Еще есть PsySH: http://psysh.org/

Предлагаю сравнить и поделиться опытом с анонами.

>>576095

> '/product/{$id}'


Знак доллара не лишний?

>>576130

Не помогаешь - тогда уходи

>>576170

> Если задача адаптера исключительно в том, чтобы подстроить драйвер под интерфейс, и ничего более


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

> И приведи еще примеры адаптеров, потому что тут не до конца ясно.


Ну не знаю, мне кажется как раз «адаптер» редиса и есть хороший пример реализации паттерна. Адаптеры используются как раз в таких ситуациях, когда есть несколько библиотек, не имеющих единого интерфейса. Мы организовываем этот интерфейс с помощью адаптеров.

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

Примеры: адаптеры для разных драйверов БД (mysqli/PDO), разных кешей, адаптеры для превращения твоей библиотеки в плагин для фреймворка.

Можешь еще в гугле попробовать посмотреть: https://www.google.ru/search?q=%D0%BF%D0%B0%D1%82%D1%82%D0%B5%D1%80%D0%BD+%D0%B0%D0%B4%D0%B0%D0%BF%D1%82%D0%B5%D1%80&newwindow=1&gbv=1&sei=jbU_VtfRIsiqsgHh5b3ACg

> Я не могу четко сформулировать, в чем задача адаптера.


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

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


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

В случае твоей библиотеки, надо иметь возможность совместить ее с новым драйвером редиса или базы данных, или поменять какие-то настройки, не трогая код самой библиотеки. Ну то есть люди будут подключать ее через тот же композер и ничего в ней изменить напрямую не могут (и не должны).
#470 #576509
Аноны, кто изучает PHP и у кого есть линукс/мак: попробуйте оболочку которая реализует интерактивную командную строку, то есть вы вводите PHP команду и она сразу же выполняется: http://psysh.org/

Там на сайте на картинках показаны еще другие возможности вроде просмотра информации о классе, какие у него есть поля и методы (включая встроенные PHP классы вроде PDO).

Я кого-то пропустил? Напомните о себе. Про анона https://github.com/p-5ch/vector/ я помню.
123 Кб, 600x960
#471 #576577
>>576504
>>576148
Спасибо, ребят. Я затупил и не посмотрел. Вообще взял Silex чисто из соображений что микрофреймворк, было бы хорошо осовить.

Взял его для совсем небольшого интернет-магазина. Правда, для очень даже солидной организации, денег дадут не много, но полная свобода с технологиями, кроме сервера, ибо он вообще у всех один. А вообще я тот анон, который устроился на работу в конце весны и работаю с Magento
#472 #576579
>>576577

Зачем писать свой магазин когда есть десятки готовых CMS, включая саму магенто, ведь достаточно взять их настроить и натянуть верстку?
#473 #576583
>>576579
Слишком много функционала, и слишком много весят, а Silex весит меньше чем, долбанный Guzzle , который я на прошлом проекте использывал. Тем более, это чудесная возможность позаниматься ООП и осовить новый фреймворк.
#474 #576584
>>576579
Ах, да, Magento медленная очень, она просто огромная, у нас на dev под Magento выделяют охуённые ресурсы, что бы не тупила.
#475 #576594
на Хабре увидел: класс в Магенто, у которого более 20 аргументов в конструкторе: https://github.com/magento/magento2/blob/2.0.0-rc/app/code/Magento/Catalog/Model/Product.php#L375

Судя по количеству аргументов и объему кода, разработчикам удалось тут реализовать паттерн God Object: https://ru.wikipedia.org/wiki/%D0%91%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%B5%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BE%D0%B1%D1%8A%D0%B5%D0%BA%D1%82

И вдобавок ниже идет функция с названием «угадай где подвох»:

> protected function _construct()

#476 #576598
Ну и вообще рекомендую бегло просмотреть репозиторий магенто: https://github.com/magento/magento2

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

Это вполне реальный проект (и как я понимаю, прибыльный, раз эта компания смогла продаться ебэю). Над ним судя по объему кода, работает немаленькая команда.

Кстати, у них и тесты есть какие-то:

https://github.com/magento/magento2/tree/develop/dev/tests
#477 #576616
Проверьте плиз.

http://ideone.com/qx873I
#479 #576636
Warning: call_user_func_array() expects parameter 2 to be array, integer given in <строка с call_user_func_array>
Как исправить? пдовыблядкам просьба пройти нахуй

function db_query($mysqli, $query, $vars) {
if(!isset($mysqli)) {
return FALSE;
}
if(!isset($query)) {
return FALSE;
}
if(!isset($vars)) {
return FALSE;
}

$stmt = $mysqli->prepare($query);

$types = str_repeat('s', count($vars));
$vars = array_unshift($vars, $types);

call_user_func_array(array($stmt, 'bind_param'), $vars);
$stmt->execute();
}
$mysqli = db_connect();

$query = 'INSERT INTO `test`(`name`, `server`) VALUES (?,?)';

$vars = array('name' => 'name', 'server' => 'server');
db_query($mysqli, $query, $vars);
#479 #576636
Warning: call_user_func_array() expects parameter 2 to be array, integer given in <строка с call_user_func_array>
Как исправить? пдовыблядкам просьба пройти нахуй

function db_query($mysqli, $query, $vars) {
if(!isset($mysqli)) {
return FALSE;
}
if(!isset($query)) {
return FALSE;
}
if(!isset($vars)) {
return FALSE;
}

$stmt = $mysqli->prepare($query);

$types = str_repeat('s', count($vars));
$vars = array_unshift($vars, $types);

call_user_func_array(array($stmt, 'bind_param'), $vars);
$stmt->execute();
}
$mysqli = db_connect();

$query = 'INSERT INTO `test`(`name`, `server`) VALUES (?,?)';

$vars = array('name' => 'name', 'server' => 'server');
db_query($mysqli, $query, $vars);
#480 #576666
>>576636
кекнул с этого говнокода.
#481 #576667
>>576636

> $vars = array_unshift($vars, $types);



>Описание


>int array_unshift ( array &$array , mixed $value1 [, mixed $... ] )


>int



Смекаешь?
#482 #576674
Почему мне рендерить слимовский апп в классах не получается? например я хочу запихнуть в класс повторяющийся код
if(1){render->(totot);}
else render(toto);
#483 #576675
>>576667
Неа
#484 #576677
>>576667
Ты имеешь ввиду что надо так?

function db_query($mysqli, $query, $vars) {
if(!isset($mysqli)) {
return FALSE;
}
if(!isset($query)) {
return FALSE;
}
if(!isset($vars)) {
return FALSE;
}

$stmt = $mysqli->prepare($query);

$types = str_repeat('s', count($vars));

> array_unshift($vars, $types);



call_user_func_array(array($stmt, 'bind_param'), $vars);
$stmt->execute();
}
$mysqli = db_connect();

$query = 'INSERT INTO `test`(`name`, `server`) VALUES (?,?)';

$vars = array('name' => 'name', 'server' => 'server');
db_query($mysqli, $query, $vars);
#484 #576677
>>576667
Ты имеешь ввиду что надо так?

function db_query($mysqli, $query, $vars) {
if(!isset($mysqli)) {
return FALSE;
}
if(!isset($query)) {
return FALSE;
}
if(!isset($vars)) {
return FALSE;
}

$stmt = $mysqli->prepare($query);

$types = str_repeat('s', count($vars));

> array_unshift($vars, $types);



call_user_func_array(array($stmt, 'bind_param'), $vars);
$stmt->execute();
}
$mysqli = db_connect();

$query = 'INSERT INTO `test`(`name`, `server`) VALUES (?,?)';

$vars = array('name' => 'name', 'server' => 'server');
db_query($mysqli, $query, $vars);
#485 #576714
>>576674
а все уже.

А это нормально запихивать все в классы и объекты классов в классы и повторяющийся код в классы, пока в контроллере не останется пара строчек?
29 Кб, 480x360
#486 #576721
>>576636

>2015


>mysqli

#487 #576827
>>575552
ОП, поправил недостатки.
https://github.com/never3ver/catsandmice

> https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L51


>Тут не >= должно быть?


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

>Так в общем, код неплох, меня устраивает, разве что комментариев как-то маловато.


Комментарии наверно специально дописывать не буду, но на будущее учту. Я могу браться за студентов?
#488 #576866
Вопрос совсем/не совсем по пхп.
Что есть для почтовых рассылок, какие сервисы? Сайт - магазин (конечно же лол), письма шлются при заказе клиенту и заказавшему + всякие там восстановления паролей и тд. 2к писем с smtp.google.com по пятницам может не хватать. Свой почтовый VPS/VDS сервер поднимать побаиваюсь, никогда не пробовал, что там делать представляю приблизительно (через пердольку поставить готовые велосипеды, настроить их), как через него отправлять - не представляю. Какие ещё есть решения?
#489 #576933
>>576594
Зачем делать конструктор защищенным? Они там синглтон мутят что ли?
Одно подчеркивание это опечатка?
>>576598
Зачем мне смотреть репозиторий magento?
Если честно, не знаю даже в какой последовательности смотреть эту тучу файлов, документацию изучать неохота.

>index.php


} catch (\Exception $e) {
echo <<<HTML
<div style="font:12px/1.35em arial, helvetica, sans-serif;">...
Зачем на лету малевать хердок, если можно подключить шаблон из файла?

$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
Чего? Зачем передавать глобальный массив в качестве параметра? 'BP' это константа что ли? А, вот она валяется в файле autoload.php, видимо это самое подходящее для нее место.
define('BP', dirname(__DIR__));

Пытаюсь отыскать класс \Magento\Framework\App\Bootstrap
Удалось это сделать только через гугл.
https://github.com/magento/magento2/blob/develop/lib/internal/Magento/Framework/App/Bootstrap.php

>Может паттерн какой знакомый увидишь.


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

Ну ладно, вернемся к нашим баранам.

Если допустить, что адаптеры для редиса являются только оберткой над клиентом, то выношу свойства $keyPrefix, $keyExpiration в класс VisitCounter.
Но теперь если быть последовательным, то нужно удалить все лишнее и из адаптера базы. Там мне необходимы такие свойства как $pk, $tblName и $colName.
Если их тоже перенести в главный класс, то появляется несколько проблем. Во-первых, эти свойства нужны только для реляционных sql хранилищ, а мы пытаемся мутить нечто универсальное, что должно работать и с NoSQL базами. Я с ними никогда не сталкивался, но думаю что там нет таблиц.
Тем не менее, мне нужен универсальный метод save у класса DbAdapter.
Объявить необязательные параметры? Выглядит костыльно:
abstract public function save(array $visits, $pk = '', $tblName = '', $colName = '');
Наверное, мне придется разобраться с тем, как устроена MongoDb и написать отдельный интерфейс под nosql.

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

Еще несколько вопросов, пока не забыл.
1. Мне еще нужно проверить, не является ли посетитель ботом. Нагуглил функцию http://php.net/manual/ru/function.get-browser.php , она вернет нужную информацию?
2. Как сделать так, чтобы композер дописывал в свою автозагрузку классы пакета?
Я знаю как прописать в composer.json, чтобы он скачал пакет с гитхаба, но не знаю, как добавить классы пакета в автозагрузку.
Могу прописать "autoload" путь к пространству имен вида
"autoload": {
"psr-4": {"RootNamespace\\": "vendor/vendor-name/package-name/"}
}
Но мне кажется это костыльно, наверняка есть правильный способ подключения.
#489 #576933
>>576594
Зачем делать конструктор защищенным? Они там синглтон мутят что ли?
Одно подчеркивание это опечатка?
>>576598
Зачем мне смотреть репозиторий magento?
Если честно, не знаю даже в какой последовательности смотреть эту тучу файлов, документацию изучать неохота.

>index.php


} catch (\Exception $e) {
echo <<<HTML
<div style="font:12px/1.35em arial, helvetica, sans-serif;">...
Зачем на лету малевать хердок, если можно подключить шаблон из файла?

$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
Чего? Зачем передавать глобальный массив в качестве параметра? 'BP' это константа что ли? А, вот она валяется в файле autoload.php, видимо это самое подходящее для нее место.
define('BP', dirname(__DIR__));

Пытаюсь отыскать класс \Magento\Framework\App\Bootstrap
Удалось это сделать только через гугл.
https://github.com/magento/magento2/blob/develop/lib/internal/Magento/Framework/App/Bootstrap.php

>Может паттерн какой знакомый увидишь.


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

Ну ладно, вернемся к нашим баранам.

Если допустить, что адаптеры для редиса являются только оберткой над клиентом, то выношу свойства $keyPrefix, $keyExpiration в класс VisitCounter.
Но теперь если быть последовательным, то нужно удалить все лишнее и из адаптера базы. Там мне необходимы такие свойства как $pk, $tblName и $colName.
Если их тоже перенести в главный класс, то появляется несколько проблем. Во-первых, эти свойства нужны только для реляционных sql хранилищ, а мы пытаемся мутить нечто универсальное, что должно работать и с NoSQL базами. Я с ними никогда не сталкивался, но думаю что там нет таблиц.
Тем не менее, мне нужен универсальный метод save у класса DbAdapter.
Объявить необязательные параметры? Выглядит костыльно:
abstract public function save(array $visits, $pk = '', $tblName = '', $colName = '');
Наверное, мне придется разобраться с тем, как устроена MongoDb и написать отдельный интерфейс под nosql.

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

Еще несколько вопросов, пока не забыл.
1. Мне еще нужно проверить, не является ли посетитель ботом. Нагуглил функцию http://php.net/manual/ru/function.get-browser.php , она вернет нужную информацию?
2. Как сделать так, чтобы композер дописывал в свою автозагрузку классы пакета?
Я знаю как прописать в composer.json, чтобы он скачал пакет с гитхаба, но не знаю, как добавить классы пакета в автозагрузку.
Могу прописать "autoload" путь к пространству имен вида
"autoload": {
"psr-4": {"RootNamespace\\": "vendor/vendor-name/package-name/"}
}
Но мне кажется это костыльно, наверняка есть правильный способ подключения.
#490 #576962
Посоны, как я могу обработать форму одновременно с текстом и картинкой одновременно и в фоне? Засунуть в базу данных, например. В большинстве примером рассматривается что-то одно и не в фоновом режиме
#491 #577113
>>576962
На сервере сохраняешь файл в нужную директорию, путь к файлу пишешь в базу.

>в фоне


В смысле "не перезагружая страницу в браузере"? Тут нужен AJAX. Чтобы осознанно работать с ним, надо бы познакомиться с яваскриптом.
#492 #577166
>>577113

> яваскрипт


Ну ладно, это не важно.

> охраняешь файл в нужную директорию, путь к файлу пишешь в базу


Это понятно, но как мне одновременно обработать и текст, и картинку? По одиночке я могу это сделать
#493 #577171
>>577166
В каком месте возникают вопросы? Текст достаешь из массива $_POST, файл - из массива $_FILES. Валидируешь, сохраняешь по очереди.
#494 #577208
>>576933

Это не конструктор, в том-то и дело, так как у конструктора 2 подчеркивания. Очевидно это внутренняя функция инициализации, которая может быть вызывается из конструктора и ей не зачем быть публичной. Но называть так функцию - плохая идея, так как я сначала не понял в чем дело и долго думал как они смогли сделать 2 конструктора в одном классе.
#495 #577209
>>577171
Я прост решил изображения в самой базе хранить
#496 #577244
>>576933

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

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

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

Хотя конечно 20 аргументов в конструкторе это признак что дело плохо и надо что-то менять.

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

> Если допустить, что адаптеры для редиса являются только оберткой над клиентом, то выношу свойства $keyPrefix, $keyExpiration в класс VisitCounter.


Но теперь если быть последовательным, то нужно удалить все лишнее и из адаптера базы. Там мне необходимы такие свойства как $pk, $tblName и $colName.
Если ты их вынесешь в VC то ты делаешь лишние ограничения: данные могут сохраняться только в базу, таблица может быть только одна, у нее должен быть первичный ключ из 1 колонки. По моему это неудобно.

> Но теперь если быть последовательным, то нужно удалить все лишнее и из адаптера базы.


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

> и с NoSQL базами. Я с ними никогда не сталкивался, но думаю что там нет таблиц.


Ну редис представь, это NoSQL хранилище без вторичных индексов (то есть искать можно только по первичному ключу) в общем-то.

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


Можешь разобраться, если хочешь и есть время.

>Зачем на лету малевать хердок, если можно подключить шаблон из файла?


Так как это фатальная ошибка. Если посмотреть то видно что там аж 2 варианта сообщения - текстовое для запуска из консоли и HTML для веба. Как я понимаю, чтобы если клиент неправильно установил магазин, он увидел не стандартную заглушку, а конкретное напоминание что он забыл сделать.

> Пытаюсь отыскать класс \Magento\Framework\App\Bootstrap


> Удалось это сделать только через гугл.


Надо было начинать с composer.json - там описаны пути для автозагрузки. Чем и хорош композер, что теперь не надо разбирать самописные автолоадеры (а в больших проектах они сложные и запутанные), а достаточно глянуть в composer.json.

> Класс VisitCounter судя по всему тоже придется разбить на два отдельных, один для работы с базой, второй для работы с редисом.


Зачем?

> Мне еще нужно проверить, не является ли посетитель ботом.


Что ты имеешь в виду под ботом? Определись. HTTP-клиент у которого стоит в юзер-агенте GoogleBot? Клиент не загружающий картинки? HTTP-клиент, не выполняющий яваскрипт код?

> Нагуглил функцию http://php.net/manual/ru/function.get-browser.php , она вернет нужную информацию?


Эта функция лишь получает данные из заголовка User-Agent и представляет их в виде массива. Читать:

https://ru.wikipedia.org/wiki/User_Agent
http://www.useragentstring.com/pages/useragentstring.php
https://en.wikipedia.org/wiki/User_agent (тут лучше чем в русской версии)

Вообще с UA связана куча нехороших историй, когда программист определяет браузер по нему и отдает ему чуть другую версию страницы, а потом выходит новая версия браузера и все ломается. Это настолько масштабно, что почти все браузеры (IE, opera, chrome, firefox) содержат в UA строку 'Mozilla' - так как раньше было всего 2 браузера: Mozilla Firefox (поддерживал стандарты) и IE6 (не поддерживал) и по этой строке UA вебмастера определяли какой перед ними браузер и отдавали им разный код. Сейчас все браузеры поддерживают стандарты, но быдлокод с проверкой UA остался на сайтах и в учебниках, и все браузеры включают в UA строку Mozilla.

И не только.

Вот например UA браузера Хром:

Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36

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

То есть из-за неправильного использования UA веб мастерами UA сейчас стали малопонятны человеку.

Еще из похожих историй- разработчики IE убрали из UA в новом IE11 название браузера которым обозначались предыдущие версии (было MSIE/9.0, теперь пишут Trident по названию движка, а не браузера). Опять же, так как вебмастера увидев в UA слово MSIE отдавали тому код рассчитанный на какой-нибудь IE5.5, в то время как уже IE8 начал поддерживать HTML4 и CSS2.1.

http://habrahabr.ru/sandbox/67192/

Вот полная история, я советую ознакомиться: http://geektimes.ru/post/84222/

Ты думаешь, на этом история заканчивается? Как бы не так. В последние года 3 стало модно по UA определять, мобильный браузер или десктопный. В UA ищут названия смартфонов, слово mobile, iOS, и интуиция подсказывает мне что мы придем к новому витку усложнения User-Agent.

Потому в общем, когда я слышу «User-Agent», я хватаюсь за воображаемый пистолет.

Определять кто перед тобой, лучше через feature testing, то есть проверяя наличие конкретных фич (поддерживает ли агент куки? а картинки? а яваскрипт?), а не устраивая гадание на гуще названий движков в UA.
#496 #577244
>>576933

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

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

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

Хотя конечно 20 аргументов в конструкторе это признак что дело плохо и надо что-то менять.

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

> Если допустить, что адаптеры для редиса являются только оберткой над клиентом, то выношу свойства $keyPrefix, $keyExpiration в класс VisitCounter.


Но теперь если быть последовательным, то нужно удалить все лишнее и из адаптера базы. Там мне необходимы такие свойства как $pk, $tblName и $colName.
Если ты их вынесешь в VC то ты делаешь лишние ограничения: данные могут сохраняться только в базу, таблица может быть только одна, у нее должен быть первичный ключ из 1 колонки. По моему это неудобно.

> Но теперь если быть последовательным, то нужно удалить все лишнее и из адаптера базы.


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

> и с NoSQL базами. Я с ними никогда не сталкивался, но думаю что там нет таблиц.


Ну редис представь, это NoSQL хранилище без вторичных индексов (то есть искать можно только по первичному ключу) в общем-то.

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


Можешь разобраться, если хочешь и есть время.

>Зачем на лету малевать хердок, если можно подключить шаблон из файла?


Так как это фатальная ошибка. Если посмотреть то видно что там аж 2 варианта сообщения - текстовое для запуска из консоли и HTML для веба. Как я понимаю, чтобы если клиент неправильно установил магазин, он увидел не стандартную заглушку, а конкретное напоминание что он забыл сделать.

> Пытаюсь отыскать класс \Magento\Framework\App\Bootstrap


> Удалось это сделать только через гугл.


Надо было начинать с composer.json - там описаны пути для автозагрузки. Чем и хорош композер, что теперь не надо разбирать самописные автолоадеры (а в больших проектах они сложные и запутанные), а достаточно глянуть в composer.json.

> Класс VisitCounter судя по всему тоже придется разбить на два отдельных, один для работы с базой, второй для работы с редисом.


Зачем?

> Мне еще нужно проверить, не является ли посетитель ботом.


Что ты имеешь в виду под ботом? Определись. HTTP-клиент у которого стоит в юзер-агенте GoogleBot? Клиент не загружающий картинки? HTTP-клиент, не выполняющий яваскрипт код?

> Нагуглил функцию http://php.net/manual/ru/function.get-browser.php , она вернет нужную информацию?


Эта функция лишь получает данные из заголовка User-Agent и представляет их в виде массива. Читать:

https://ru.wikipedia.org/wiki/User_Agent
http://www.useragentstring.com/pages/useragentstring.php
https://en.wikipedia.org/wiki/User_agent (тут лучше чем в русской версии)

Вообще с UA связана куча нехороших историй, когда программист определяет браузер по нему и отдает ему чуть другую версию страницы, а потом выходит новая версия браузера и все ломается. Это настолько масштабно, что почти все браузеры (IE, opera, chrome, firefox) содержат в UA строку 'Mozilla' - так как раньше было всего 2 браузера: Mozilla Firefox (поддерживал стандарты) и IE6 (не поддерживал) и по этой строке UA вебмастера определяли какой перед ними браузер и отдавали им разный код. Сейчас все браузеры поддерживают стандарты, но быдлокод с проверкой UA остался на сайтах и в учебниках, и все браузеры включают в UA строку Mozilla.

И не только.

Вот например UA браузера Хром:

Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36

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

То есть из-за неправильного использования UA веб мастерами UA сейчас стали малопонятны человеку.

Еще из похожих историй- разработчики IE убрали из UA в новом IE11 название браузера которым обозначались предыдущие версии (было MSIE/9.0, теперь пишут Trident по названию движка, а не браузера). Опять же, так как вебмастера увидев в UA слово MSIE отдавали тому код рассчитанный на какой-нибудь IE5.5, в то время как уже IE8 начал поддерживать HTML4 и CSS2.1.

http://habrahabr.ru/sandbox/67192/

Вот полная история, я советую ознакомиться: http://geektimes.ru/post/84222/

Ты думаешь, на этом история заканчивается? Как бы не так. В последние года 3 стало модно по UA определять, мобильный браузер или десктопный. В UA ищут названия смартфонов, слово mobile, iOS, и интуиция подсказывает мне что мы придем к новому витку усложнения User-Agent.

Потому в общем, когда я слышу «User-Agent», я хватаюсь за воображаемый пистолет.

Определять кто перед тобой, лучше через feature testing, то есть проверяя наличие конкретных фич (поддерживает ли агент куки? а картинки? а яваскрипт?), а не устраивая гадание на гуще названий движков в UA.
#497 #577254
>>576933

Еще из истории UA: Opera после выхода 10-й версии начала писать UA так:

# 12 - настоящая версия, presto - название движка оперы
Opera/9.80 Presto/12

Почему? Потому-что быдлокодеры использовали регулярку вроде

Opera/[1-6]

для определения старых версий Оперы, и новая Опера бы тоже под нее попала.

Кстати, по этой же причине новая Windows тоже пропустила версию 9 и перескочила с 8 на 10: http://geektimes.ru/post/238915/
#498 #577257
>>576933

> Я знаю как прописать в composer.json, чтобы он скачал пакет с гитхаба, но не знаю, как добавить классы пакета в автозагрузку.


правила автозагрузки для библиотеки определяются в ее собственном composer.json, а не там где ты ее подключаешь.
#499 #577269
>>576933

Что-то в коде косяки:

https://github.com/nsdvw/visit-counter/blob/master/src/VisitCounter.php#L38

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

> https://github.com/nsdvw/visit-counter/blob/master/src/VisitCounter.php#L11


> private $keyPrefix = '';


Так как это необязательная опция, для нее надо разумное значение по умолчанию.

> $this->client = $redisAdapter;


Одинаковые вещи надо называть одинаково.

Ну и в шапку класса VisitCounter хорошо бы добавить комментарий с кратким описанием алгоритма.
#500 #577312
>>569144
Сам удивился.
#501 #577322
>>576721
Что не так?
16 Кб, 573x157
#502 #577352
Почему кириллица, проходя через доктрину, сохраняется как кракозябры? В браузере, при этом, всё отображается корректно.
В дампе базы данных присутствуют строки:
SET NAMES utf8; //в самом начале
DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; //после каждого CREATE TABLE

Пикрилейтед.
#503 #577353
>>577352

В настройках соединения доктрины с БД скорее всего не указана кодировка соедиения utf-8. Либо код не в utf-8.

Покажи конфиг или настройки доктрины.
#504 #577354
>>577352

> SET NAMES utf8; //в самом начале


Эта команда лишь говорит о том что дамп закодирован а utf8. Она никак не влияет на работу доктрины.

> DEFAULT CHARSET=utf8


Это говорит что данные в таблице хранятся в utf-8, но опять же доктрина тут не при чем. Важно, какая кодировка соединения выставляется когда доктрина подключается к базе и в какой кодировке она шлет данные (то есть в какой кодировке написано твой код, в какой присылает данные форм браузер и что стоит в meta charset).
#505 #577355
>>577353
И правда. Забыл выставить кодировку в массиве $connection - думал, доктрина за меня поставит ютф8 по умолчанию. Спасибо.

>>577354
Ну так я привел эти данные для того, чтобы не было сомнений, что проблема на участке работы доктрины.
#506 #577367
>>576675

>&$array



& какбы говорит нам что переданный массив уже будет изменён. Сам массив, а не его копия.
А потом ты ему зачем-то присваеваешь этому массиву возвращаемое значение типа Int (Возвращает новое количество элементов в array. ).
#507 #577400
Какие вам вопросы на собеседованиях задают обычно? Послезавтра собеседоваться иду в конторку, которая угорает по базам данных, чего ждать? Кучу вопросов про ООП, mysql и логирование?
#508 #577426
>>577400
Какой город?
#509 #577432
>>577400
Обязательно потом напиши репорт - тебе аноны большое спасибо скажут.
#510 #577439
>>577426
Миллионник в европейской части рашки, не ДСы.
>>577432
Напишу, если не забуду.
#511 #577683
как долго нужно учит html чтоб знать его в идеале?
#512 #577693
>>577367
Но ошибка та же
#513 #577696
>>577683
Почти нихуя не надо. Это всего лишь разметка, там не много элементов. А вот с CSS поебешься.
#514 #577701
Посоны где можно скачать свежие номера 2013-2015 года журнала php|architect?
Сотни нефти за ссылочку
#515 #577703
ОП или знающие аноны, помогите пожалуйста. Весь день мучаюсь с этой хуйней, никак неполучается решить задачу, готов уже клаву разъебать. Есть скрипт который по нажатии кнопки динамиески добавляет input type text на страницу с помощью jquery. Нужно это для составления заявки на покупку двери. В одной заявке может быть покупка нескольких дверей, поэтому может быть создано 1-10 полей через этот скрипт. Все работает, все создается.
Теперь мне нужно оживить каждое из этих полей, то есть добавить к ним ajax обрабочик. Продавец вводит информацию в поле, ввел первые пару символов, а дальше уже выбирает из появившегося блока что это за дверь. Блок появляется через ajax запрос. И тут у меня появилась куча проблем.
Если делать отдельное поле на странице, то есть не создавать его через jquery, а сразу прописать в html, то форма ajax поиск работает, все хорошо. Однако если создавать такое же поле оно не хочет ну накак работать через ajax. То есть я ввожу туда данные, а скрипт не обрабатывает эту форму. Если проинспектить элемент через "Просмотра кода элемента", то инспектр вообще не ставит там пометку что эта форма обрабатывается каким-либо скриптом. Если же это же поле ввода написать выше вручную, как писал выше, а не создавать через jquery по нажатию на ссылку, то инспектр показывает что к обработчику она привязана. Вот про какие поментки я говорю (надпись ev):
https://gyazo.com/39569e0b92bf243030c4b2e72ef31e28
Помогите пожалуйста, пасаны. Весь день потратил на эту хрень, ничего не получается, а без этого не могу двигаться дальше. Вот код который у меня есть сейчас:
http://ideone.com/lrWZvr
#516 #577721
>>577244
Можно подумать он потом устроится в контору фреймворки писать.
Люди годами делают один сайтик или 2D игру. Не понимаю, как можно работать программистом в одиночку. Как минимум должна быть большая команда и каждый разрабатывает свою часть сайта.
#517 #577769
Пиздец, внезапно перестал работать метод для вызова куки $app->request->get->cookie();, надо было просто $app->getCookie();
два часа искал ошибку.
#518 #577821
>>577244
Ну я и не говорил, что магенто так уж плох, по сравнению с другими cms он очень даже хорош. Но вот если сравнить с проектами на фреймворках, разница ощущается.

>Неизвестно еще, что бы ты напроектировал


"Сперва добейся", я понял. Только у тебя привилегия пиздеть про говнокод.

>Что ты имеешь в виду под ботом?


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

В общем, переписал еще раз библиотеку для счетчика (версия 3).
https://github.com/nsdvw/visit-counter
Сделал класс редис-адаптера более высокоуровневым, как ты советовал. Тут минус в том, что нужно писать подробную инструкцию для человека, который вздумает написать адаптер для своего клиента. Раньше мне достаточно было заставить его реализовать несколько низкоуровневых методов типа lrange или setnx, а их вызовы я зашил в классе VisitCounter, то есть четко зафиксировал алгоритм работы библиотеки.

>>577257
Ну подробнее.
Как выглядят эти правила автозагрузки для библиотеки?
Так https://github.com/nsdvw/visit-counter/blob/master/composer.json не работает, class not found.

С тестированием давай возиться позже, я хочу привести в порядок сайт с объявлениями, как закончу можно будет для него написать тесты. Ну и твое задание про сайт с тестами тоже собираюсь сделать, мне нравится идея. На нем буду учить yii2. Такой план до конца этого года.
p-5ch #519 #577910
У меня вопрос, не знаю как сформулировать, в коде все будет:
http://ideone.com/s9eMne
Можно ли вызвать метод класса foo?
#520 #577914
>>577703
Разобрался сам, больше все ищется и подставляется в разных формах как нужно. Но есть одно но. Работает только в созданных формах вручную, то есть в формал прописанных в самом файлике кода. Если же формы создаются через jquery по нажатию кнопки, то обработчик не срабатывает для этих форм. Как решить вот это вообще не понимаю. Может тут кто-нибудь подскажет?
https://ideone.com/0BFzHr
624 Кб, 1260x1024
#521 #577946
Сап, граждане этого пхп-треда.
И сразу глупейший вопрос, на снисходительный и понятный ответ которого я надеюсь : ... сможет ли найти 18-летний студент не из России, учащийся на юридическом факультете, но с превосходным знанием 1-ого основного и 6 доп. языков, удаленную работу пхп-погромистом с удобным графиком?
#522 #578002
>>577914
Таки доделал, знакомый подсказал в чем дело и как исправить. Просто функцию обработки кейАпа нужно вешать при создании каждого поля.
#523 #578011
>>577946
7 языков программирования? Так может стэк технологий и ссылку на github в студию, а то у нас тут часто бывает разногласие относительно "превосходного знания", "от корки до корки" и т.п.
#524 #578016
>>577946
На фрилансе куча заказов, все зависит от твоего упорства и желания. Разумеется только выучив пхп тебе никто не предложет много проектов и денег за это, нужно понимать что изначально придется работать за гроши чтобы получить опыт + портфолио. Далее уже можешь просить больше, когда поймешь что уровень твоих работ и знаний превышает нынешнюю планку оплаты.
Я например благодаря этому треду основную работу нашел, где сейчас и учусь чему-то новому постоянно, и портфолио набиваю на будущее. Не знал по сути ничего, но учился на программиста при этом, и понял что пора бы задуматься о будущем. За два года я выучил html+css, научился верстать, пиздить идеи и примеры, внедряя их у себя. Далее немного освоил jquery, попутно со всем этим изучал php. На данный момент имею какие-никакие знания из каждой этой области, их вполне хватает чтобы читать чужой код, понимать как работает и при надобности применять у себя, ну и собственные разработки естественно. Я рад что так сложилось, прочитав этот тред впервые и зайдя на сайт ОПа мне понравились уроки, я занимался этим с удовольствием, ну и не прогадал вроде. Однако стоит заметить что от этих уроков я ушел довольно таки быстро и начал смотреть курсы от Специалиста. Хорошая вещь, рекомендую. По крайней мере как базис точно, объясняется все досконально и просто.
98 Кб, 1409x571
#525 #578117
Аноны, я ньюфаг, помогите разобраться с позиционированием. Хочу запилить его в первых трех голубых дивах внутри красного и чтобы средний занимал все свободное пространство, но 3 вылазит впизду.
Заранее всем спасибо.
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Домашнее задание</title>
</head>
<style type="text/css">
.green1 {
width: 100%;
height: 1000px;
border:solid 2px green;
}
.red1 {
width: auto;
height: 150px;
border:solid 2px red;
margin:20px;
position: relative;
.red1 DIV{position:absolute;}
}
.red2 {
width: auto;
height: 100px;
border:solid 2px red;
margin:20px;
}
.red3 {
width: auto;
height: 450px;
border:solid 2px red;
margin:20px;
}
.red4 {
width: auto;
height: 180px;
border:solid 2px red;
margin:20px;
}
.blue1 {
width: 250px;
height: 120px;
border:solid 2px blue;
float:left;
}
.blue2 {
left:250px;
right:250px;
height: 120px;
border:solid 2px blue;
}
.blue3 {
width: 250px;
right:0;
height: 120px;
border:solid 2px blue;
}

.blue4 {
width: 20%;
height: 70px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue5 {
width: 19%;
height: 70px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue6 {
width: 19%;
height: 70px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue7 {
width: 34%;
height: 70px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue8 {
width: 20%;
height: 420px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue9 {
width: 76%;
height: 420px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue10 {
width: 20%;
height: 155px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue11 {
width: 50%;
height: 155px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue12 {
width: 24%;
height: 155px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.yellow1 {
width: 50%;
height: 40px;
border:solid 2px yellow;
margin:10px;

}
.yellow2 {
width: 40%;
height: 40px;
border:solid 2px yellow;
margin:10px;

}
.yellow3 {
width: auto;
height: 190px;
border:solid 2px yellow;
margin:10px 10px 10px 10px;
float:bottom;
}
.yellow4 {
width: auto;
height: 190px;
border:solid 2px yellow;
margin:10px 10px 10px 10px;
float:bottom;
}
.yellow5 {
width: auto;
height: 60px;
border:solid 2px yellow;
margin:10px 10px 10px 10px;
float:bottom;
}
.yellow6 {
width: auto;
height: 60px;
border:solid 2px yellow;
margin:10px 10px 10px 10px;
float:bottom;
}
</style>
</head>
<body>
<div class="green1">
<div class="red1" >
<div class="blue1"></div>
<div class="blue2"></div>
<div class="blue3">
<div class="yellow1"></div>
<div class="yellow2"></div>
</div>
</div>
<div class="red2">
<div class="blue4"></div>
<div class="blue5"></div>
<div class="blue6"></div>
<div class="blue7"></div>
</div>
<div class="red3">
<div class="blue8"></div>
<div class="blue9">
<div class="yellow3"></div>
<div class="yellow4"></div>
</div>
</div>
<div class="red4">\t
<div class="blue10">
<div class="yellow5"></div>
<div class="yellow6"></div>
</div>
<div class="blue11"></div>
<div class="blue12"></div>
</div>
</div>
</body>
</html>
98 Кб, 1409x571
#525 #578117
Аноны, я ньюфаг, помогите разобраться с позиционированием. Хочу запилить его в первых трех голубых дивах внутри красного и чтобы средний занимал все свободное пространство, но 3 вылазит впизду.
Заранее всем спасибо.
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Домашнее задание</title>
</head>
<style type="text/css">
.green1 {
width: 100%;
height: 1000px;
border:solid 2px green;
}
.red1 {
width: auto;
height: 150px;
border:solid 2px red;
margin:20px;
position: relative;
.red1 DIV{position:absolute;}
}
.red2 {
width: auto;
height: 100px;
border:solid 2px red;
margin:20px;
}
.red3 {
width: auto;
height: 450px;
border:solid 2px red;
margin:20px;
}
.red4 {
width: auto;
height: 180px;
border:solid 2px red;
margin:20px;
}
.blue1 {
width: 250px;
height: 120px;
border:solid 2px blue;
float:left;
}
.blue2 {
left:250px;
right:250px;
height: 120px;
border:solid 2px blue;
}
.blue3 {
width: 250px;
right:0;
height: 120px;
border:solid 2px blue;
}

.blue4 {
width: 20%;
height: 70px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue5 {
width: 19%;
height: 70px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue6 {
width: 19%;
height: 70px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue7 {
width: 34%;
height: 70px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue8 {
width: 20%;
height: 420px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue9 {
width: 76%;
height: 420px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue10 {
width: 20%;
height: 155px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue11 {
width: 50%;
height: 155px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.blue12 {
width: 24%;
height: 155px;
border:solid 2px blue;
margin:10px 10px 10px 10px;
float:left;
}
.yellow1 {
width: 50%;
height: 40px;
border:solid 2px yellow;
margin:10px;

}
.yellow2 {
width: 40%;
height: 40px;
border:solid 2px yellow;
margin:10px;

}
.yellow3 {
width: auto;
height: 190px;
border:solid 2px yellow;
margin:10px 10px 10px 10px;
float:bottom;
}
.yellow4 {
width: auto;
height: 190px;
border:solid 2px yellow;
margin:10px 10px 10px 10px;
float:bottom;
}
.yellow5 {
width: auto;
height: 60px;
border:solid 2px yellow;
margin:10px 10px 10px 10px;
float:bottom;
}
.yellow6 {
width: auto;
height: 60px;
border:solid 2px yellow;
margin:10px 10px 10px 10px;
float:bottom;
}
</style>
</head>
<body>
<div class="green1">
<div class="red1" >
<div class="blue1"></div>
<div class="blue2"></div>
<div class="blue3">
<div class="yellow1"></div>
<div class="yellow2"></div>
</div>
</div>
<div class="red2">
<div class="blue4"></div>
<div class="blue5"></div>
<div class="blue6"></div>
<div class="blue7"></div>
</div>
<div class="red3">
<div class="blue8"></div>
<div class="blue9">
<div class="yellow3"></div>
<div class="yellow4"></div>
</div>
</div>
<div class="red4">\t
<div class="blue10">
<div class="yellow5"></div>
<div class="yellow6"></div>
</div>
<div class="blue11"></div>
<div class="blue12"></div>
</div>
</div>
</body>
</html>
#526 #578122
>>569049 (OP)
Пили новый трэд, жопка.
11 Кб, 363x144
#528 #578134
http://php.feedme.ru/quiz.php

Я - годный программист!
#529 #578137
>>578134
P.S. Это тест от badoo.
#530 #578153
>>577693
попробуй вместо $vars = array_unshift($vars, $types);
поставить array_unshift($vars, $types);
#531 #578391
>>578125
Постоянно проигрываю с этого скорострела.
194 Кб, 1392x1059
opcache #532 #578472
Что такое wasted memory?

> opcache.max_accelerated_files integer


> The maximum number of keys (and therefore scripts) in the OPcache hash table.


Что подразумевают под ключами (keys)?
Что такое hits? Кол-во запросов к кешированным скриптам(или "ключам")?
#533 #578505
>>578472

В исходниках написано https://github.com/zendtech/ZendOptimizerPlus/blob/8c3e56f83bf4fda5f6780618638c77ee43867a70/zend_shared_alloc.h#L105

> Amount of shared memory allocated by garbage



Тут http://www.koscheev.ru/nazlobu/?n=194 написано

> OPcache не имеет встроенного менеджера кеша. Когда скрипт изменяется, его старая копия остается в памяти (wasted memory). Кеш очищается автоматически и полностью, если недостаточно доступной памяти для кеширования новых файлов и при этом количество "wasted memory" больше, чем opcache.max_wasted_percentage % от opcache.memory_consumption. По умолчанию opcache.max_wasted_percentage=5.



> Что подразумевают под ключами (keys)?


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

$cache['/tmp/file.php'] = ...;

То есть ключ значит элемент хранящийся в кеше.

> Что такое hits? Кол-во запросов к кешированным скриптам(или "ключам")?


Я думаю, число успешных запросов (для которых в кеше нашелся ответ) в противоположность misses

Отношение hits/misses показывает эффективен или бесполезен ли кеш (как именно догадайся сам).

При использовании кеша помни про 2 подвоза:

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

2) оп-кешер может проверять дату изменения файла на диске каждый раз, не проверять или проверять не чаще раза в N минут ради большей эффективности. В этом случае твои изменения могут не примениться сразу, а только через какое-то время. То есть при выполнении require_once будет подключена старая версия файла из кеша. Для борьбы с этим нужно явно вызывать opcache_reset() при выгрузке нового кода на сервер. А на локалхосте лучше включить режим постоянной перепроверки и все будет работать само.
#533 #578505
>>578472

В исходниках написано https://github.com/zendtech/ZendOptimizerPlus/blob/8c3e56f83bf4fda5f6780618638c77ee43867a70/zend_shared_alloc.h#L105

> Amount of shared memory allocated by garbage



Тут http://www.koscheev.ru/nazlobu/?n=194 написано

> OPcache не имеет встроенного менеджера кеша. Когда скрипт изменяется, его старая копия остается в памяти (wasted memory). Кеш очищается автоматически и полностью, если недостаточно доступной памяти для кеширования новых файлов и при этом количество "wasted memory" больше, чем opcache.max_wasted_percentage % от opcache.memory_consumption. По умолчанию opcache.max_wasted_percentage=5.



> Что подразумевают под ключами (keys)?


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

$cache['/tmp/file.php'] = ...;

То есть ключ значит элемент хранящийся в кеше.

> Что такое hits? Кол-во запросов к кешированным скриптам(или "ключам")?


Я думаю, число успешных запросов (для которых в кеше нашелся ответ) в противоположность misses

Отношение hits/misses показывает эффективен или бесполезен ли кеш (как именно догадайся сам).

При использовании кеша помни про 2 подвоза:

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

2) оп-кешер может проверять дату изменения файла на диске каждый раз, не проверять или проверять не чаще раза в N минут ради большей эффективности. В этом случае твои изменения могут не примениться сразу, а только через какое-то время. То есть при выполнении require_once будет подключена старая версия файла из кеша. Для борьбы с этим нужно явно вызывать opcache_reset() при выгрузке нового кода на сервер. А на локалхосте лучше включить режим постоянной перепроверки и все будет работать само.
https://github.com/p-5ch/vector #534 #578831
>>575750

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

Для начала, стандартная паста на тему как надо решать ООП-задачки:

-----------

Когда ты решаешь задачу на ООП, ты должен ответить на вопросы:

— какие есть сущности, для которых мы сделаем классы? (Сотрудник и Департамент)
— какие у них есть свойства (у Сотрудника есть ранг, базовая ставка, профессия, является ли боссом). Потребление кофе или зарплата не являются свойствами так как они вычисляются из других свойств и хранить их не надо.
— что мы хотим от них получить (какие у них должны быть методы). Например мы хотим узнать сколько сотрудник заработал или сколько он пьет кофе. От департамента мы наверно хотим получить сколько всего выпито кофе и заплачено денег.
— как сущности связаны? Очевидно, Сотрудник работает в каком-то Департаменте.

Также, сразу скажу еще один совет: гораздо удобнее сделать не один класс Сотрудник, а 4 класса: Инженер, Менеджер, и т.д. Тогда мы можем легко менять например правила расчет зарплаты или кофе для каждой профессии. Естественно, копипастить одинаковый код в 4 класса не надо — создай базовый абстрактный класс Сотрудник и унаследуй от него 4 класса-профессии.

Наследование позволяет создавать класс не с нуля. а расширяя сущетсвующий класс: http://php.net/manual/ru/language.oop5.inheritance.php

«Абстрактный» — это класс, объект которого нельзя создать. Он предназначен для наследования от него других классов: http://php.net/manual/ru/language.oop5.abstract.php

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

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

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

Это тоже неправильно, на мой взгляд:

> $salary = array("ме" => "500",


> "ин" => "200",


Если ты хочешь обозначать профессии, надо завести для них константы: http://php.net/manual/ru/language.oop5.constants.php вроде Employee::JOB_ENGINEER. Или, если ты решишь сделать по классу для каждой профессии, то можно использовать в качестве обозначения их имена: 'Manager' (а с версии 5.5 можно писать Manager::class - мануал: http://php.net/manual/ru/language.oop5.basic.php#language.oop5.basic.class.class )

> Order of properties and methods in class (best practices)


Порядок обычно такой: константы, поля, конструктор, публичные методы, непубличные методы.

> Specified in PSR?


А PSR доступен даже на русском, почитай:

http://www.php-fig.org/psr/psr-1/ru/
http://www.php-fig.org/psr/psr-2/ru/

Порядок там вроде не определен

> phpDOC. What is this? How to use it?


phpDoc - это стандарт комментариев для описания функций, классов. Комментарии в формате phpDoc понимают IDE и извлекают из них информацию (например показывают описание функции при наведении мыши на ее имя), а также из phpDoc комментариев можно автоматически сгенерировать документацию. Вот пример сгенерированной документации: http://api.symfony.com/2.6/Symfony/Component/HttpFoundation/Request.html а вот исходный файл с phpDoc-комментариями: https://github.com/symfony/http-foundation/blob/master/Request.php

phpDoc комментарии отличаются от обычных наличием 2 звездочек в начале.

Описание формата:

кратко https://ru.wikipedia.org/wiki/PhpDocumentor
статья в тему http://habrahabr.ru/post/162535/
и как всегда, подробно на английском: http://www.phpdoc.org/docs/latest/references/phpdoc/index.html

В 99% случаев достаточно знать только следующие теги: @author, @var, @param, @return, @see, @since, @deprecated и изучить как описываются сложные типы, например int[] или SomeClass|null.

Чтобы проверить что ты понял phpDoc, попробуй поставить комментарии в свои классы.

Сразу же замечу что @return mixed ( https://github.com/p-5ch/vector/blob/master/app/Model/Department.php#L19 ) это бессмысленный комментарий так как не несет никакой информации. Очевидно, название депатамента это строка и должно стоять @return string

Этот комментарий «Department constructor.» тоже не нужен так как и без него очевидно что перед нами конструктор.

> @return array of Employee


Не по стандарту написан тип

> @param Employee $employee


Комментарий дублирует тайп-хинт, не дает новой информации и потому не несет особой ценности.

Также, чтобы ты лучше разобрался в ООП, держи дополнительное задание к этой задаче (вообще, я его всем даю):

---------

Задание: напиши программу для учета расходов и результатов работы всего дружного коддектива компании «Вектор».

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

1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.

2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)

3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.

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

----------

И еще:

> https://github.com/p-5ch/vector/blob/master/index.php#L17


> echo "Can't load $class from: $classFile \n. Script halted";


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

К тому же если ты будешь подключать библиотеки, у них может быть свой автозагрузчик и этим кодом ты не даешь ему шанса запуститься.
https://github.com/p-5ch/vector #534 #578831
>>575750

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

Для начала, стандартная паста на тему как надо решать ООП-задачки:

-----------

Когда ты решаешь задачу на ООП, ты должен ответить на вопросы:

— какие есть сущности, для которых мы сделаем классы? (Сотрудник и Департамент)
— какие у них есть свойства (у Сотрудника есть ранг, базовая ставка, профессия, является ли боссом). Потребление кофе или зарплата не являются свойствами так как они вычисляются из других свойств и хранить их не надо.
— что мы хотим от них получить (какие у них должны быть методы). Например мы хотим узнать сколько сотрудник заработал или сколько он пьет кофе. От департамента мы наверно хотим получить сколько всего выпито кофе и заплачено денег.
— как сущности связаны? Очевидно, Сотрудник работает в каком-то Департаменте.

Также, сразу скажу еще один совет: гораздо удобнее сделать не один класс Сотрудник, а 4 класса: Инженер, Менеджер, и т.д. Тогда мы можем легко менять например правила расчет зарплаты или кофе для каждой профессии. Естественно, копипастить одинаковый код в 4 класса не надо — создай базовый абстрактный класс Сотрудник и унаследуй от него 4 класса-профессии.

Наследование позволяет создавать класс не с нуля. а расширяя сущетсвующий класс: http://php.net/manual/ru/language.oop5.inheritance.php

«Абстрактный» — это класс, объект которого нельзя создать. Он предназначен для наследования от него других классов: http://php.net/manual/ru/language.oop5.abstract.php

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

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

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

Это тоже неправильно, на мой взгляд:

> $salary = array("ме" => "500",


> "ин" => "200",


Если ты хочешь обозначать профессии, надо завести для них константы: http://php.net/manual/ru/language.oop5.constants.php вроде Employee::JOB_ENGINEER. Или, если ты решишь сделать по классу для каждой профессии, то можно использовать в качестве обозначения их имена: 'Manager' (а с версии 5.5 можно писать Manager::class - мануал: http://php.net/manual/ru/language.oop5.basic.php#language.oop5.basic.class.class )

> Order of properties and methods in class (best practices)


Порядок обычно такой: константы, поля, конструктор, публичные методы, непубличные методы.

> Specified in PSR?


А PSR доступен даже на русском, почитай:

http://www.php-fig.org/psr/psr-1/ru/
http://www.php-fig.org/psr/psr-2/ru/

Порядок там вроде не определен

> phpDOC. What is this? How to use it?


phpDoc - это стандарт комментариев для описания функций, классов. Комментарии в формате phpDoc понимают IDE и извлекают из них информацию (например показывают описание функции при наведении мыши на ее имя), а также из phpDoc комментариев можно автоматически сгенерировать документацию. Вот пример сгенерированной документации: http://api.symfony.com/2.6/Symfony/Component/HttpFoundation/Request.html а вот исходный файл с phpDoc-комментариями: https://github.com/symfony/http-foundation/blob/master/Request.php

phpDoc комментарии отличаются от обычных наличием 2 звездочек в начале.

Описание формата:

кратко https://ru.wikipedia.org/wiki/PhpDocumentor
статья в тему http://habrahabr.ru/post/162535/
и как всегда, подробно на английском: http://www.phpdoc.org/docs/latest/references/phpdoc/index.html

В 99% случаев достаточно знать только следующие теги: @author, @var, @param, @return, @see, @since, @deprecated и изучить как описываются сложные типы, например int[] или SomeClass|null.

Чтобы проверить что ты понял phpDoc, попробуй поставить комментарии в свои классы.

Сразу же замечу что @return mixed ( https://github.com/p-5ch/vector/blob/master/app/Model/Department.php#L19 ) это бессмысленный комментарий так как не несет никакой информации. Очевидно, название депатамента это строка и должно стоять @return string

Этот комментарий «Department constructor.» тоже не нужен так как и без него очевидно что перед нами конструктор.

> @return array of Employee


Не по стандарту написан тип

> @param Employee $employee


Комментарий дублирует тайп-хинт, не дает новой информации и потому не несет особой ценности.

Также, чтобы ты лучше разобрался в ООП, держи дополнительное задание к этой задаче (вообще, я его всем даю):

---------

Задание: напиши программу для учета расходов и результатов работы всего дружного коддектива компании «Вектор».

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

1. Сократить в каждом департаменте 40% (округляя в большую сторону) инженеров, преимущественно самого низкого ранга. Если инженер является боссом, вместо него надо уволить другого инженера, не босса.

2. Увеличить в целях стимуляции умственной деятельности базовую ставку аналитика с 800 до 1100 тугриков, а количество выпиваемого им кофе с 50 до 75 литров. В тех департаментах, где руководитель не является аналитиком, заменить его на аналитика самого высшего ранга из этого департамента (а бывшего руководителя вернуть к обычной работе)

3. В каждом департаменте повысить 50% (округляя в большую сторону) менеджеров 1-го и 2-го ранга на один ранг с целью расширить их полномочия.

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

----------

И еще:

> https://github.com/p-5ch/vector/blob/master/index.php#L17


> echo "Can't load $class from: $classFile \n. Script halted";


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

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

ab -c 5 -n 50

Document Path: /
Document Length: 68791 bytes

Concurrency Level: 5
Time taken for tests: 14.308 seconds
Complete requests: 50
Failed requests: 0
Total transferred: 3458850 bytes
HTML transferred: 3439550 bytes
Requests per second: 3.49 [#/sec] (mean)
Time per request: 1430.804 [ms] (mean)
Time per request: 286.161 [ms] (mean, across all concurrent requests)
Transfer rate: 236.08 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 1.6 0 6
Processing: 803 1400 192.5 1417 1685
Waiting: 788 1360 184.5 1365 1617
Total: 803 1400 192.7 1423 1685

Percentage of the requests served within a certain time (ms)
50% 1423
66% 1535
75% 1554
80% 1575
90% 1618
95% 1649
98% 1685
99% 1685
100% 1685 (longest request)

Единственный запрос, который производится на странице, оптимизирован (вроде бы) и закеширован.
Не знаю, о чем говорят тесты, но судя по логам yii, страница генерировалась 1.4 секунды, а по моему глазомеру даже дольше. Многовато что-то.
Что еще можно оптимизировать или закешировать?
Что я сделал: поставил индекс на колонках таблицы, по которым идет условие выборки; включил оп-кешер, дал ему памяти (128 должно хватить), увеличил mysql cache и innodb pool по 256 мб.
В самом скрипте кое-что переделал, например убрал кое-где актив-рекорды, заменил дао.

Ну в общем, что делать дальше с цифрами бенчмарка и что еще можно придумать для ускорения полета? Профайлер смотрел, но там вроде особо ничего уже не выдавишь. Приложу на всякий случай. http://rghost.ru/695mdbz8Q
apache benchmark #535 #578842
Как интерпретировать результаты тестов сервера?
Получил какие-то цифры, но пока не знаю, хороши ли они, или нужно стремиться их улучшать (как?).

ab -c 5 -n 50

Document Path: /
Document Length: 68791 bytes

Concurrency Level: 5
Time taken for tests: 14.308 seconds
Complete requests: 50
Failed requests: 0
Total transferred: 3458850 bytes
HTML transferred: 3439550 bytes
Requests per second: 3.49 [#/sec] (mean)
Time per request: 1430.804 [ms] (mean)
Time per request: 286.161 [ms] (mean, across all concurrent requests)
Transfer rate: 236.08 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 1.6 0 6
Processing: 803 1400 192.5 1417 1685
Waiting: 788 1360 184.5 1365 1617
Total: 803 1400 192.7 1423 1685

Percentage of the requests served within a certain time (ms)
50% 1423
66% 1535
75% 1554
80% 1575
90% 1618
95% 1649
98% 1685
99% 1685
100% 1685 (longest request)

Единственный запрос, который производится на странице, оптимизирован (вроде бы) и закеширован.
Не знаю, о чем говорят тесты, но судя по логам yii, страница генерировалась 1.4 секунды, а по моему глазомеру даже дольше. Многовато что-то.
Что еще можно оптимизировать или закешировать?
Что я сделал: поставил индекс на колонках таблицы, по которым идет условие выборки; включил оп-кешер, дал ему памяти (128 должно хватить), увеличил mysql cache и innodb pool по 256 мб.
В самом скрипте кое-что переделал, например убрал кое-где актив-рекорды, заменил дао.

Ну в общем, что делать дальше с цифрами бенчмарка и что еще можно придумать для ускорения полета? Профайлер смотрел, но там вроде особо ничего уже не выдавишь. Приложу на всякий случай. http://rghost.ru/695mdbz8Q
#536 #578903
Аноны, насчет переката: я в общем не против того треда, он вроде создан довольно аккуратно, хотя конечно без картинки с кошачьим кафе немного грустно.

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

>>576577

Вообще, это не лучшая идея.

Во-первых, интернет-магазин это в общем сложная штука и писать ее долго. Гораздо выгоднее взять и допилить один из готовых движков.

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

>>576584

Может быть у вас что-то плохо настроено и кеши какие-нибудь не подключены. А может конечно и медленная, не знаю.
#537 #578904
>>576616

> preg_split("/([^!\?\.?]+[!\?\.?]+)/"


Почему такое сложно выражение? Ты хочешь получить предложение со знаком препинания? Тогда лучше использовать утверждения - они не захватывают символы при совпадении и они не теряются: http://php.net/manual/ru/regexp.reference.assertions.php

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

> [!\?\.?]


Непонятно зачем тут 2 раза знак вопроса. В квадратных скобках большинство символов не имеют специального значения (кроме 5 символов: ^ - [ ] \ ).

> function correctSpacesAroundChar($text, $char) {


Эту функцию, по моему, можно легко заменить 1 регулярным выражением и preg_replace. Будет и короче и понятнее.

>>576621

> preg_replace('/,/', '', $text);


Тут не нужна вся мощь регулярок и хватит str_replace

> implode(' ', explode(' ', $sentence));


Непонятен смысл этой операции

> $words[0] = makeFirstletterLowercase($words[0]);


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

> $words[count($words)-1] = makeFirstletterUppercase($words[count($words)-1]);


Вот это не очень красиво смотрится. Лучше взять последний элемент через array_pop и потом положить обратно через $x[] = ...

>>576714

> А это нормально запихивать все в классы и объекты классов в классы и повторяющийся код в классы, пока в контроллере не останется пара строчек?


Зависит от ситуации. Так трудно сказать.

Ну и если ты передаешь $app в класс, то с вероятностью 99% ты делаешь что-то не так. $app это большой сложный объект и классу весь он целиком точно не нужен.
#537 #578904
>>576616

> preg_split("/([^!\?\.?]+[!\?\.?]+)/"


Почему такое сложно выражение? Ты хочешь получить предложение со знаком препинания? Тогда лучше использовать утверждения - они не захватывают символы при совпадении и они не теряются: http://php.net/manual/ru/regexp.reference.assertions.php

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

> [!\?\.?]


Непонятно зачем тут 2 раза знак вопроса. В квадратных скобках большинство символов не имеют специального значения (кроме 5 символов: ^ - [ ] \ ).

> function correctSpacesAroundChar($text, $char) {


Эту функцию, по моему, можно легко заменить 1 регулярным выражением и preg_replace. Будет и короче и понятнее.

>>576621

> preg_replace('/,/', '', $text);


Тут не нужна вся мощь регулярок и хватит str_replace

> implode(' ', explode(' ', $sentence));


Непонятен смысл этой операции

> $words[0] = makeFirstletterLowercase($words[0]);


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

> $words[count($words)-1] = makeFirstletterUppercase($words[count($words)-1]);


Вот это не очень красиво смотрится. Лучше взять последний элемент через array_pop и потом положить обратно через $x[] = ...

>>576714

> А это нормально запихивать все в классы и объекты классов в классы и повторяющийся код в классы, пока в контроллере не останется пара строчек?


Зависит от ситуации. Так трудно сказать.

Ну и если ты передаешь $app в класс, то с вероятностью 99% ты делаешь что-то не так. $app это большой сложный объект и классу весь он целиком точно не нужен.
https://github.com/never3ver/catsandmice #538 #578906
>>576827

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


По моему это типичная ошибка off-by-1. Если в мире ширина = 5 клеток и отсчет координат идет с нуля, то в нем X может принимать значения 0, 1, 2, 3, 4, но не 5.

> Я могу браться за студентов?


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

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

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

> https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L101


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

Тут https://github.com/never3ver/catsandmice/blob/master/classes/Mouse.php#L80 не учитывается квадрат зрения мышки.

В остальном, код вполне нормальный.
#539 #578907
>>576866

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

>>576962

Если ты знаешь как сказать A и как сказать Б, что тебе мешает сказать обе буквы по очереди? Если нет, то возможно стоит подучить язык PHP.

>>577209

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

>>577400

Паста:

----------

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

PHP: перечитай мануал, любят спрашивать тонкости языки типа преобразования одного типа в другой или правил сравнения типов (сработает ли if ("foo" == 0) { } или if ("1 person" == true) ? ). По ООП любят вопросы из серии «что выведет эта дебильная программа где мы переопределяем в наследнике приватный метод публичным с тем же именем», опять же спасает чтение мануала.

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

Если требуют знания фреймворков, могут спросить как реализовать штуку X (например древовидные категории, хотя это продвинутый вопрос) в фрейморке.

MySQL и SQL вообще: любят вопросы по теории баз данных и SQL: транзакции, внешние ключи, нормализация, виды джойнов, индексы (это у более продвинутых). Могут попросить сделать хитрый SQL запрос типа найти в таблице записи которые встречаются больше N раз или найти записи которые есть в одной таблице и нет в другой.

JS: тонкости вроде преобразования типов, чему равно [] + {} + "hello", вопросы по прототипам, вопросы по замыканиям, вопросы по передаче значений по ссылке (объекты всегда передаются по ссылке, примитивы копируются). Некоторые подвохи освещены в моих задачах по JS, некоторые в learn.javascript.ru

HTML/CSS: тут подвохи вряд ли будут, разве что могут спросить как реализовать ту или иную вещь (например вертикальное выравнивание или прибитый к низу футер) и обычно там много вариантов.

Наконец у нас есть набор задач с собеседований самого разного уровня: https://github.com/codedokode/pasta/blob/master/interview-tasks.md

----------

>>577683

В Оп посте есть задания на HTML/CSS которые хорошо помогают изучить их на базовом уровне, включая позиционирование и полноценную верстку макета. Если ты после этого захочешь знать их еще лучше, я могу придумать специальные задания повышенной сложности.
#539 #578907
>>576866

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

>>576962

Если ты знаешь как сказать A и как сказать Б, что тебе мешает сказать обе буквы по очереди? Если нет, то возможно стоит подучить язык PHP.

>>577209

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

>>577400

Паста:

----------

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

PHP: перечитай мануал, любят спрашивать тонкости языки типа преобразования одного типа в другой или правил сравнения типов (сработает ли if ("foo" == 0) { } или if ("1 person" == true) ? ). По ООП любят вопросы из серии «что выведет эта дебильная программа где мы переопределяем в наследнике приватный метод публичным с тем же именем», опять же спасает чтение мануала.

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

Если требуют знания фреймворков, могут спросить как реализовать штуку X (например древовидные категории, хотя это продвинутый вопрос) в фрейморке.

MySQL и SQL вообще: любят вопросы по теории баз данных и SQL: транзакции, внешние ключи, нормализация, виды джойнов, индексы (это у более продвинутых). Могут попросить сделать хитрый SQL запрос типа найти в таблице записи которые встречаются больше N раз или найти записи которые есть в одной таблице и нет в другой.

JS: тонкости вроде преобразования типов, чему равно [] + {} + "hello", вопросы по прототипам, вопросы по замыканиям, вопросы по передаче значений по ссылке (объекты всегда передаются по ссылке, примитивы копируются). Некоторые подвохи освещены в моих задачах по JS, некоторые в learn.javascript.ru

HTML/CSS: тут подвохи вряд ли будут, разве что могут спросить как реализовать ту или иную вещь (например вертикальное выравнивание или прибитый к низу футер) и обычно там много вариантов.

Наконец у нас есть набор задач с собеседований самого разного уровня: https://github.com/codedokode/pasta/blob/master/interview-tasks.md

----------

>>577683

В Оп посте есть задания на HTML/CSS которые хорошо помогают изучить их на базовом уровне, включая позиционирование и полноценную верстку макета. Если ты после этого захочешь знать их еще лучше, я могу придумать специальные задания повышенной сложности.
#540 #578909
>>577703

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


Не нужно писать велосипед, есть готовые решения: jQuery UI Autocomplete, Chosen, Select2

> Если делать отдельное поле на странице, то есть не создавать его через jquery, а сразу прописать в html, то форма ajax поиск работает, все хорошо. Однако если создавать такое же поле оно не хочет ну накак работать через ajax.


А почему он должен обрабатывать? Ты понимаешь, как работают события в браузере, что такое обработчик событий, как он ставится, что такое addEventListener, всплытие событий? Если нет то стоит почитать теорию на learn.javascript.ru

Если ты думаешь что команда $('.some-class').click(...) говорит что при клике по some-class должна вызываться функция, то это не так. Она лишь находит на странице все элементы указанного класса и неэффективно в цикле ставит на них обработчики. Если ты не понимаешь этого, тебе надо начать с изуения DOM, событий и jQuery.

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

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

> $("<div class='field'>Номенклатура" + i +"<input name='search' id='search'


На странице не может быть 2 элементов с одинаковым id.

> $('.field:last').remove();


Незачем делать поиск, достаточно сохранить jQuery объект с добавленной строчкой в переменной

У тебя слишком много отступов и вложенности в JS коде. Функции надо писать друг над другом, а не устраивать callback hell.

> <a href='#'


Кнопки верстаются тегом button, тег a предназначен для ссылки. Ссылка должна куда-то вести и у нее не может быть прописано # в href

> cache: false,


Непонятно зачем отключать здесь кеширование, оно полезно. И так как POST запросы не кешируются, логично заменить его на GET. Он по смыслу больше подходит для автокомплита.

> $query = mysqli_query


Нет проверки и обработки ошибок. После почти каждой mysqli функции ты обязан писать if с проверкой ошибок

> otdel_name LIKE '%". $search


Нельзя вставлять переменные в запрос это SQL инъекция. Надо использовать плейсходеры и prepared statements.

> echo "<table style='width: 100%;'>";


Не надо смешивать HTML и PHP логику, HTML надо выносить в шаблоны.

> }while($sql = mysqli_fetch_array($query));


Есть функция, которая выбирает все строки сразу. Незачем писать do/while.

В SQL запросе нет ограничения на число результатов и сортировки результатов.

В общем, по моим ощущениям тебе стоило бы получше изучить все веб-техногии: HTML, CSS, JS, PHP, SQL, делать рабочие проекты с твоим уровнем рановато.

Кстати задачи из ОП поста вполне помогли бы закрыть тебе пробелы, если конечно у тебя достаточно свободного времени.
#540 #578909
>>577703

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


Не нужно писать велосипед, есть готовые решения: jQuery UI Autocomplete, Chosen, Select2

> Если делать отдельное поле на странице, то есть не создавать его через jquery, а сразу прописать в html, то форма ajax поиск работает, все хорошо. Однако если создавать такое же поле оно не хочет ну накак работать через ajax.


А почему он должен обрабатывать? Ты понимаешь, как работают события в браузере, что такое обработчик событий, как он ставится, что такое addEventListener, всплытие событий? Если нет то стоит почитать теорию на learn.javascript.ru

Если ты думаешь что команда $('.some-class').click(...) говорит что при клике по some-class должна вызываться функция, то это не так. Она лишь находит на странице все элементы указанного класса и неэффективно в цикле ставит на них обработчики. Если ты не понимаешь этого, тебе надо начать с изуения DOM, событий и jQuery.

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

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

> $("<div class='field'>Номенклатура" + i +"<input name='search' id='search'


На странице не может быть 2 элементов с одинаковым id.

> $('.field:last').remove();


Незачем делать поиск, достаточно сохранить jQuery объект с добавленной строчкой в переменной

У тебя слишком много отступов и вложенности в JS коде. Функции надо писать друг над другом, а не устраивать callback hell.

> <a href='#'


Кнопки верстаются тегом button, тег a предназначен для ссылки. Ссылка должна куда-то вести и у нее не может быть прописано # в href

> cache: false,


Непонятно зачем отключать здесь кеширование, оно полезно. И так как POST запросы не кешируются, логично заменить его на GET. Он по смыслу больше подходит для автокомплита.

> $query = mysqli_query


Нет проверки и обработки ошибок. После почти каждой mysqli функции ты обязан писать if с проверкой ошибок

> otdel_name LIKE '%". $search


Нельзя вставлять переменные в запрос это SQL инъекция. Надо использовать плейсходеры и prepared statements.

> echo "<table style='width: 100%;'>";


Не надо смешивать HTML и PHP логику, HTML надо выносить в шаблоны.

> }while($sql = mysqli_fetch_array($query));


Есть функция, которая выбирает все строки сразу. Незачем писать do/while.

В SQL запросе нет ограничения на число результатов и сортировки результатов.

В общем, по моим ощущениям тебе стоило бы получше изучить все веб-техногии: HTML, CSS, JS, PHP, SQL, делать рабочие проекты с твоим уровнем рановато.

Кстати задачи из ОП поста вполне помогли бы закрыть тебе пробелы, если конечно у тебя достаточно свободного времени.
#541 #578910
>>577769

> $app->request->get->cookie()


Это никогда не было методом получения кук

>>577821

> "Сперва добейся", я понял. Только у тебя привилегия


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

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

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


Обычно (гарантий нет) они не поддерживают куки и не выполняют JS код. Они себя идентифицируют 2 способами: User-Agent, у каждого бота свой, я тебе дал ссылку на сайт где собрана куча UA, в том числе поисковых ботов. Также, информацию можно найти в самой поисковой системе, например яндекс: https://yandex.ru/support/webmaster/robot-workings/check-yandex-robots.xml

Заметь что кто угодно может прикинуться ботом и по идее надо проверять еще IP-адрес на принадлежность яндексу. Но в твоем случае это не требуется, хочет человек притвориться яндексом, пусть притворяется.

В общем универсального способа нет, из практических есть проверка кук/JS (например сбор статистики аякс запросом) либо взять 5-10 популярных систем и проверять UA на соответсвие списку.

Подумай еще как это можно сделать максимально просто и с минимумом ложных срабатываний.

А, вспомнил! Есть еще так назваемая договоренность про robots.txt.Ты можешь поместить на сервер этот файл и описать в нем адреса, на которые боты заходить не имеют права. И вписать туда скрипт сбора статистики. Заметь, что robots это именно договоренность. Порядочный бот идентифицирует себя с помощью UA, подчиняется robots и взамен за это просит его не банить. Непорядочный бот может делать что угодно, кто ему запретит, но если он попадется, то пощады пусть не ждет.

Подробнее:

- http://www.robotstxt.org/
- http://robotstxt.org.ru/
- https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9_%D0%B4%D0%BB%D1%8F_%D1%80%D0%BE%D0%B1%D0%BE%D1%82%D0%BE%D0%B2
- https://yandex.ru/support/webmaster/controlling-robot/robots-txt.xml

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

Также, поисковые роботы гугла и яндекса подчиняются атрибуту rel="nofollow" на ссылке и некоторым метатегам: https://yandex.ru/support/webmaster/controlling-robot/html.xml

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


Мне нравится низкоуровневый адаптер. Он проще в реализации и логика работы с редисом остается в 1 экземпляре в VC, а не копируется в каждый адаптер. А так логика будет многократно дублироваться, и сейчас в адаптере у тебя перемешаны высокоуровневые и низкуровневые методы (addUniqueVisit и getFromQueue).

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

https://getcomposer.org/doc/04-schema.md#description
https://getcomposer.org/doc/04-schema.md#license

> https://github.com/nsdvw/visit-counter/blob/master/VisitCounter.php#L17


> public function setDb(Db\DbAdapter $dbAdapter)


DbAdapter необязательный? Странно конечно. Ведь вызов moveToDb может упасть с ошибкой.

> considerVisit


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

> $batchCount = intval(floor($queueLen/$this->perTransaction));


Почему окугление вниз? Что если длина очередь меньше размера транзакции?

> public function moveBatch($count)


С какой целью публичная?

> https://github.com/nsdvw/visit-counter/blob/master/Db/DbAdapter.php#L9


> public function __construct($connection)


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

> https://github.com/nsdvw/visit-counter/blob/master/Db/PdoAdapter.php


> $tblName;


Эта настройка не сделана обязательной и не имеет значения по умолчанию. Значит если мы простосоздадим объект адаптера то произойдет ошибка при попытке использования. Это неправильно. Если система позволила тебе создать объект то он должен быть работоспособен. Так гораздо проще.

> IN ({$pageList})";


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

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


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

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

Просто по моему, если ты знаешь Юи 1, а тем более Юи 2, понимаешь некоторые паттерны, нормализацию, индексы, знаешь ООП, умеешь работать с редисом и сфинксом, то у тебя более чем достаточно знаний для того чтобы быть джуниором (не в любой компании конечно, где-то планка высокая, но там видимо ищут людей с опытом). Ты уже можешь работать и приносить пользу в реальном проекте.
#541 #578910
>>577769

> $app->request->get->cookie()


Это никогда не было методом получения кук

>>577821

> "Сперва добейся", я понял. Только у тебя привилегия


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

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

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


Обычно (гарантий нет) они не поддерживают куки и не выполняют JS код. Они себя идентифицируют 2 способами: User-Agent, у каждого бота свой, я тебе дал ссылку на сайт где собрана куча UA, в том числе поисковых ботов. Также, информацию можно найти в самой поисковой системе, например яндекс: https://yandex.ru/support/webmaster/robot-workings/check-yandex-robots.xml

Заметь что кто угодно может прикинуться ботом и по идее надо проверять еще IP-адрес на принадлежность яндексу. Но в твоем случае это не требуется, хочет человек притвориться яндексом, пусть притворяется.

В общем универсального способа нет, из практических есть проверка кук/JS (например сбор статистики аякс запросом) либо взять 5-10 популярных систем и проверять UA на соответсвие списку.

Подумай еще как это можно сделать максимально просто и с минимумом ложных срабатываний.

А, вспомнил! Есть еще так назваемая договоренность про robots.txt.Ты можешь поместить на сервер этот файл и описать в нем адреса, на которые боты заходить не имеют права. И вписать туда скрипт сбора статистики. Заметь, что robots это именно договоренность. Порядочный бот идентифицирует себя с помощью UA, подчиняется robots и взамен за это просит его не банить. Непорядочный бот может делать что угодно, кто ему запретит, но если он попадется, то пощады пусть не ждет.

Подробнее:

- http://www.robotstxt.org/
- http://robotstxt.org.ru/
- https://ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B0%D0%BD%D0%B4%D0%B0%D1%80%D1%82_%D0%B8%D1%81%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B9_%D0%B4%D0%BB%D1%8F_%D1%80%D0%BE%D0%B1%D0%BE%D1%82%D0%BE%D0%B2
- https://yandex.ru/support/webmaster/controlling-robot/robots-txt.xml

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

Также, поисковые роботы гугла и яндекса подчиняются атрибуту rel="nofollow" на ссылке и некоторым метатегам: https://yandex.ru/support/webmaster/controlling-robot/html.xml

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


Мне нравится низкоуровневый адаптер. Он проще в реализации и логика работы с редисом остается в 1 экземпляре в VC, а не копируется в каждый адаптер. А так логика будет многократно дублироваться, и сейчас в адаптере у тебя перемешаны высокоуровневые и низкуровневые методы (addUniqueVisit и getFromQueue).

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

https://getcomposer.org/doc/04-schema.md#description
https://getcomposer.org/doc/04-schema.md#license

> https://github.com/nsdvw/visit-counter/blob/master/VisitCounter.php#L17


> public function setDb(Db\DbAdapter $dbAdapter)


DbAdapter необязательный? Странно конечно. Ведь вызов moveToDb может упасть с ошибкой.

> considerVisit


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

> $batchCount = intval(floor($queueLen/$this->perTransaction));


Почему окугление вниз? Что если длина очередь меньше размера транзакции?

> public function moveBatch($count)


С какой целью публичная?

> https://github.com/nsdvw/visit-counter/blob/master/Db/DbAdapter.php#L9


> public function __construct($connection)


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

> https://github.com/nsdvw/visit-counter/blob/master/Db/PdoAdapter.php


> $tblName;


Эта настройка не сделана обязательной и не имеет значения по умолчанию. Значит если мы простосоздадим объект адаптера то произойдет ошибка при попытке использования. Это неправильно. Если система позволила тебе создать объект то он должен быть работоспособен. Так гораздо проще.

> IN ({$pageList})";


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

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


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

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

Просто по моему, если ты знаешь Юи 1, а тем более Юи 2, понимаешь некоторые паттерны, нормализацию, индексы, знаешь ООП, умеешь работать с редисом и сфинксом, то у тебя более чем достаточно знаний для того чтобы быть джуниором (не в любой компании конечно, где-то планка высокая, но там видимо ищут людей с опытом). Ты уже можешь работать и приносить пользу в реальном проекте.
#542 #578913
>>577910

> Можно ли вызвать метод класса foo?


Для этого класс bar должен где-то иметь ссылку на класс foo (что за привычка писать классы с маленькой буквы? сбивает с толку). Такое часто бывает, что 2 класса содержат ссылки друг на друга (например начальник на подчиненных, а подчиненные на начальника), но система получается сложнее.

Как передать ссылку? Ну можно например в конструкторе foo внедрить ее в $a через какой-то метод $a->setFoo($this);

>>577946

У тебя 7 языков программирования или 7 языков народов мира? В первом случае, думаю, все будет в порядке. Спрос на грамотных разработчиков высок. Поиски можешь начать с geekjob, moikrug, hh.ru

>>578117

Слушай, тут слишком много кода чтобы разбираться. Упрости пример до минимума, чтобы там было не больше 3-4 тегов и залей на jsfiddle или подобный сайт, чтобы сразу можно было посмотреть. Также напиши свое видение ситуации: какие методы позиционирования тут можно бы применить и что в них не устраивает тебя.

Ну и держи ссылку на хороший учебник по позиционированию, читать снизу вверх: http://softwaremaniacs.org/blog/category/primer/

И у нас в ОП посте есть хорошие задания на HTML/CSS которые помогут тебе разобраться с версткой. Обрати на них внимание.

>>578125

Ну ты торопыга. Тред создан всего 10 дней назад и в нем даже 650 постов не набили еще.
#543 #578914
>>578842

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

Смотри, на что надо смотреть:

> Requests per second: 3.49 [#/sec] (mean)


3 запроса в секуду обрабатывается. Это очень мало. Смотри, допустим 1 человек просматривает в среднем 15 динамических страниц (это зависит от специфики сайта, на форуме например эта цифра значительно больше, на новостном сайте может быть меньше). Твой сайт сможет обработать в сутки 86400 x 3.5 = 300 000 запросов или 20 000 посетителей. Это очень мало.

> Failed requests: 0


Это хорошо, что не было ни одной ошибки. Скорость не имеет смысла если ответ отдается с ошибкой.

> Time per request: 1430.804 [ms] (mean)


Время обработки запроса: слишком долго. Надо стремится к 50-200 (в зависимости от сложности сайта).

> Transfer rate: 236.08 [Kbytes/sec] received


Скорость передачи данных - очень маленькая из-за маленького числа обработанных запросов

> Connection Times (ms)


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

> Percentage of the requests served within a certain time (ms)


Сколько процентов запросов в какое время укладывается

Надо искать узкие места. Почему так долго обрабатывется запрос? Используется ли например ресурс процессора на полную мощность или процессор простаивает и ждет медленного диска? Если у тебя Линукс то для него есть куча полезных утилит: http://habrahabr.ru/post/114082/

Я советую применить htop, iotop, mytop. Если у тебя Windows, то попробуй диспетчер задач, начиная с семерки он неплох.

Замерь потребление процессора, используется ли он на 100% или простаивает? Какие процессы его используют и насколько? Достаточно ли памяти? Не идет ли своп? Сколько памяти занимают разные процессы? Как нагружен диск? Сколько трафика/IOPS? Не нагружена ли сеть, не идет ли обращение к внешним медленным ресурсам?

И кстати какое у тебя железо? Ты случайно не в вирутальной машине на китайском андроидофоне сервер поднял?

Для ОП-кешера стоит смотреть статистику его исплоьзования, много ли hits/misses, сколько занято памяти.

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

Я вижу в профайлере вызов CActiveRecord->findAll() который занял 74 мс, что-то много. Сколько ты там записей выбираешь? Эффективно ли? И еще вижу EAVACtiveRecord->findAll, который занимает около 40 мс внутри CListView->init

И еще у тебя 3600 вызовов Twig_template->getAttribute, не многовато ли? Это большая страница?

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

> Не знаю, о чем говорят тесты, но судя по логам yii, страница генерировалась 1.4 секунды, а по моему глазомеру даже дольше. Многовато что-то.


По глазомеру может быть больше, если браузер ждет пока загрузятся какие-то скрипты. График загрузки есть на вкладке Network инспектора.

> Что еще можно оптимизировать или закешировать?


Нужно для начала понять на что тратятся ресурсы системы, как загружен процессор. Кеширование это больше костыль, там и так много уровней кеширования (кеширование в БД например) и лишние слои могут только усложнить систему.
#543 #578914
>>578842

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

Смотри, на что надо смотреть:

> Requests per second: 3.49 [#/sec] (mean)


3 запроса в секуду обрабатывается. Это очень мало. Смотри, допустим 1 человек просматривает в среднем 15 динамических страниц (это зависит от специфики сайта, на форуме например эта цифра значительно больше, на новостном сайте может быть меньше). Твой сайт сможет обработать в сутки 86400 x 3.5 = 300 000 запросов или 20 000 посетителей. Это очень мало.

> Failed requests: 0


Это хорошо, что не было ни одной ошибки. Скорость не имеет смысла если ответ отдается с ошибкой.

> Time per request: 1430.804 [ms] (mean)


Время обработки запроса: слишком долго. Надо стремится к 50-200 (в зависимости от сложности сайта).

> Transfer rate: 236.08 [Kbytes/sec] received


Скорость передачи данных - очень маленькая из-за маленького числа обработанных запросов

> Connection Times (ms)


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

> Percentage of the requests served within a certain time (ms)


Сколько процентов запросов в какое время укладывается

Надо искать узкие места. Почему так долго обрабатывется запрос? Используется ли например ресурс процессора на полную мощность или процессор простаивает и ждет медленного диска? Если у тебя Линукс то для него есть куча полезных утилит: http://habrahabr.ru/post/114082/

Я советую применить htop, iotop, mytop. Если у тебя Windows, то попробуй диспетчер задач, начиная с семерки он неплох.

Замерь потребление процессора, используется ли он на 100% или простаивает? Какие процессы его используют и насколько? Достаточно ли памяти? Не идет ли своп? Сколько памяти занимают разные процессы? Как нагружен диск? Сколько трафика/IOPS? Не нагружена ли сеть, не идет ли обращение к внешним медленным ресурсам?

И кстати какое у тебя железо? Ты случайно не в вирутальной машине на китайском андроидофоне сервер поднял?

Для ОП-кешера стоит смотреть статистику его исплоьзования, много ли hits/misses, сколько занято памяти.

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

Я вижу в профайлере вызов CActiveRecord->findAll() который занял 74 мс, что-то много. Сколько ты там записей выбираешь? Эффективно ли? И еще вижу EAVACtiveRecord->findAll, который занимает около 40 мс внутри CListView->init

И еще у тебя 3600 вызовов Twig_template->getAttribute, не многовато ли? Это большая страница?

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

> Не знаю, о чем говорят тесты, но судя по логам yii, страница генерировалась 1.4 секунды, а по моему глазомеру даже дольше. Многовато что-то.


По глазомеру может быть больше, если браузер ждет пока загрузятся какие-то скрипты. График загрузки есть на вкладке Network инспектора.

> Что еще можно оптимизировать или закешировать?


Нужно для начала понять на что тратятся ресурсы системы, как загружен процессор. Кеширование это больше костыль, там и так много уровней кеширования (кеширование в БД например) и лишние слои могут только усложнить систему.
Тред закрыт #544 #578916
Аноны, давайте переходить в новый тред >>578124 (OP)

Этот тред закрыт.

Если я кому-то не ответил, напомните о себе в новом треде.
Тред утонул или удален.
Это копия, сохраненная 1 декабря 2015 года.

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

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
« /pr/В начало тредаВеб-версияНастройки
/a//b//mu//s//vg/Все доски