Art-revolver или как не стоит делать сайты
Я хотел рассказать об этом проекте, когда он будет уже совсем в production, но его у меня забрали, поэтому, чтобы не забыть, пишу сейчас.
Я не ставлю целью якобы обличить “дураков-заказчиков” и “дураков-менеджеров”, а себя выгородить как жертву обстоятельств, а просто пытаюсь поделиться опытом и рассказать, как не стоит делать сайты. Тем более сложные.
Сначала расскажу немного о себе, чтобы вы понимали обстановку на момент начала работы над проектом. Мне 23, программирую с переменным успехом с 15 лет, были долгие (несколько лет) перерывы в связи с отсутствием компьютера и/или должной мотивации. Поэтому в то время, когда некоторые мои ровесники на этом ресурсе вовсю пишут дополнения с применением Node.js, я едва научился делать действительно неплохие сайты. Работать с MODX Revo я начал осенью 2015 года, до этого год делал сайты на OpenCart, до этого год – на MODX Evo.
Собственно, именно с осени 2015 началась разработка этого проекта. Полгода он обсуждался заказчиком и директором веб-студии, в которой я работал. Заказчик – профессиональный фотограф с большим опытом и собственной большой студией, лауреат международных выставок. Он обнаружил, что на российском рынке отсутствует ресурс, похожий на всемирно известный YelloKorner и решил сделать его аналог.
YelloKorner – это огромный интернет-магазин с фотографиями, которые печатаются ограниченным тиражом на отличной бумаге и имеют уникальные идентификаторы. Почти тоже самое, что купить хорошую картину, в общем-то. Так вот. Несмотря на то, что проект обсуждался с сентября 2015 по январь 2016, я к моменту начала работы не получил вообще никакого технического задания. Только общие фразы: “интернет-магазин с двумя языками, опциями товара, от которых зависит цена, личный кабинет и платежная система”. Если убрать всю воду из того “ТЗ”, то получается, что это все. Бюджет на разработку, прошу не ржать в голос – десять в пятой степени рублей, из них только (два в шестой степени минус четыре) тысяч рублей – на оплату труда программиста. Техническое задание я придумал у себя в голове уже тогда, когда получил дизайн-макеты будущего сайта.
И оно получалось примерно таким:
Мультиязычный интернет-магазин по продаже фотографий с различными опциями – размер фото, наличие/отсутствие рамки, выбор бумаги. Каждая опция имеет свою цену, и при ее выборе общая цена товара меняется. При изменении размера фотографии и ее опций – рамка, тубус, бумага – фотография товара должна меняться на соответствующую заданным параметрам. На сайте должна быть функция фотобанка – продажа цифровых копий фотографий по заданной стоимостьи, с защитой от копирования и защитой от несанкционированного скачивания. На сайте должен быть реализован личный кабинет автора – человека, который выставляет свои фотографии на продажу. Он должен иметь возможность менять аватарку, фон в личном кабинете, заполнять информацию о себе, указывать ссылки в соц.сетях, а так же, добавлять товары. Цены на сайте должны быть реализованы в двух валютах – рубли и евро. При переключении языка цена товара меняется на соответствующую: русский – рубли, английский – евро, с конвертацией по актуальному курсу. На сайте должен быть реализован блог – раздел, где авторы делятся своим опытом и дискуссируют на различные темы. Блог, опять же, двуязычный. На сайте должна присутствовать поисковая система и фильтр товаров по характеристикам – цветовой тон фотографии, раздел, тип товара (живопись, фото, фотобанк). Оплата на сайте должна производиться с помощью систем PayPal для иностранных клиентов и Яндекс.Касса для российских. Все.
Ошибка номер 1. При создании более-менее нестандартного сайта требуйте полное техническое задание. Со всеми, со всеми подробностями! Если ни у кого нет на ТЗ времени – не беритесь за проект, пока ТЗ не будет. Или составьте сами посредством интервью с заказчиком. За отдельную плату, офкорс.
Окей. Так как я был работником веб-студии, оспаривать бюджет права не имел, ибо все равно, оплата сдельная, а не попроектная. Получаю свои пять умножить на шесть тысяч рублей в месяц и ок. Начал работу. Мне с самого начало казалось, что моих способностей на это не хватит, но договор есть, крутись-вертись, но делай. Да и по-хорошему, такое бы на каком-нибудь Laravel делать, ведь чуяло мое сердце, что все будет не так просто, особенно с фотобанком. Это же ведь, защиту нужно придумать, способ передачи фотокопии клиенту, и вообще и вообще. Но, наша веб-студия делала сайты только на MODX Revo, и никак иначе.
Итак, ход мыслей:
Размер 30*45 Базовая цена
Размер 40*60 Кастомная цена
Размер 120*180 Кастомная цена
Бумага Fuji 0 рублей
Бумага Epson 1000 рублей
Без рамки 0 рублей
Пенокартон 1000 рублей
Пенокартон + рамка 2000 рублей
Техническое задание получается теперь таким:
Интернет-магазин по продаже фотографий с различными опциями – размер фото, наличие/отсутствие рамки, выбор бумаги. Каждая опция имеет свою цену, и при ее выборе общая цена товара меняется. Но! Все опции взаимосвязаны между собой определенным ценовым коэффициентом. То есть, если размер фотографии 30*45, то цена бумаги одна, цена рамки одна, то при размере фотографии 40*60 цена бумаги становится другой, цена рамки – другой, и все в том же духе. Мало того. Размеры фотографий тоже должны задаваться вручную, так как не всегда фотографии делаются именно в этих стандартных размерах, есть исключения. При этом, для определенного типа бумаги действительны одни размеры фотографии, для другого типа бумаги – другие, так как большой формат не печатают на Fuji, а маленький не печатают на Epson. А с холстом вообще все сложно – его нельзя натянуть на паспарту и пенокартон, только в рулоне или подрамнике. А для фотобумаги нельзя выбрать подрамник.
Получается крайне изощренная система опций. Если попытаться осмыслить всю эту систему с первого раза, то скорее всего, голова задымится. А ведь это еще закодить надо…
Логика работы фотобанка тоже пересмотрена заказчиком – товар не продается по одной цене, можно купить разные копии фото – в маленьком разрешении, в стандартном, и в HD.
Система с Babel тоже не выдерживает критики от заказчика, так как заполнять два ресурса для одного товара слишком утомительно, да и в блоге должны быть и русские комментарии, и зарубежные. Необходимо сделать так, чтобы язык менялся как-то иначе, Babel ну вообще не вариант.
Итак. После встречи оказывается, что нужно за десять в пятой степени рублей сделать убер-магазин с нереальным функционалом, когда разработчик (т.е. я) ничего сложнее магазина свадебных платьев никогда не делал. Я понимаю, что все, что я могу сделать – это суперкостыльный сайт, но ничего с этим поделать не могу, так как я единственный разработчик с кучей проектов на очереди. И что же мы делаем дальше?
Правильно! Еще на месяц забиваем на этот проект, ибо он на рассрочке, а деньги-то нужны. Тем временем в моей жизни происходят кое-какие изменения, и я вынужден покинуть место работы и уехать из города на пару месяцев. Я нахожу себе замену – на MODX.pro я оставлял даже соответствующее объявление, и уезжаю. Art-revolver остается на мне, так как новый разработчик, хоть вроде, даже поумнее меня, но ему сходу дают парсинг и перенос крупного сайта с самописной CMS на MODX + все старые проекты. Ему точно некогда, и так, задержки по всем фронтам. Договариваемся с боссом, что я за оставшиеся из бюджета пять умножить на шесть тысяч рублей доделаю этот сайт и мы больше ничего друг другу не должны. Сайт практически не работает, все нужно переделывать. То есть, по цене обычного небольшого магазина я должен за два месяца сделать суперпроект. Но деваться некуда, иных источников дохода я найти не могу, так как обстоятельства, беру и делаю.
Ошибка номер 2. Если дело пахнет керосином, а денюжка небольшая – бегите. Больше потеряете, чем заработаете. И это не только о деньгах. Еще есть нервы там, личное время…
Ошибка номер 3. Если вы понимаете, что не осилите проект, не сможете сделать его хорошо – лучше слиться. Репутация и отношения дороже. У меня забрали проект, почти ничего не объяснив и никто со мной теперь не общается из тех людей. Такие дела.
Итак, я, находясь в непростой ситуации, начинаю уже более-менее осмысленно делать проект, теперь хотя бы есть общая картинка того, как это видит заказчик.
Далее по тексту наконец-то будут технические подробности реализации, УРА!
Так как я ранее много работал с OpenCart, то решил использовать их систему мультиязычности, в контексте работы с MODX. И такую систему я накостылил следующим образом.
В менюшке есть переключалка языка – rus/eng. Язык по-умолчанию – русский. Ссылка на переключалке имеет GET-параметр “lang”, который передает серверу команду на переключение словарей в плагине на событие OnHandleRequest и сохраняет текущую настройку в куках:
На фронте замена всего происходит так.
Пункты меню, наименования опций, кнопки и прочая фиготень берут тексты из нужных записей словаря текущего языка:
Названия ресурсов и их страниц обрабатывают сниппеты getPagetitle и getContent:
Система опций.
Бэкенд.
Толком кодить на JS я не умею, кастомизировать miniShop2 и админку MODX для меня задача непосильная. До сих пор боюсь. Решил продолжить делать все на MIGX, знатно расширив таблицу опций и сделав значения по-умолчанию, а если надо, то в карточке товара можно что-нибудь подправить. Расширил таблицу следующим образом – есть пять размеров фотографии – от обычной рамочной, до полотна на всю стену. Каждый размер имеет свои ценовые значения для каждой опции – бумага, рамка, тубус, стоимость печати. По идее, при выборе нужного чекбокса на фронтенде, JS-скрипт лезет через AJAX на сервер и тянет нужные цены для выбранного параметра, типа, вот так:
Сама таблица опций MIGX выглядит так:
Фронтенд.
Боль моей души. Мой ночной кошмар. Мое незнание JavaScript…
Когда я начинал учиться веб-разработке, то у меня было две книги по HTML 4 (дело было в 2009 году), написанные русскими авторами, и оба они советовали забить на JS, ибо Flash это революция и он всех порвет. С тех пор и до 2016 года я упорно забивал на изучение JS (а препод по JS в универе только усилил ненависть к JS) и юзал только jQuery. Удобно же.
Ошибка номер 4. Выучи JS. Научись делать все классами/методами/объектами, и перестань быдлокодить на уровне if/else.
Собственно, за систему опций мне стыдно больше всего на этом сайте. Те, кто осиливает сейчас этот текст, и до сих пор не забил, может зайти на сайт и поковырять там код в карточке товара. Обещаю – скучно не будет. Когда я это писал, я уже понимал, что это полное д***мо. Но иначе не умел. Да и сейчас, я едва-едва начал что-то понимать в классах и методах, благо немного освоил Node.js, он дал мне неплохое представление о хорошем JS коде. Да и изучение исходников JS кода miniShop2 тоже помогает.
Когда я закончил эту систему опций, если не ошибаюсь, в июле, Володя выкатил новый, обновленный релиз msOptionsPrice2.
Интересно узнать, умеет ли этот компонент все то, что заложено в ТЗ в этом топике?
upd. Изменение фото в зависимости от опций
При выборе параметров необходимо изменять превью и фото товаров на соответствующие опциями. Совать 32 возможных варианта в админку — нереально, плюс неизвестно, как это выводить. Поэтому решение получилось примерно таким:
Есть две подложки — для маленьких форматов и больших — на столе и за диваном.
Есть само изображение товара. Есть опции в виде рамок и их цветов.
Путем переключения radio кнопок с помощью HTML+CSS я накладываю одну картинку на другую и CSS рисую рамку. Чтобы CSS был более-менее адекватным, была сделана система префиксов параметров:
размер фона — ориентация фото — размер фото, то есть, в боевом режиме:
класс .sofa-vertical-real означает показать фотографию за диваном в вертикальной ориентации в большом размере
Далее. Личный кабинет.
Так как к этому времени Володя уже убрал из магазина UserProfile, то ничего не оставалось, как купить Office. Запросил бюджет на компонент от заказчика, настроил по мануалу. А дальше самое интересное. По-идее, на сайте должно быть две группы пользователей – авторы и покупатели. Авторы – выставляют товары, делают посты, имеют аватарки и личные странички. Покупатели – только покупают и смотрят в личном кабинете статус заказа. Оказалось, что НИКТО вообще не знает, как должен выглядеть кабинет покупателя и что там должно быть. Мало того, оказалось, что НИКТО до конца не знает, как должен выглядеть кабинет автора, и что там должно быть. Нет, на макете был нарисован кабинет автора – личная страничка, аватарка, текст о себе, ссылки в соц.сетях, выставленные работы. Но нет кнопок – добавить товар, редактировать товар, выйти из личного кабинета, еще-что нибудь. На мои плечи, помимо реализации двух разных кабинетов, еще ложится разработка логики работы авторов и покупателей, так как никто кроме меня вообще не в курсе того, что это нужно. Иначе вообще же смысла в кабинете нет.
Повторяю ошибку номер 1. Техническое задание. Полностью. Без него трудные проекты – не брать. Нельзя сделать хороший проект на одних разговорах. Нельзя. Нереально.
Итак, права пользователей и роутинг кабинетов. В админке создаем два контейнера ресурсов – пользователи и авторы. На всякий затер id страниц, мало ли что.

Далее создаем две группы пользователей – users и authors.
Роутинг осуществляется по заметке Василия, в плагине на событие OnPageNotFound, примерно так:
Сам же шаблон страницы автора не так интересен. Картинка-фон к кабинету это адрес картинки, который хранится в extended поле юзера, его биография и ссылки на соц.сети – тоже extended. Как я реализовал загрузку кастомной картинки в кабинет пользователя – не помню. Не могу найти в исходниках (о бардаке в чанках и сниппетах — позже).
Внезапно оказывается, что заказчик хочет менять цвет текста-описания биографии. Естественно, учить HEX-кодам не вариант, HTML 5 поле color не все браузеры еще умеют, прилепил jQuery плагин, который показывает форму выбора цвета и сохраняет в extended поле HEX код. А при загрузке кабинета это прописывается прям в “style” атрибут тега с текстом. Костыль, но опять же. Задача внезапная, а увеличения бюджета тоже не планируется.
На следующий день заказчик хочет, чтобы во время редактирования текста биографии в textarea поле отображалась фоновая картинка, чтобы можно было менять цвет текста и сразу смотреть как это выглядит.

Ошибка номер 4. Никаких новых хотелок по ходу работы. Только после завершения оговоренных работ. Иначе разработка превратится в бесконечный цирк, где денег за доп.работу можно и не увидеть. Или увидеть не в полном объеме.
Загрузка товаров авторами
Это тоже задачка была не из простых, но к счастью, есть ms2Form. С горем-пополам настроил модуль, товары создаются. Правда, из-за того, что товары разные, и каждый тип имеет свои уникальные характеристики, пришлось сделать сначала выбор типа товара, потом AJAX’ом загружать сниппет и отдавать шаблон.

—
Во время настройки ms2Form произошел знатный прикол, который отнял у меня пару дней времени. Оказалось, что если один пользователь загружает фото товара к своему товару, но внезапно бросил это дело, и закрыл браузер, то если другой автор будет грузить свой товар и свои фото, то он будет видеть, что грузил другой автор. Но так как права на редактирования чужих товаров он не имеет, то и свой товар загрузить не может. Конфликт! Решилось ковырянием исходников ms2Form и раскомментированием последних строчек в сниппете ms2Form (да, нужные строчки были почему-то закомментированы).
В общем, с горем пополам, за две-три недели личные кабинеты пользователей двух групп и доступ к анонимам был реализован.
Переходим к самому прикольному – фотобанку
Идея реализовать полноценный фотобанк в стиле Fotolia на базе MODX, имея не самые хорошие знания платформы, как я уже говорил, с самого начала казалось мне плохой. Но, вызов принят. Арсенал костылей еще полон, полный вперед!
Итак, идея примерно такова.
Нужен раздел на сайте, продающий цифровые товары, то есть, ссылки на фотографии в различном разрешении. При этом, файлы нельзя скачать посторонним пользователям, доступ к ссылке имеют только купившие товар. В идеале, ссылка всегда должна хэшироваться и для каждого юзера быть уникальной. Фотографии хранятся в HD, и весят по 15-20 мегабайт. Хранить все это добро на shared-хостинге идиотизм. Но об этом, как всегда, никто не подумал. Поэтому я, вооружившись Swift, настроил облако Selectel и фотобанк хранится там. Хранение фотографий сначала реализовал с помощью FileAttach. Он даже ссылочки хэшировать умеет. Но, как оказалось, он работает только с локальным хранилищем, а с облаком не умеет. Ума допилить компонент у меня не хватило. Поэтому я обратил внимание на компонент от Володи – UserFiles. Подостовав Володю в тех.поддержке, я таки-настроил компонент и фотки загружаются в Selectel и хранятся там. Проблема только в том, что ссылки не хэшируются, и купивший фотографию человек, может спокойно расшарить ссылку всем. Но, думаю, до этого не дойдет.
Как же сделана выдача ссылок покупателю?
Подразумевается, что купить фотку в фотобанке можно только картой. Значит, у такого товара будет статус “ОПЛАЧЕН”. Выходит, задача такая – найти пользователя, который купил этот товар, проверить статус товара и вывести сниппет UserFiles со ссылкой на фотку. Создал сниппет getBuyingPhotos и поместил вызов сниппета на странице покупателя, сразу под стандартным кабинетом Office на ExtJs.
Код сниппета getBuyingPhotos:
Бардак в коде
Проект делался (а точнее, делается) уже год.
За это время мои знания улучшались, но из-за спешки в реализации я не соблюдал никакой логики в хранении и именовании элементов, поэтому сейчас на сайте, чтобы понять, как что-то работает, нужно убить достаточно времени, ибо сразу отыскать все сниппеты и чанки задача не из легких.
Уже в сентябре я освоил Fenom и файловые элементы, когда большая часть была сделана, а переделывать такую махину было уже лень. Тем более, не забываем о оплате в пять умножить на шесть тысяч рублей. Тратить еще две недели на переписывание этого кошмара мне уже не моглось.
Ошибка номер 5. Следуй какой-то методике хранения элементов. Правильно называй чанки/сниппеты/плагины. Разложи все по папкам. По-хорошему – сделай все на файловых элементах Fenom, чтобы четко видеть местоложение всех элементов. Это реально удобно. Точнее, это нереально удобно.
Я уверен, что текущий разработчик, который занимается этим проектом, наверняка увидит этот пост, и может даже обратит на него внимание босса и заказчика. Возможно, я даже получу по шапке за эту публикацию. Но, я уверен, никаких договоренностей на этот счет нет ни у кого, а я вообще, как бы, не при делах. Да и код, по сути, мой. Почти что интеллектуальная собственность.
P.S. Я все же получил еще доплату за проект в размере два в четвертой степени минус одна тысяча рублей. Итого, за 8 месяцев работы гонорар по проекту вышел в два в шестой степени плюс одиннадцать тысяч рублей. Стоит ли проект этот суммы, несмотря на костыли? Как считаете?
P.S.2. За последние полгода я сделал достаточно проектов, за которые мне ни разу не стыдно. Все сделано реально круто. Везде Fenom, грамотное наследование шаблонов, неплохо (а местами очень хорошо) написанные сниппеты, хорошая верстка, TV в работе с miniShop2 почти не использую, только плагины товаров, вовсю использую словари и системные параметры, ну и вообще, за исключением внезапных приступов тупости (можно видеть в моих предыдущих топиках), считаю, что могу сказать, что делаю хорошие сайты. Но с Art-revolver судьба не сложилась.
Я не ставлю целью якобы обличить “дураков-заказчиков” и “дураков-менеджеров”, а себя выгородить как жертву обстоятельств, а просто пытаюсь поделиться опытом и рассказать, как не стоит делать сайты. Тем более сложные.
Сначала расскажу немного о себе, чтобы вы понимали обстановку на момент начала работы над проектом. Мне 23, программирую с переменным успехом с 15 лет, были долгие (несколько лет) перерывы в связи с отсутствием компьютера и/или должной мотивации. Поэтому в то время, когда некоторые мои ровесники на этом ресурсе вовсю пишут дополнения с применением Node.js, я едва научился делать действительно неплохие сайты. Работать с MODX Revo я начал осенью 2015 года, до этого год делал сайты на OpenCart, до этого год – на MODX Evo.
Собственно, именно с осени 2015 началась разработка этого проекта. Полгода он обсуждался заказчиком и директором веб-студии, в которой я работал. Заказчик – профессиональный фотограф с большим опытом и собственной большой студией, лауреат международных выставок. Он обнаружил, что на российском рынке отсутствует ресурс, похожий на всемирно известный YelloKorner и решил сделать его аналог.
YelloKorner – это огромный интернет-магазин с фотографиями, которые печатаются ограниченным тиражом на отличной бумаге и имеют уникальные идентификаторы. Почти тоже самое, что купить хорошую картину, в общем-то. Так вот. Несмотря на то, что проект обсуждался с сентября 2015 по январь 2016, я к моменту начала работы не получил вообще никакого технического задания. Только общие фразы: “интернет-магазин с двумя языками, опциями товара, от которых зависит цена, личный кабинет и платежная система”. Если убрать всю воду из того “ТЗ”, то получается, что это все. Бюджет на разработку, прошу не ржать в голос – десять в пятой степени рублей, из них только (два в шестой степени минус четыре) тысяч рублей – на оплату труда программиста. Техническое задание я придумал у себя в голове уже тогда, когда получил дизайн-макеты будущего сайта.
И оно получалось примерно таким:
Мультиязычный интернет-магазин по продаже фотографий с различными опциями – размер фото, наличие/отсутствие рамки, выбор бумаги. Каждая опция имеет свою цену, и при ее выборе общая цена товара меняется. При изменении размера фотографии и ее опций – рамка, тубус, бумага – фотография товара должна меняться на соответствующую заданным параметрам. На сайте должна быть функция фотобанка – продажа цифровых копий фотографий по заданной стоимостьи, с защитой от копирования и защитой от несанкционированного скачивания. На сайте должен быть реализован личный кабинет автора – человека, который выставляет свои фотографии на продажу. Он должен иметь возможность менять аватарку, фон в личном кабинете, заполнять информацию о себе, указывать ссылки в соц.сетях, а так же, добавлять товары. Цены на сайте должны быть реализованы в двух валютах – рубли и евро. При переключении языка цена товара меняется на соответствующую: русский – рубли, английский – евро, с конвертацией по актуальному курсу. На сайте должен быть реализован блог – раздел, где авторы делятся своим опытом и дискуссируют на различные темы. Блог, опять же, двуязычный. На сайте должна присутствовать поисковая система и фильтр товаров по характеристикам – цветовой тон фотографии, раздел, тип товара (живопись, фото, фотобанк). Оплата на сайте должна производиться с помощью систем PayPal для иностранных клиентов и Яндекс.Касса для российских. Все.
Ошибка номер 1. При создании более-менее нестандартного сайта требуйте полное техническое задание. Со всеми, со всеми подробностями! Если ни у кого нет на ТЗ времени – не беритесь за проект, пока ТЗ не будет. Или составьте сами посредством интервью с заказчиком. За отдельную плату, офкорс.
Окей. Так как я был работником веб-студии, оспаривать бюджет права не имел, ибо все равно, оплата сдельная, а не попроектная. Получаю свои пять умножить на шесть тысяч рублей в месяц и ок. Начал работу. Мне с самого начало казалось, что моих способностей на это не хватит, но договор есть, крутись-вертись, но делай. Да и по-хорошему, такое бы на каком-нибудь Laravel делать, ведь чуяло мое сердце, что все будет не так просто, особенно с фотобанком. Это же ведь, защиту нужно придумать, способ передачи фотокопии клиенту, и вообще и вообще. Но, наша веб-студия делала сайты только на MODX Revo, и никак иначе.
Итак, ход мыслей:
- Мультиязычность – значит Babel.
- Личный кабинет – Office. Но, он платный, а бюджет и так никакой. Однако, тогда еще лежал в репозитории UserProfile и Virtual Page от Володи. Берем.
- Магазин – значит miniShop2.
- Блог – Tickets.
- Цены в валюте – CurrencyRate.
- Поиск – mSearch2.
- Платежные системы – и так все ясно.
- Верстка – Bootstrap, ибо полюбил.
- Virtual Page и User Profile толком не хотят работать. То ли я криворукий, то ли что, но кабинет автора ну вообще не получался. Еле-еле сделал какое-то демо, где можно было менять аватарку и менять пароль с личной информацией.
- Опции товара с помощью MIGX и кривонаписанного JS скрипта реализовал созданием скрытого поля options[], которое добавляло стоимость.
Размер 30*45 Базовая цена
Размер 40*60 Кастомная цена
Размер 120*180 Кастомная цена
Бумага Fuji 0 рублей
Бумага Epson 1000 рублей
Без рамки 0 рублей
Пенокартон 1000 рублей
Пенокартон + рамка 2000 рублей
- Мультиязычность через разные контексты сделал. Все работает. Но вот проблема – некоторые вещи, такие как опции товара и какие-то другие тексты не переводились через Babel. О словарях я тогда знал немного.
- Поиска еще не было, как не было и фильтра.
- Фотографии к товарам не меняются при изменении опций, ибо я хз как это сделать вообще. Идей не было никаких.
- Блог, понятно дело, получился одноязычным, ибо писать две статьи и иметь на одной версии русские комментарии, а на другой – английские это идиотизм.
Техническое задание получается теперь таким:
Интернет-магазин по продаже фотографий с различными опциями – размер фото, наличие/отсутствие рамки, выбор бумаги. Каждая опция имеет свою цену, и при ее выборе общая цена товара меняется. Но! Все опции взаимосвязаны между собой определенным ценовым коэффициентом. То есть, если размер фотографии 30*45, то цена бумаги одна, цена рамки одна, то при размере фотографии 40*60 цена бумаги становится другой, цена рамки – другой, и все в том же духе. Мало того. Размеры фотографий тоже должны задаваться вручную, так как не всегда фотографии делаются именно в этих стандартных размерах, есть исключения. При этом, для определенного типа бумаги действительны одни размеры фотографии, для другого типа бумаги – другие, так как большой формат не печатают на Fuji, а маленький не печатают на Epson. А с холстом вообще все сложно – его нельзя натянуть на паспарту и пенокартон, только в рулоне или подрамнике. А для фотобумаги нельзя выбрать подрамник.
Получается крайне изощренная система опций. Если попытаться осмыслить всю эту систему с первого раза, то скорее всего, голова задымится. А ведь это еще закодить надо…
Логика работы фотобанка тоже пересмотрена заказчиком – товар не продается по одной цене, можно купить разные копии фото – в маленьком разрешении, в стандартном, и в HD.
Система с Babel тоже не выдерживает критики от заказчика, так как заполнять два ресурса для одного товара слишком утомительно, да и в блоге должны быть и русские комментарии, и зарубежные. Необходимо сделать так, чтобы язык менялся как-то иначе, Babel ну вообще не вариант.
Итак. После встречи оказывается, что нужно за десять в пятой степени рублей сделать убер-магазин с нереальным функционалом, когда разработчик (т.е. я) ничего сложнее магазина свадебных платьев никогда не делал. Я понимаю, что все, что я могу сделать – это суперкостыльный сайт, но ничего с этим поделать не могу, так как я единственный разработчик с кучей проектов на очереди. И что же мы делаем дальше?
Правильно! Еще на месяц забиваем на этот проект, ибо он на рассрочке, а деньги-то нужны. Тем временем в моей жизни происходят кое-какие изменения, и я вынужден покинуть место работы и уехать из города на пару месяцев. Я нахожу себе замену – на MODX.pro я оставлял даже соответствующее объявление, и уезжаю. Art-revolver остается на мне, так как новый разработчик, хоть вроде, даже поумнее меня, но ему сходу дают парсинг и перенос крупного сайта с самописной CMS на MODX + все старые проекты. Ему точно некогда, и так, задержки по всем фронтам. Договариваемся с боссом, что я за оставшиеся из бюджета пять умножить на шесть тысяч рублей доделаю этот сайт и мы больше ничего друг другу не должны. Сайт практически не работает, все нужно переделывать. То есть, по цене обычного небольшого магазина я должен за два месяца сделать суперпроект. Но деваться некуда, иных источников дохода я найти не могу, так как обстоятельства, беру и делаю.
Ошибка номер 2. Если дело пахнет керосином, а денюжка небольшая – бегите. Больше потеряете, чем заработаете. И это не только о деньгах. Еще есть нервы там, личное время…
Ошибка номер 3. Если вы понимаете, что не осилите проект, не сможете сделать его хорошо – лучше слиться. Репутация и отношения дороже. У меня забрали проект, почти ничего не объяснив и никто со мной теперь не общается из тех людей. Такие дела.
Итак, я, находясь в непростой ситуации, начинаю уже более-менее осмысленно делать проект, теперь хотя бы есть общая картинка того, как это видит заказчик.
Далее по тексту наконец-то будут технические подробности реализации, УРА!
Так как я ранее много работал с OpenCart, то решил использовать их систему мультиязычности, в контексте работы с MODX. И такую систему я накостылил следующим образом.
В менюшке есть переключалка языка – rus/eng. Язык по-умолчанию – русский. Ссылка на переключалке имеет GET-параметр “lang”, который передает серверу команду на переключение словарей в плагине на событие OnHandleRequest и сохраняет текущую настройку в куках:
<?php
if($modx->context->key == "mgr"){return;}
else
{
$defaultLang = 'ru';
if (empty($_COOKIE['lang'])){
$siteLang = $defaultLang;
setcookie('lang',$siteLang);
} else {
$siteLang = $_COOKIE['lang'];
if (isset($_GET['lang'])){
if ($siteLang != $_GET['lang']){
$siteLang = $_GET['lang'];
setcookie('lang',$siteLang);
}
}
}
$modx->setOption('cultureKey', $siteLang);
$modx->getService('lexicon','modLexicon');
$modx->lexicon->load($siteLang.':art-revolver:default');
}В админке сайта у каждого ресурса появляются TV-поля: content-en, pagetitle-en, longtitle-en. Теперь все данные заполняются в одном ресурсе, довольно удобно. Для менеджеров-то точно. Минус – все-таки это TV, занимает время на выборку + английский сайт не индексируется поисковыми системами (но это не точно).На фронте замена всего происходит так.
Пункты меню, наименования опций, кнопки и прочая фиготень берут тексты из нужных записей словаря текущего языка:
<div class="col-md-10">
<span class="option-name">Fuji</span>
<p class="photo-description">[[!%art-revolver.fuji]]</p>
</div>Важно! Записи словаря должны вызываться некэшированными, иначе нифига не будет работать.Названия ресурсов и их страниц обрабатывают сниппеты getPagetitle и getContent:
<a href="[[+link]]" [[+attributes]]>[[!getPagetitle?&lang=`[[!%art-revolver.sitelang?&namespace=`art-revolver`]]`&id=`[[+id]]`]] </a>Код сниппета getPagetitle (для getContent тоже самое. Можно даже универсально сделать, но тогда как-то это в голову не пришло):<?php
if ((isset($lang)) && (isset($id)) ){
$page = $modx->getObject('modResource', $id);
if ($lang == 'ru'){
$pagetitle = $page->get('pagetitle');
} else if ($lang == 'en') {
$pagetitle = $page->getTVValue('longtitle-en');
if ($pagetitle == ''){
$pagetitle = $page->get('pagetitle');
}
} else {
$pagetitle = $page->get('pagetitle').' / '.$page->getTVValue('longtitle-en');
}
return $pagetitle;
} else {
return 'эта строка не может быть отображена';
}Вот таким, не очень хитрым способом я запилил мультиязычность на сайте. До сих пор считаю, что данная система имеет право на существование, но я бы очень хотел узнать методы улучшения, и очень интересно, как мультиязычность работает на MODX.pro. Система опций.
Бэкенд.
Толком кодить на JS я не умею, кастомизировать miniShop2 и админку MODX для меня задача непосильная. До сих пор боюсь. Решил продолжить делать все на MIGX, знатно расширив таблицу опций и сделав значения по-умолчанию, а если надо, то в карточке товара можно что-нибудь подправить. Расширил таблицу следующим образом – есть пять размеров фотографии – от обычной рамочной, до полотна на всю стену. Каждый размер имеет свои ценовые значения для каждой опции – бумага, рамка, тубус, стоимость печати. По идее, при выборе нужного чекбокса на фронтенде, JS-скрипт лезет через AJAX на сервер и тянет нужные цены для выбранного параметра, типа, вот так:
<?php
if ($_SERVER['HTTP_X_REQUESTED_WITH'] != 'XMLHttpRequest') {return;}
if (empty($_POST['action'])) {return;}
//На выходе всегда отдавались крокозябры, добавил header(), вроде помогло.
header('Content-Type: text/html; charset=utf-8');
$action = $_POST['action'];
$id = '';
$id = $_POST['id'];
//По полученным параметрам запускаем MIGX сниппет с параметром WHERE и тянем данные.
if ($product = $modx->getObject('msProduct', $id)) {
$output = $modx->runSnippet('getImageList',array(
'tvname' => 'photo_format',
'tpl' => 'photo_options-tpl',
'where' => '{"MIGX_id:=":"'.$action.'"}'
));
} else {
$output = '<h2>Невозможно загрузить страницу</h2>';
}
if (!empty($output)) {
die($output);
}Весь скрипт вырван из заметки Василия за 2013 год о работе AJAX, ибо тогда я реально мало что в этом понимал. Сейчас мои AJAX запросы выглядят прикольнее. Правда.Сама таблица опций MIGX выглядит так:
[{"MIGX_id":"1","name":"[[!%art-revolver.photo-standart]]","description":"[[!%art-revolver.photo-standart-decription]]","size":"30*45","price":"4800","epson":"0","fuji":"0","canvas":"1600","nodecor":"0","mont1":"1120","mont2":"1760","printCanvas":"0","mont3":"800"},
{"MIGX_id":"2","name":"[[!%art-revolver.photo-optimal]]","description":"[[!%art-revolver.limited-edition]] 500 [[!%art-revolver.copies]]","size":"40*60","price":"8000","epson":"0","fuji":"0","canvas":"2640","nodecor":"0","mont1":"1280","mont2":"2800","printCanvas":"0","mont3":"960"},
{"MIGX_id":"3","name":"[[!%art-revolver.photo-real]]","description":"[[!%art-revolver.limited-edition]] 300 [[!%art-revolver.copies]]","size":"60*90","price":"12800","epson":"0","fuji":"0","canvas":"4000","nodecor":"0","mont1":"2400","mont2":"0","printCanvas":"0","mont3":"2000"},
{"MIGX_id":"4","name":"[[!%art-revolver.photo-exclusive]]","description":"[[!%art-revolver.limited-edition]] 200 [[!%art-revolver.copies]]","size":"100*150","price":"28000","epson":"0","fuji":"0","canvas":"10800","nodecor":"0","mont1":"6320","mont2":"0","printCanvas":"0","mont3":"2400"},
{"MIGX_id":"5","name":"[[!%art-revolver.photo-super]]","description":"[[!%art-revolver.limited-edition]] 100 [[!%art-revolver.copies]]","size":"120*180","price":"80000","epson":"0","fuji":"0","canvas":"16000","nodecor":"0","mont1":"9200","mont2":"0","printCanvas":"0","mont3":"4000"}]Теги MODX используются для мультиязычности. Хитро. Хе-хе.Фронтенд.
Боль моей души. Мой ночной кошмар. Мое незнание JavaScript…
Когда я начинал учиться веб-разработке, то у меня было две книги по HTML 4 (дело было в 2009 году), написанные русскими авторами, и оба они советовали забить на JS, ибо Flash это революция и он всех порвет. С тех пор и до 2016 года я упорно забивал на изучение JS (а препод по JS в универе только усилил ненависть к JS) и юзал только jQuery. Удобно же.
Ошибка номер 4. Выучи JS. Научись делать все классами/методами/объектами, и перестань быдлокодить на уровне if/else.
Собственно, за систему опций мне стыдно больше всего на этом сайте. Те, кто осиливает сейчас этот текст, и до сих пор не забил, может зайти на сайт и поковырять там код в карточке товара. Обещаю – скучно не будет. Когда я это писал, я уже понимал, что это полное д***мо. Но иначе не умел. Да и сейчас, я едва-едва начал что-то понимать в классах и методах, благо немного освоил Node.js, он дал мне неплохое представление о хорошем JS коде. Да и изучение исходников JS кода miniShop2 тоже помогает.
Когда я закончил эту систему опций, если не ошибаюсь, в июле, Володя выкатил новый, обновленный релиз msOptionsPrice2.
Интересно узнать, умеет ли этот компонент все то, что заложено в ТЗ в этом топике?
upd. Изменение фото в зависимости от опций
При выборе параметров необходимо изменять превью и фото товаров на соответствующие опциями. Совать 32 возможных варианта в админку — нереально, плюс неизвестно, как это выводить. Поэтому решение получилось примерно таким:
Есть две подложки — для маленьких форматов и больших — на столе и за диваном.
Есть само изображение товара. Есть опции в виде рамок и их цветов.
Путем переключения radio кнопок с помощью HTML+CSS я накладываю одну картинку на другую и CSS рисую рамку. Чтобы CSS был более-менее адекватным, была сделана система префиксов параметров:
размер фона — ориентация фото — размер фото, то есть, в боевом режиме:
класс .sofa-vertical-real означает показать фотографию за диваном в вертикальной ориентации в большом размере
Далее. Личный кабинет.
Так как к этому времени Володя уже убрал из магазина UserProfile, то ничего не оставалось, как купить Office. Запросил бюджет на компонент от заказчика, настроил по мануалу. А дальше самое интересное. По-идее, на сайте должно быть две группы пользователей – авторы и покупатели. Авторы – выставляют товары, делают посты, имеют аватарки и личные странички. Покупатели – только покупают и смотрят в личном кабинете статус заказа. Оказалось, что НИКТО вообще не знает, как должен выглядеть кабинет покупателя и что там должно быть. Мало того, оказалось, что НИКТО до конца не знает, как должен выглядеть кабинет автора, и что там должно быть. Нет, на макете был нарисован кабинет автора – личная страничка, аватарка, текст о себе, ссылки в соц.сетях, выставленные работы. Но нет кнопок – добавить товар, редактировать товар, выйти из личного кабинета, еще-что нибудь. На мои плечи, помимо реализации двух разных кабинетов, еще ложится разработка логики работы авторов и покупателей, так как никто кроме меня вообще не в курсе того, что это нужно. Иначе вообще же смысла в кабинете нет.
Повторяю ошибку номер 1. Техническое задание. Полностью. Без него трудные проекты – не брать. Нельзя сделать хороший проект на одних разговорах. Нельзя. Нереально.
Итак, права пользователей и роутинг кабинетов. В админке создаем два контейнера ресурсов – пользователи и авторы. На всякий затер id страниц, мало ли что.

Далее создаем две группы пользователей – users и authors.
Роутинг осуществляется по заметке Василия, в плагине на событие OnPageNotFound, примерно так:
<?php
if ($modx->event->name != 'OnPageNotFound') {return false;}
$alias = $modx->context->getOption('request_param_alias', 'q');
if (!isset($_REQUEST[$alias])) {return false;}
$request = $_REQUEST[$alias];
$tmp = explode('/', $request);
// Ссылка подходит под заданный формат: user/username
if (($tmp[0] == 'user') || ($tmp[0]=='author')) {
// Теперь очищаем имя пользователя от возможного расширения
$name = str_replace('.html', '', $tmp[1]);
// Здесь будем определять, какую страницу надо показывать
// Дальше проверяем наличие запрошенного пользователя
if ($user = $modx->getObject('modUser', array('username' => $name))) {
if ($user->isMember('Authors')){
$tmp[0] = 'author';
if ($tmp[2] == 'comments'){
$section = __; // id ресурса для подстраницы «Комментарии»
}
} else {
if ($tmp[2] == 'comments'){
$section = __; // id ресурса для подстраницы «Комментарии»
}
}
if (!$section = $modx->findResource($tmp[0] . '/')) {
return false;
}
if ($tmp[1] != $name) {
$modx->sendRedirect($tmp[0] . '/' . $name . '/');
}
$modx->sendForward($section);
}
}Но тут появляется такая проблема. Дело в том, что переходить в личный кабинет автора могут как сами авторы, так и пользователи из группы Users, так и анонимы. А у автором же в кабинете загрузчик товаров (о нем позже), статистика продаж, манипуляции с товарами, редактирование информации, замена аватарок, фона кабинета. И авторы могут переходить в режим кабинета покупателя, так как по сути, имеют на это все право. Поэтому формируется задача – редиректить users и authors только на их шаблоны кабинетов + запрещать показывать непринадлежащие формы и чанки, но дать анонимам и юзерам смотреть страницы авторов. Решил я это таким вот сниппетом: <?php
$alias = $modx->context->getOption('request_param_alias', 'q');
if (!isset($_REQUEST[$alias])) {return 'пустой запрос';}
$request = $_REQUEST[$alias];
$tmp = explode('/', $request);
$tmp[0] = strtolower($tmp[0]);
// Ссылка подходит под заданный формат: user/username
if (($tmp[0] == 'user') || ($tmp[0] == 'author') || ($tmp[0] == 'authors')) {
$name = strtolower(str_replace('.html', '', $tmp[1]));
// Здесь будем определять, какую страницу надо показывать
// Дальше проверяем наличие запрошенного пользователя
if ($user = $modx->getObject('modUser', array('username' => $name))) {
//получаем пользователя в сессии
$current_user = $modx->getUser();
$current_user = strtolower($current_user->get('username'));
//если запрошенный пользователь состоит в группе пользователей дать обычный шаблон, иначе - шаблон автора
if ($user->isMember('Users')){
$tpl = 'cabinet-tpl';
} else {
$tpl = 'author-cabinet-tpl';
}
//если имена пользователей сходятся, то запустить Офис, то есть пустить в личный кабинет
if ($name == $current_user){
$output = $modx->runSnippet('officeProfile',array(
'tplProfile' => $tpl,
'avatarParams' => '{"w":150,"h":150,"zc":1,"bg":"ffffff","f":"jpg"}'
));
return $output;
} else {
//Иначе - отобразить страничку пользователя
$u_name = $user->get('username');
$u_profile = $user->Profile->toArray();
$user_prop = array('username' => $u_name, 'cabinet-menu' => 'off');
$u_profile = array_merge($u_profile,$user_prop);
$modx->setPlaceholders($u_profile);
$output = $modx->getChunk($tpl, $u_profile);
return $output;
}
} else if ( ($name == 'add') || ($name == 'comments') || ($name == 'add-socials') || ($name == 'history') || ($name == 'edit') || ($name == 'my-selling') ){
if ($user = $modx->getUser()){
if ($user->isMember('Users')){
$tpl = 'cabinet-tpl';
} else {
$tpl = 'author-cabinet-tpl';
}
$output = $modx->runSnippet('officeProfile',array(
'tplProfile' => $tpl,
'avatarParams' => '{"w":150,"h":150,"zc":1,"bg":"ffffff","f":"jpg"}'
));
return $output;
}
}
}Было бы интересно более элегантное решение, хотя бы в теории.Сам же шаблон страницы автора не так интересен. Картинка-фон к кабинету это адрес картинки, который хранится в extended поле юзера, его биография и ссылки на соц.сети – тоже extended. Как я реализовал загрузку кастомной картинки в кабинет пользователя – не помню. Не могу найти в исходниках (о бардаке в чанках и сниппетах — позже).
Внезапно оказывается, что заказчик хочет менять цвет текста-описания биографии. Естественно, учить HEX-кодам не вариант, HTML 5 поле color не все браузеры еще умеют, прилепил jQuery плагин, который показывает форму выбора цвета и сохраняет в extended поле HEX код. А при загрузке кабинета это прописывается прям в “style” атрибут тега с текстом. Костыль, но опять же. Задача внезапная, а увеличения бюджета тоже не планируется.
На следующий день заказчик хочет, чтобы во время редактирования текста биографии в textarea поле отображалась фоновая картинка, чтобы можно было менять цвет текста и сразу смотреть как это выглядит.

Ошибка номер 4. Никаких новых хотелок по ходу работы. Только после завершения оговоренных работ. Иначе разработка превратится в бесконечный цирк, где денег за доп.работу можно и не увидеть. Или увидеть не в полном объеме.
Загрузка товаров авторами
Это тоже задачка была не из простых, но к счастью, есть ms2Form. С горем-пополам настроил модуль, товары создаются. Правда, из-за того, что товары разные, и каждый тип имеет свои уникальные характеристики, пришлось сделать сначала выбор типа товара, потом AJAX’ом загружать сниппет и отдавать шаблон.

—

Во время настройки ms2Form произошел знатный прикол, который отнял у меня пару дней времени. Оказалось, что если один пользователь загружает фото товара к своему товару, но внезапно бросил это дело, и закрыл браузер, то если другой автор будет грузить свой товар и свои фото, то он будет видеть, что грузил другой автор. Но так как права на редактирования чужих товаров он не имеет, то и свой товар загрузить не может. Конфликт! Решилось ковырянием исходников ms2Form и раскомментированием последних строчек в сниппете ms2Form (да, нужные строчки были почему-то закомментированы).
В общем, с горем пополам, за две-три недели личные кабинеты пользователей двух групп и доступ к анонимам был реализован.
Переходим к самому прикольному – фотобанку
Идея реализовать полноценный фотобанк в стиле Fotolia на базе MODX, имея не самые хорошие знания платформы, как я уже говорил, с самого начала казалось мне плохой. Но, вызов принят. Арсенал костылей еще полон, полный вперед!
Итак, идея примерно такова.
Нужен раздел на сайте, продающий цифровые товары, то есть, ссылки на фотографии в различном разрешении. При этом, файлы нельзя скачать посторонним пользователям, доступ к ссылке имеют только купившие товар. В идеале, ссылка всегда должна хэшироваться и для каждого юзера быть уникальной. Фотографии хранятся в HD, и весят по 15-20 мегабайт. Хранить все это добро на shared-хостинге идиотизм. Но об этом, как всегда, никто не подумал. Поэтому я, вооружившись Swift, настроил облако Selectel и фотобанк хранится там. Хранение фотографий сначала реализовал с помощью FileAttach. Он даже ссылочки хэшировать умеет. Но, как оказалось, он работает только с локальным хранилищем, а с облаком не умеет. Ума допилить компонент у меня не хватило. Поэтому я обратил внимание на компонент от Володи – UserFiles. Подостовав Володю в тех.поддержке, я таки-настроил компонент и фотки загружаются в Selectel и хранятся там. Проблема только в том, что ссылки не хэшируются, и купивший фотографию человек, может спокойно расшарить ссылку всем. Но, думаю, до этого не дойдет.
Как же сделана выдача ссылок покупателю?
Подразумевается, что купить фотку в фотобанке можно только картой. Значит, у такого товара будет статус “ОПЛАЧЕН”. Выходит, задача такая – найти пользователя, который купил этот товар, проверить статус товара и вывести сниппет UserFiles со ссылкой на фотку. Создал сниппет getBuyingPhotos и поместил вызов сниппета на странице покупателя, сразу под стандартным кабинетом Office на ExtJs.
Код сниппета getBuyingPhotos:
<?php
$pdo = $modx->getService('pdoTools');
if (empty($tpl)){
$tpl = 'UFfileattach.tpl';
}
if (empty($tplOuter)){
$tplOuter = 'UFfileattachOuter.tpl';
}
//Если пользователь авторизован
if ($modx->user->isAuthenticated('web')) {
$current_user = $modx->getUser();
if (!isset($user_id)){
$user_id = $current_user->get('id');
}
//Создаем запрос
$query = $modx->newQuery('modResource');
//Проверяем необходимые параметры
$parent == '' ? $parent = __ : $parent;
$parent == '' ? $parent = __ : $template;
//условие
$query->where(array(
'parent' => $parent,
'template' => $template,
'ms2o.status' => $status,
'ms2o.user_id' => $user_id,
));
//Запрос с JOIN нужных таблиц
$query->select('modResource.id');
$query->leftJoin('msOrderProduct', 'ms2op', 'modResource.id=ms2op.product_id');
$query->leftJoin('msOrder', 'ms2o', 'ms2op.order_id=ms2o.id');
$query->prepare();
$query->stmt->execute();
$result = $query->stmt->fetchAll(PDO::FETCH_ASSOC);
foreach ($result as $res) {
$links .= $pdo->runSnippet('!pdoResources',array(
'parents' => __,
'limit' => 10,
'class' => 'UserFile',
'loadModels' => 'UserFiles',
'tpl' => $tpl,
'leftJoin' => '{
"Thumb": {
"class": "UserFile",
"on": "Thumb.parent = UserFile.id"
}
}',
'where' => '{"UserFile.parent":"'.$res['id'].'","UserFile.name:!=":"modelrelease"}',
'sortby' => 'rank',
'sortdir' => 'ASC',
'select'=>'{
"UserFile": "*",
"Thumb": "Thumb.url as thumb"
}'
));
}
// return $links;
if (!empty($links)){
$output = $pdo->getChunk($tplOuter,array('links'=>$links));
} else {
$output = '';
}
return $output;
} else {
$modx->sendUnauthorizedPage();
}Таким вот образом я запилил что-то типа фотобанка. От вариаций покупки в разных разрешениях пришлось отказаться, так как слишком запарно, даже сам заказчик, кажется, забил на эту идею.Бардак в коде
Проект делался (а точнее, делается) уже год.
За это время мои знания улучшались, но из-за спешки в реализации я не соблюдал никакой логики в хранении и именовании элементов, поэтому сейчас на сайте, чтобы понять, как что-то работает, нужно убить достаточно времени, ибо сразу отыскать все сниппеты и чанки задача не из легких.
Уже в сентябре я освоил Fenom и файловые элементы, когда большая часть была сделана, а переделывать такую махину было уже лень. Тем более, не забываем о оплате в пять умножить на шесть тысяч рублей. Тратить еще две недели на переписывание этого кошмара мне уже не моглось.
Ошибка номер 5. Следуй какой-то методике хранения элементов. Правильно называй чанки/сниппеты/плагины. Разложи все по папкам. По-хорошему – сделай все на файловых элементах Fenom, чтобы четко видеть местоложение всех элементов. Это реально удобно. Точнее, это нереально удобно.
Я уверен, что текущий разработчик, который занимается этим проектом, наверняка увидит этот пост, и может даже обратит на него внимание босса и заказчика. Возможно, я даже получу по шапке за эту публикацию. Но, я уверен, никаких договоренностей на этот счет нет ни у кого, а я вообще, как бы, не при делах. Да и код, по сути, мой. Почти что интеллектуальная собственность.
P.S. Я все же получил еще доплату за проект в размере два в четвертой степени минус одна тысяча рублей. Итого, за 8 месяцев работы гонорар по проекту вышел в два в шестой степени плюс одиннадцать тысяч рублей. Стоит ли проект этот суммы, несмотря на костыли? Как считаете?
P.S.2. За последние полгода я сделал достаточно проектов, за которые мне ни разу не стыдно. Все сделано реально круто. Везде Fenom, грамотное наследование шаблонов, неплохо (а местами очень хорошо) написанные сниппеты, хорошая верстка, TV в работе с miniShop2 почти не использую, только плагины товаров, вовсю использую словари и системные параметры, ну и вообще, за исключением внезапных приступов тупости (можно видеть в моих предыдущих топиках), считаю, что могу сказать, что делаю хорошие сайты. Но с Art-revolver судьба не сложилась.
Комментарии: 38
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
Ну а вообще да, изрядная картина создания сайта на MODX из говна и палок за еду. Очень интересно, чем думает веб-студия, когда берёт такие проекты без ТЗ, сроков и выставляет смешные ценники. Жадность ли это, или банальная глупость?
Есть мнение, что для сдачи такого проекта заказчику, студия потратит больше, чем заработает.
Всё же заказчик не виноват что менеджер проектов не опирается на опыт работников.
А так что я могу сказать, описаны советы от капитана:
Без ТЗ получаем ХЗ
Чувствуется вся боль.
Долгострой сам по себе морально сложен, а тут еще поддерживают стресс за счет «быстро-быстро, горим».
Со временем, наверное, все приходят к тому, что лучше отказаться от чего-то подобного и потратить время на семью, себя или что-то поинтереснее в профессиональном плане.
Тоже штук 5 подобных проектов (по сложности брал), все слил в свое время, зато получил опыта и знаний немерено.
2. Статья о том, как работать с файловыми элементами
Серьезно, после освоения этого инструмента делать сайты на MODX стало еще проще. И код стал куда красивее. Идиотские однообразные простыни шаблонов с одним отличием сменились на шаблоны с наследованием, все чанки и собственноручно написанные сниппеты/модификаторы хранятся в файлах, их можно использовать с Git, а это вообще просто потрясающе! Теперь никаких утерянных чанков, все всегда можно откатить и радоваться жизни. Прелесть. Если до сих пор никогда не использовали Fenom — потратьте пару дней и познайте дзен реально крутой разработки.
Хотя, как я понял, проблема со скоростью и памятью если и может проявиться, то только при первой загрузке, дальше все попадает в кеш и работает также, как и в базовом подходе MODx.
Подход действительно великолепный, жаль, что MODx изначально не по этому пути шел.
Могут ли параллельно уживаться Fenom и обычный подход?
Не знаете, не планируется ли Modx на Fenom перевести?
Тем более тебя интересовал Git
А это уже к феному никакого отношения не имеет. ))
Перевел на феном и файловые элементы уже не один свой сайт — полет нормальный. Просто по самой статье «Art-revolver или как не стоит делать сайты» предложит автору писать как эти сайты делать надо, применяя феном и т.п. со всеми тонкостями.
Мне казалось именно это могло быть понятно из мой реплики автору топика.
А закончилось так
))
П.С. В спорах рождается истина.
Что касается моих рук, можете оценить в приложении.
yadi.sk/d/ulmHBl1F3GgTCj
Про цены ничего не понял. Для чего было писать эти ребусы со степенями… Лучшеб сразу написал суммы цифрами. И так текст длинный.