Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 6643 сообщений
Cообщения с меткой

php - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

Как создать свой VPS-хостинг с нуля и начать на нем зарабатывать? Простой биллинг с WooCommerce

Четверг, 23 Июня 2016 г. 14:43 (ссылка)





Здравствуйте, уважаемые читатели хабра. Данная статья является продолжением цикла материалов о том, как построить VPS-хостинг с нуля на базе RUVDS White Label API. В вводной статье цикла мы говорили о том, что в первую очередь нам понадобится сайт и предложили 3 варианта, как его можно создать. Мы детально остановимся на варианте с использованием популярных CMS и плагинов к ним, которые призваны быстро предоставить так необходимую нам функциональность по приему платежей и оплате серверов.



В серии публикаций мы рассмотрим такие популярные CMS, как Wordpress, Joomla и Drupal.



Почему мы выбрали именно их:


  • Поддерживаются почти всеми популярными shared-хостингами

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

  • Бесплатны (для старта с минимальными вложениями это важно)

  • Распространены в интернете





Disclaimer: Мы не утверждаем, что эти CMS самые популярные или самые лучшие. Также мы не говорим о том, что PHP язык номер один и вы просто обязаны использовать только его. Вы можете использовать любые технологии, которые подойдут для решения задачи по созданию своего VPS-хостинга. В данный материал добавлено множество ссылок на сторонние источники, содержимое которых мы не стали включать в его текст, иначе он бы был менее читабельным и цельным. Надеемся вы сочтете их полезными. Итак, приступим.



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



Этот плагин по праву считается одним из самых мощных и функциональных бесплатных eCommerce-решений для Wordpress. Вместе с ним идёт специализированная тема Storefront, полностью поддерживающая последний функционал плагина что называется «из коробки». Можно либо воспользоваться данной темой с незначительными доработками дизайна, либо приобрести платную за 50-70$ например тут. Что сразу бросается в глаза — так это наличие множества расширений, в том числе для интеграции со всевозможными платёжными агрегаторами, например robokassa или paymaster (оба бесплатны).



Плюсы






  • Легкость установки. В пошаговом процессе установки всё интуитивно понятно. Загружаем плагин и тему, активируем. Далее сразу можно добавлять товары и переходить к более тонкой настройке.

  • Наличие огромного количества платных и бесплатных шаблонов

  • Простое и удобное добавление товаров

  • Расширяемость. Кроме коробочной функциональности существует множество расширений плагина, что позволяет получить желаемую функциональность

  • Бесплатность. Без лишних слов

  • Постоянные доработки и обновления. Плагин активно дорабатывается, последний коммит в репозиторий на github был несколько дней назад (на момент написания статьи).

  • Функциональность по построению различных отчетов

  • Купоны, промоакции из коробки

  • SEO. Для товаров доступна настройка чпу, карты сайта, метатегов (также как и для простых страниц)

  • Наличие мультиязычного расширения





Минусы




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

  • Возможны конфликты при установке некоторых расширений вместе

  • Отсутствует бесплатная техническая поддержка

  • Безопасность. Учитываю популярность CMS wordpress в мире и популярность самого расширения, магазины на этом движке часто становятся целью атаки хакеров





Особенности адаптации под vps-хостинг



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



Приём платежей



Здесь всё абсолютно также, как и при организации приёма платежей для любых других товаров. Плагинов, реализовывающих интеграцию с аггрегаторами для woocommerce достаточно много. Если выбирать из бесплатных расширений woocommerce для приема платежей России и СНГ, можно подключить robokassa или paymaster. В случае с robokassa, сразу после регистрации на сайте вы сразу можете принимать платежи как физическое лицо на основании договора оферты, однако в этом случае имеем высокую комиссию. В целом, даже с учетом этого, конечная цена вашего сервера всё равно будет достаточно привлекательной по отношению к конкурентам, поэтому можно смело начинать работать сразу с robokassa. Детальную информацию по настройкам расширения robokassa можно получить тут

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



Отключение механизма гостевых покупок и доставки



В WooCommerce есть возможность совершать покупки без регистрации. Нам же нужно, чтобы клиент мог осуществлять покупки только из своего аккаунта, в котором, к слову, мы будем отображать клиенту всю необходимую информацию, в том числе о его серверах. Для этого переходим в Настройки Wordpress > WooCommerce > Настройки > Платежи и снимаем галочку «Разрешить гостям оформлять заказы».



Доставку также необходимо отключить. Для этого переходим в Настройки Wordpress > WooCommerce > Настройки > Основные и выбираем «Отключить доставку и расчет доставки»



Настройка страниц



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

Переходим в Настройки Wordpress > настройки > Чтение и указываем в качестве главной страницы и страницы записей станицу с витриной товаров WooCommerce.



Добавление товаров



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


  • Минимальная: 1x2.6ГГц CPU, 1Гб RAM, 20Гб HDD, 1 IP

  • Средняя: 4x2.6ГГц CPU, 4Гб RAM, 40Гб HDD, 1 IP

  • Мощная: 10x2.6ГГц CPU, 10Гб RAM, 80Гб HDD, 1 IP





В меню добавления товара мы рекомендуем сразу заменить содержимое поля Ярлык на более понятный вариант, например medium-configuration. Также, в содержимом товара желательно описать для каких целей подойдёт данная конфигурация, например для размещения свое сайта на с посещаемостью до 100 человек в день. Не забываем указать цену и скидку, если это требуется. Также, обязательно укажите изображение товара.

В результате должно получиться вроде этого:







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



Обработка оплаченных заказов



Вот мы и подошли к одному из самых важных пунктов в вопросе адаптации WooCommerce под продажу услуг аренды VPS. После оплаты VPS-сервера на вашем сервисе вы должны клиенту этот сервер предоставить.



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


  • инициировать создание сервера с помощью RuVDS Whitelabel API и предоставить клиенту все необходимые данные о процессе создания (идентификатор сервера, этап создания, прогресс создания, конфигурация сервера)

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



Для решения данной задачи существует множество способов. Один из наиболее простых — это периодически получать данные об оплаченных заказах, по которым не были созданы VPS напрямую из соответствующих таблиц wordpress и woocommerce (детальное описание схемы woocommerce вы найдете тут) и если такие существуют, помечать их как «в процессе исполнения» и запускать процесс создания сервера. Не самое лучшее решение, но одно из самых простых… Также для этой задачи можно использовать веб-хуки woocommerce. Что такое веб-хуки? Говоря простыми словами, это подписка на событие в интернет магазине. Покажем, как работать с этим механизмом по REST API.



Чем хорош woocommerce? Не в последнюю очередь тем, что у него есть документированное REST API (и примеры его использования на 4-ти языках, Javascript, PHP, Python, Ruby и на curl, вывод которого можно потом разобрать как вам нравится). Также, для использования возможностей плагина есть wp cli и подробнейшая документация по его коду.



Для того, чтобы воспользоваться REST API необходимо предварительно сгенерировать специальный ключ. Делается это следующим образом: переходим в WooCommerce > Настройки > API и жмем добавить ключ. При генерации ключа требуется выбрать пользователя и указать тип прав (чтение, запись, чтение/запись). Генерируем ключ для текущего пользователя и указываем уровень прав чтение/запись. Далее переходим в Настройки > постоянные ссылки и выбираем второй тип. Теперь REST API доступно по url: yourdomain.com/wc-api/v3



Для работы с API, воспользуемся специальной библиотекой для PHP. Установим её с помощью composer, выполнив в консоли:

composer require automattic/woocommerce


Авторизоваться в API и получить список товаров можно, используя следующий PHP-код:

https://habrahabr.ru/post/303936/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Из песочницы] Работа с OZON (Merchants) API средствами PHP

Четверг, 23 Июня 2016 г. 13:47 (ссылка)

Работаем над большим интернет-магазином. И вот возникла необходимость из УТ (1С Управление торговлей) управлять заказами на O Ozon.



Смысл такой: есть БД PostgreSQL, 1C'ка работает с этой базой, вносит данные о поступивших заказах, меняет статусы заказов. И есть также скрипт PHP, который лежит на сервере и выполняется по крону каждые 3 минуты. Что этот скрипт должен делать?




  • 1. Получать токен от API ozon;

  • 2. Забирать все новые заказы с Ozon. Создавать новый XML файл с полученными заказами;

  • 3. Получать из БД заказы с определённым статусом. Изменять статус этих заказов на Ozon. Изменять статус этих заказов в БД;

  • 4. Закрывать заказы с определённым статусом на Ozon. Изменять статус этих заказов в БД.



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



// Получим токен /auth/token/merchants?applicationid=[ApplicationId] (ApplicationId )
// $sign - рассчитанная SHA1-HMAC подпись, где ключом будет секретный ключ приложения, а значением на подпись - path-часть URL
// Ответ json, например { "token": "9895DDA48379484ABC51A4B193CDAE04", "expiration": 600 }
$sign = hash_hmac('sha1','/auth/token/merchants?applicationid=albion','[секретный ключ приложения]');
$token = file_get_contents('https://api.ozon.ru/auth/token/merchants?applicationid=[ApplicationId]&sign='.$sign);
$token = substr($token,10,32);


Далее возникли проблемы. Вместе с запросом нужно было передавать заголовки. API документировано довольно плохо, примеры кода отсутствуют, в Гугле не нашёл ни одного примера. Пришлось работать методом проб и ошибок. Попробовал сначала действовать таким же образом через file_get_contents() — безрезультатно. Что бы я ни делал — выводилась ошибка, что невозможно создать канал.



В итоге воспользовался curl. Код получения списка новых созданных заказов (в json и в xml):



// Получаем список новых заказов в json
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://api.ozon.ru/merchants/orders?StateName=Создан');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
"x-ApplicationId: [ApplicationId]",
"x-Token: ".$token,
"x-ApiVersion: 0.1"
));
$out = curl_exec($curl);
curl_close($curl);

// Получаем список новых заказов в xml
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://api.ozon.ru/merchants/orders?StateName=Создан');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
"accept: application/xml",
"content-type: application/xml",
"x-ApplicationId: [ApplicationId]",
"x-Token: ".$token,
"x-ApiVersion: 0.1"
));
$out1 = curl_exec($curl);
curl_close($curl);


Моменты, связанные с созданием xml файла и изменениями в БД postgreSQL описывать тут не буду, ибо это уже будет отступлением от темы.



Далее нужно было изменить статус заказа. Для этого кроме всего прочего в теле PUT-запроса нужно было передать новый статус (как выяснилось путём долгих изысканий — в виде XML).



Смена статусов заказов выглядит следующим образом:



// Для каждого заказа меняем его статус
foreach($ids as $item)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://api.ozon.ru/merchants/orders/state/'.$item);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, "ClientOrderStateMerchantAccepted");
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
"accept: application/xml",
"content-type: application/xml",
"x-ApplicationId: [ApplicationId]",
"x-Token: ".$token,
"x-ApiVersion: 0.1"
));
$out = curl_exec($curl);
curl_close($curl);
}


Для различных статусов нужно использовать разные XML данные. Приведу список всех доступных статусов:






Создан
ClientOrderStateMerchantCreated


Ожидает оплаты
ClientOrderStateMerchantAwaitingPayment


Оплачен
ClientOrderStateMerchantPaymentDone


Принят продавцом
ClientOrderStateMerchantAccepted


Отправлен
ClientOrderStateMerchantSent


Выполнен
ClientOrderStateMerchantDone


Аннулирован
ClientOrderStateMerchantCanceled





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



Приведу пример (указанная причина: «Число заказов больше, чем есть в наличии»):



		// Меняем статус на озоне		
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'https://api.ozon.ru/merchants/orders/state/'.$order_number);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, "ClientOrderStateMerchantCanceledOrderCountMoreThanRest");
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
"accept: application/xml",
"content-type: application/xml",
"x-ApplicationId: [ApplicationId]",
"x-Token: ".$token,
"x-ApiVersion: 0.1"
));
$out = curl_exec($curl);
curl_close($curl);


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



Надеюсь, моя статья будет кому-то полезной. Всем спасибо за внимание!



Кое-какая документация
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/303938/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Отчёт с Symfony Moscow Meetup 2 июня

Среда, 22 Июня 2016 г. 16:55 (ссылка)

image



В начале июня в офисе Mail.Ru Group прошла восьмая встреча сообщества Symfony Moscow Meetup — разработчиков на PHP/Symfony2. Здесь обсуждались вопросы разработки веб-приложений и смежные технологии, участники обменивались опытом и последними техническими новостями. Ну и, конечно, было много общения в неформальной обстановке. На встрече было представлено 4 доклада. Предлагаем ознакомиться с записями и презентациями выступлений.



Александр Лисаченко, Alpari



«Решение вопросов сквозной функциональности в приложениях»



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







Видеозапись выступления: it.mail.ru/video/715



Aлексей Медведев, Alpari



«Enterprise-инфраструктура менеджмента PHP-пакетов в рамках компании»



В докладе было рассказано, как в Альпари разворачивали локальную систему менеджмента пакетов на базе Composer, Packagist и git-фронтенда Gitweb; а также как работают с приватными пакетами и почему при сборке приложений зависимости никогда не выкачиваются напрямую с GitHub.



Кроме того, будет несколько слов о том, что находится под капотом у Packagist, когда, как и зачем его разворачивать у себя в компании, какие есть альтернативные Composer-репозитории пакетов и в каких случаях их удобно использовать.







Видеозапись выступления: it.mail.ru/video/716



Максим AloneCoder Попов, Mail.Ru Group



«Асинхронные запросы в MySQL или когда PDO становится мало»



В докладе было рассмотрено, зачем нужны и в чем преимущества асинхронных выборок из MySQL, а также как мы используем MySQLi и PDO вместе.







Видеозапись выступления: it.mail.ru/video/717



Руслан Ханов



«Контейнер сервисов — Что? Где? Когда?»



В докладе были рассмотрены типичные примеры и антипаттерны того, что обычно помещают в контейнеры, зачем это делают и каким образом.







Видеозапись выступления: it.mail.ru/video/716
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/303868/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Различия в реализации функций min() и max() на уровне исходника в PHP

Вторник, 21 Июня 2016 г. 13:59 (ссылка)

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



php > echo min(1,2,3,4,5,6,7,-1);
-1

php > echo min([1,5,3]);
1





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



php > echo min([-1,2],[1,5,3]);
PHP Notice: Array to string conversion in php shell code on line 1
PHP Stack trace:
PHP 1. {main}() php shell code:0

Notice: Array to string conversion in php shell code on line 1

Call Stack:
659.0962 352688 1. {main}() php shell code:0

Array




Для случая, если передаются строки, то происходит поиск минимального или максимального символа согласно следованию порядка в алфавите.



php > echo min("1","2");
1
php > echo min("a","b");
a
php > echo min("a","b", "c");
a
php > echo max("a","b", "c");
c
php > echo max("ab","ba", "cd");
cd




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



Приведу для наглядности исходники кода, удалив из тела функций различного рода проверки.



Файл: ext/standard/array.c




Функция поиска минимального значения.



PHP_FUNCTION(min)
{
int argc;
zval *args = NULL;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
return;
}

//….

if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 0)) != NULL) {
//….
}
//….
}





Функция поиска максимального значения.



PHP_FUNCTION(min)
{
int argc;
zval *args = NULL;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
return;
}

//….

if ((result = zend_hash_minmax(Z_ARRVAL(args[0]), php_array_data_compare, 1)) != NULL) {
//….
}
//….
}




То есть, если присмотреться, то отличается всего лишь последний аргумент в функции zend_hash_minmax():

1 — возвращает максимальное значение, 0 — возвращает минимальное значение.



Перейдем в тело функции zend_hash_minmax(), также удалив код который в данный момент не требует внимания.



Файл: Zend/zend_hash.c




ZEND_API zval* ZEND_FASTCALL zend_hash_minmax(const HashTable *ht, compare_func_t compar, uint32_t flag)
{
//….
for (; idx < ht->nNumUsed; idx++) {
p = ht->arData + idx;
if (UNEXPECTED(Z_TYPE(p->val) == IS_UNDEF)) continue;

if (flag) {
if (compar(res, p) < 0) { /* max */
res = p;
}
} else {
if (compar(res, p) > 0) { /* min */
res = p;
}
}
}
return &res->val;
}




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



PHP_FUNCTION(ms_maximal)
{
int argc = ZEND_NUM_ARGS();
double maximal = ZEND_LONG_MIN, cur_value = 0;
zval *array,
*value;

if (zend_parse_parameters(argc, "a", &array) == FAILURE) {
RETURN_DOUBLE(maximal);
}

ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), value) {
cur_value = zval_get_double (value);
if(cur_value > maximal) {
maximal = cur_value;
}
} ZEND_HASH_FOREACH_END();

RETURN_DOUBLE(maximal);
}




Возможно, функция zend_hash_minmax() довольно долго отрабатывает при передаче “гигантского” списка элементов в массиве. Интересно, в этом случае наверное, было бы оптимальней предварительно отсортировать массив наиболее подходящим алгоритмом сортировки (в зависимости от объема элементов), а затем брать крайние значения.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/303758/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Как мы написали helpdesk (часть 3)

Вторник, 21 Июня 2016 г. 11:25 (ссылка)





В продолжении части 2 и части 1, мы решили написать ещё одну статью, в которой хотим детально рассказать, что произошло за 2 года работы над проектом, чего мы добились, что нового реализовали, почему вообще системы заявок настолько перспективное направление. И конечно номер статьи (3) соответствует номеру версии продукта, о которой ниже пойдёт речь.







Как собрать снова команду и написать систему с нуля?
Мы поняли, что дальнейшее развитии проекта и его разработка на текущей архитектуре тянет за собой большие затраты на трудовой ресурс и производительность системы. Слишком много было «велосипеда» в нашем коде, который был «самокатом» в прямом смысле этого слова. С него было трудно упасть, так как колёса маленькие, но большой скорости развить мы не смогли уже. А ехать хотелось далеко и быстро :)

Поэтому выбор встал в сторону PHP framework, который бы по большей своей части обладал следующими критериями:

— Простота и понимание принципов работы за счёт хорошей документации и нашей идеологии

— Быстрое вхождение в разработку

— Наличие необходимых инструментов и библиотек для интеграции с необходимыми нам сервисами

— Перспективы поддержки фреймворка

— Повышение квалификации наших разработчиков

— Единый стандарт поддержки и развития системы

Так, мы поставили себе цель и добились её. За 8 месяцев был написан с нуля, используя переработанную и адаптированную бизнес модель предыдущей версии системы, целый проект.



Почему мы развиваем именно систему заявок?
Вы даже не представляете себе, насколько широко применение систем заявок. В теории, в организации где есть постановка задач и отслеживание их выполнения, самый примитивный вид документооборота — это и есть система заявок. Её могут использовать от пиццерий (курьерская доставка и заказы) и до конечно же IT-департаментов, которые оказывают поддержку пользователям. Именно на них мы и нацелены в первую очередь.

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



Почему мы решили использовать Laravel?
Во-первых, это новый фреймворк, но довольно популярный, красивый и в нём из коробки доступны реализации тех механизмов, которые нам необходимо использовать в нашей системе. Во-вторых, мы хотели расширять нашу команду, а использовать узкий свой собственный фреймворк, который нигде больше, кроме нас не используется — не позволяла совесть перед нашими разработчиками. Заодно мы «убили двух зайцев» — получили общую стандартизированную систему в рамках которой всё работает и добавили +1 фреймворк в skills опыта наших коллег.



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



Как много пользователей интересуется подобными системами?
Настолько много, что в любой адекватной офисной структурной организации есть необходимость вести учёт задач и сроков их исполнения. Тут уже либо выбирают PM-продукты, либо системы заявок, либо ToDo-блокноты, ну или в идеале CRM-системы. В этом плане ZENLIX — не является универсальным средством, но его новая версия старается максимально легко быть интегрирована в среду предприятия, благодаря различным общим сущностям. Например, слово группа заменяется, компанией либо проектом и тогда задача/заявка уже создаётся на проект.



Разработка и поддержка



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



Deploy & Test
Благодаря Envoy, мы имеем прекрасную возможность быстро развернуть/обновить существующую среду разработки для тестирования, к примеру API разработчику iOS-мобильного приложения.



Процесс разработки
Всё начинается с клиента. Наша команда делится на 2 группы — одна занимается развитием текущей ветки, другая — разработкой узких решений системы заявок. Часто эти границы стираются, ведь есть некоторые задачи, которые пересекаются и мы реализуем их быстрее, чем это оговорено. 65% всех идей реализации поступают от наших постоянных клиентов, от которых мы анализируем их запросы и представляем в виде плана развития проекта. Остальная часть — поступает от руководителя проекта, который чаще руководствуется своими анализаторскими способностями рынка систем заявок. Благодаря такой формуле — мы достигаем успех и признание наших клиентов. Сам процесс разработки — не является основной работой, ведь кроме него есть ещё — техническая поддержка.



Поддержка пользователей
Наши клиенты получают бесплатную поддержку по почте «в течении одного рабочего дня», на практике же этот показатель достигает «в течении часа». Мы очень стремимся, что бы этот показатель был максимально высокий. Это обусловлено тем, что для нас Важно понимать наших пользователей и получать в первую очередь от них информацию, что бы двигаться дальше. Удалённая поддержка осуществляется нашим техническим персоналом только по SSH, предварительно клиенты принимают небольшое пользовательское соглашение.



Что нового мы реализовали?

В новой версии мы пересмотрели подходы к организации пользователей/групп, системе уведомлений, общих разделениях структурных единиц. Теперь администратор может создать неограниченное число групп (например в соответсвии компаниям-клиентов и отделов организации, которые оказывают поддержку данным группам). Кроме того, каждой группе можно назначить своих главных пользователей, которые будут видеть в группе все заявки. Для создания заявок — ещё более гибкий подход. Мы создали систему форм заявок, благодаря которой, каждой группе или пользователю можно назначить уникальную форму создания заявок.





Формы создания заявок
Это та возможность, которая реализовалась именно из запросов наших пользователей. Это прекрасный пример, когда одним пользователям важно было поле «крайний срок» на странице создания заявок, а другим — «статус» и так далее. Мы решили всех удовлетворить и сделать механизм форм создания заявок. Теперь более чем из 20-ти пунктов настраивается форма создания заявок. Кроме того, форму можно подключить как на пользователя, так и на группу пользователей. Данный функционал дополнительно даёт возможность управления правами доступа на создание заявок группам/пользователям.



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



NodeJS+REDIS




В ранней версии (v.2) в качестве системы опроса новых событий мы использовали ежесекундное обращение к таблице БД. В новой версии, мы убрали эту связку и решили использовать REDIS. Теперь наш nodejs сервер подписан на redis и это даёт дополнительную стабильность и скорость в работе всплывающих уведомлений.





Полноценный QUEUE




Аналогично, в ранней версии мы использовали наш собственный механизм обработки очереди сообщений. Раз в минуту cron запускал систему обработки очереди сообщений и производил обработку их. Такой механизм подходил только под почтовую рассылку и расширять его под pushbullet, iOS-push, SMS — было не совсем правильным. В новой версии мы использовали Laravel Queues, который полноценно справляется с этими задачами и даёт дополнительно запас на дальнейшую интеграцию с внешними сервисами.



Индивидуальное выполнение заявки и принятие заявки после её выполнения




Дополнительные статусы заявок в новой версии:

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

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

Во всех случаях будет работать нотификация: на почту, sms, pushbullet, webpush, ios-push. (в зависимости от личных настроек пользователя)



Безопасность системы




Это одно из немаловажных мест, в системе, которое должно максимально сокращать расстояние между Удобством и Безопасностью. Много стало возможным благодаря встроенной системе учётных записей Laravel. Но мы её доработали, для одновременного использования с LDAP. Мы использовали полноценно механизмы middleware для полного контроля доступа к методам и ресурсам системы.



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

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



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

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



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



Новая версия мобильного приложения


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

В старой версии — необходим постоянный доступ к интернет.



Одним из преимуществ использование приложения, является использование PUSH-уведомлений.





Общий список поддерживаемых возможностей новой версии




  • SLA-планы заявок

    Учёт заявок по времени реакции на заявку, времени работы с заявкой, крайнего срока заявки


  • Редактирование/удаление/объединение/печать заявок

    Возможность производить действия с заявкой


  • Журналирование действия с заявками

    Отображение всех действий с заявками


  • Уведомления по заявкам по действиям:

    — Создание заявки

    — Взятие в работу заявки

    — Снятие с обработки заявки

    — Переадресация заявки

    — Комментирование заявки

    — Выполнение заявки

    — Ожидание проверки выполнения заявки

    — Успешное/не успешное подтверждение выполнения заявки

    — Удаление заявки

    — Восстановление заявки

    — Напоминание об окончании срока выполнения заявки (крайник срок)

    — Напоминание о просроченной заявке


  • Уведомления через сервисы

    — Уведомления в веб-браузер (по аналогии с VK.com), приходят по всем вышеописанным действиям, а так же выводится в правом верхнем углу веб-интерфейса в панель уведомлений, в которой хранятся все действия.

    — Уведомления на email

    — Уведомления на SMS (в профиле пользователя должен быть указано номер мобильного и сервис должен быть активен) основано на SMSC.ru. Для использования сервиса SMS, необходимо зарегистрироваться на сайте SMSc.ru, пополнить баланс и в системе ZENLIX ввести данные для (логин/пароль) для работы с SMSC.

    — iOS-push приходят так же автоматически, если пользователь установил мобильное приложение и авторизировался.

    — PUSHBULLET-позволяет бесплатно получать уведомления на различные ОС, платформы и мобильные устройства. Для этого, необходимо зарегистрироваться на сайте pushbullet.com, и получить API-ключ, который необходимо ввести в настройках ZENLIX.


  • Сообщения и комментарии в заявках

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


  • Создание заявки через email

    Возможность настраиваемо создавать заявки через входящие email.


  • Дополнительные поля заявки

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


  • Интеграция с Active Directory

    LDAP — авторизация и мастер импорта учётных записей

  • Многоуровневая система прав

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

  • Центр знаний

    Позволяет хранить обучающий материал в системе заявок


  • Система сообщений

    Даёт возможность обмениваться личными сообщениями между пользователями системы

  • Календарь

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

  • Чат

    Для быстрого обмен сообщениями (на равных условиях), а так же для поддержки клиентов (запрос-ответ, закрытие-открытие чата)


  • Инсталляция и обновление

    Удобные встроенные инструменты веб-инсталляции приложения и обновления системы


  • iOS-мобильный клиент

    С поддержкой PUSH-уведомлений и offline-хранением заявок.

  • Отчёты

    Система генерации отчёты как конкретных пользователей, так и целых групп.

  • API

    На котором работает мобильное приложение и поддерживает другие методы.

  • Другие функции, которые лучше увидеть :)





PS.

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

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



А для тех, кого заинтересовал проект — прошу писать на info@zenlix.com и мы будем рады любому сотрудничеству.
Original source: habrahabr.ru.

https://habrahabr.ru/post/303484/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Макросы Zend обхода циклов (HashTable Iteration)

Понедельник, 20 Июня 2016 г. 15:09 (ссылка)

Продолжая своё поверхностное изучение исходников PHP (7.0.7) и написания простейшего расширения к нему, хотел бы в этот раз немного углубится и описать приемы обхода массива через принятый аргумент функции, с которыми я познакомился при реализации простой PHP функции median(). Задача этой функции проста — вернуть средне-арифметическое значение. Возможна данная публикация будет полезной другим разработчикам PHP, таким же как и я, которые решили в свободное время немного изучить архитектуру любимого языка, на котором зарабатывают деньги. В предыдущей публикации я на “скорую руку” описал прием быстрого создания расширения в PHP с реализаций функции расчета факториала. Она проста в той степени, что принимает простой параметр целого типа и затем рекурсивно вызывается. Реализация функции median() усложнена тем, что принимаемый параметр — массив, по нему нужно пройтись, для суммирования общего значения, а также просчитать общее число элементов в массиве.



В данный момент я упростил задачу еще и тем, что заведо считаю, что все принятые элементы массива — числа. Исходники расширений PHP удивительны тем, что здесь “все пишется” через использование макросов. По крайней мере создается такое первоначальное мнение. Оказывается, для прохода по списку элементов в массиве тоже используются макросы. Для наглядности приведу сразу код функции с последующим небольшим описанием.



Функция описана все в том же файле — mathstat.c расширения mathstat. Ссылка на github.



Занесение в список функций расширения mathstat:



const zend_function_entry mathstat_functions[] = {
PHP_FE(confirm_mathstat_compiled, NULL) /* For testing, remove later. */
PHP_FE(ms_factorial, arginfo_ms_factorial)
PHP_FE(ms_median, NULL)
PHP_FE_END /* Must be the last line in mathstat_functions[] */
};




Само определение тела функции:



PHP_FUNCTION(ms_median)
{
int argc = ZEND_NUM_ARGS();
double total = 0;
int count = 0;
zval *array,
*value;

if (zend_parse_parameters(argc, "a", &array) == FAILURE) {
RETURN_DOUBLE(0);
}

ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(array), value) {
total = total + zval_get_double (value);
count += 1;
} ZEND_HASH_FOREACH_END();

if (count == 0 || total == 0) {
RETURN_DOUBLE(0);
}

RETURN_DOUBLE(total/count);
}




Если смотреть тело функции, то как и в прошлый раз, вызывается функция проверки параметра, где в качестве шаблона принимаемого типа аргумента задаем значение “a” (array)



   if (zend_parse_parameters(argc, "a", &array) == FAILURE) {
RETURN_DOUBLE(number);
}




Теперь самое интересное, проход по циклу реализован через макрос ZEND_HASH_FOREACH_VAL. Всего макросов которые проходят по массиву я нашел в справочках 7 штук. При этом, везде используется вместо массива термин HashTable. Для нашего случая я выбрал самый простой макрос. Первым аргументом он получает сам принятый массив через функцию, а вторым zval (базовая структура данных, которая хранить себе значение и тип данных — видео по этой части Дмитрия Стогова). В данном случае, я просто вызываю функцию zval_get_double, которая грубо говоря, мне и возвращает самое значение из массива. Если переписать это на обычный код PHP, то получится:



  1 




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



ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val)




то без кода уже понятно, что это аналог php цикла:



foreach($array as $key => $value) {
}




Для наглядности приведу из справочника все макросы:



ZEND_HASH_FOREACH_VAL(ht, val)
ZEND_HASH_FOREACH_KEY(ht, h, key)
ZEND_HASH_FOREACH_PTR(ht, ptr)
ZEND_HASH_FOREACH_NUM_KEY(ht, h)
ZEND_HASH_FOREACH_STR_KEY(ht, key)
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val)
ZEND_HASH_FOREACH_KEY_VAL(ht, h, key, val)




На этом все. Спасибо за отнятое время и потерянные деньги на мобильном трафике.
Original source: habrahabr.ru.

https://habrahabr.ru/post/303678/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Пишем расширение под PHP (7.0.7) без знаний о С/C++ и как это вообще работает

Суббота, 18 Июня 2016 г. 19:06 (ссылка)

Можно ли написать свой модуль (расширение) к PHP без особых знаний, требующих большого времени изучения теории? Если умеешь программировать на самом PHP, то написать простейший код на С не составит особого труда, тем более, что PHP позволяет генерировать каркас под разрабатываемое расширение, в рамках которого потом пишешь код. Есть еще набирающий популярность зефир на хабре для этого вопроса. Данная публикация для тех, кто решил покопаться в исходниках PHP, немного посмотреть его внутренности, преследуя цель лишь поверхностного исследования. В данный момент я тот же самый исследовать без необходимых знаний. На собеседованиях по PHP часто просят написать код подсчета факториала. Вот такую функцию мы и напишем сейчас на С, которую потом можно вызывать из кода PHP. Я буду описывать действия, которые я сам делал и при этом ничего не знаю изначально по этой части. В интернете можно найти много статей по этому вопросу, большинство из них описывает информацию с использованием zval «старого» формата, но я не думаю, что будет хуже если и я еще добавлю от себя.



В PHP есть уже готовый инструмент ./ext_skel (находится в папке ext), который генерирует будущий шаблон (каркас) для расширения. Я не буду описывать все, что им генерируется и зачем (сам особо в этом ничего еще не понимаю и не знаю), а просто распишу минимальные правки, которую решат нашу задачу. Весь процесс происходит в CentOS 7.



Создаем каркас для будущего расширения mathstat, которое будет содержать функцию factorial().



 [root@localhost ext]# ./ext_skel --extname=mathstat 

Смотрим, что содержится в папке mathstat.

[root@localhost mathstat]# ls
config.m4 config.w32 CREDITS EXPERIMENTAL mathstat.c mathstat.php php_mathstat.h tests




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



To use your new extension, you will have to execute the following steps:

1. $ cd ..
2. $ vi ext/mathstat/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-mathstat
5. $ make
6. $ ./sapi/cli/php -f ext/mathstat/mathstat.php
7. $ vi ext/mathstat/mathstat.c
8. $ make





В PHP7 файла buildconf после генерации у меня нет (наверное это остатки ранних версий PHP), но я знаю, что сейчас компиляция расширений начинается с команды phpize. Она “создает” кучу файлов, среди которых есть необходимый ./configure. Напомню, что пользовательский вариант компиляции расширения состоит в последовательном выполнении следующих команд.



Phpize -> ./configure -> make -> make test -> make install 




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



[root@localhost eugene]# make install
Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20151012/
cp: cannot stat 'modules/*': No such file or directory
make: *** [install-modules] Error 1




Phpize создает файлы на основе описания config.m4. Это, как я понял, своеобразный декларативный способ описания того, каким будет расширение, будет ли оно подтягивать внешние исходники или нет и т.д… Поэтому просмотрев другие расширения PHP в исходниках, я просто решил его максимально упростить, чтобы минимизировать ошибки компиляций с чистого листа. Действую по принципу — ничего не хочу, «все галочки снимаю».



Открываем этот файл (config.m4) и оставляем только этот текст. Опция “--enable-mathstat” говорит о том, что это просто расширение без внешних исходников (библиотек) и который можно либо включить, либо выключить. (dnl означает комментирование строки)



dnl $Id$

PHP_ARG_ENABLE(mathstat, whether to enable mathstat support,
[ --enable-mathstat Enable mathstat support])

if test "$PHP_MATHSTAT" != "no"; then
PHP_NEW_EXTENSION(mathstat, mathstat.c, $ext_shared,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
fi




Перезапускаем команду phpize.



[root@localhost mathstat]# phpize
Configuring for:
PHP Api Version: 20151012
Zend Module Api No: 20151012
Zend Extension Api No: 320151012
[root@localhost mathstat]# ls
acinclude.m4 config.guess configure EXPERIMENTAL mathstat.c php_mathstat.h
aclocal.m4 config.h.in configure.in install-sh mathstat.php run-tests.php
autom4te.cache config.m4 config.w32 ltmain.sh missing tests
build config.sub CREDITS Makefile.global mkinstalldirs




Далее, делаем знакомые команды:



./configure && make 




make test — запустит один изначально созданный тест. Про эти тесты PHP я как то писал уже вкратце.



[root@localhost mathstat]# make install
Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20151012/




В этот раз “make install” проходит, далее пробуем прописывать расширение в php.ini.



Определяем, где находится php.ini.



[root@localhost mathstat]# php --ini
Configuration File (php.ini) Path: /usr/local/lib
Loaded Configuration File: /usr/local/lib/php.ini
Scan for additional .ini files in: (none)
Additional .ini files parsed: (none)

viim /usr/local/lib/php.ini

extension=mathstat.so
;zend_extension = /usr/local/lib/php/extensions/no-debug-non-zts-20151012/xdebug.so

[root@localhost mathstat]# systemctl restart php-fpm

[root@localhost mathstat]# php -m | grep -i math
mathstat




Команда php -m (просматривает все установленные модули) говорит, что вроде бы все нормально, расширение mathstat подгрузилось.



Запускаем в текущей директории тестовый файл mathstat.php



[root@localhost mathstat]# php mathstat.php
Functions available in the test extension:
confirm_mathstat_compiled

Congratulations! You have successfully modified ext/mathstat/config.m4. Module mathstat is now compiled into PHP.
[root@localhost mathstat]#





Отлично, что — то уже работает.



2. Начинаем реализовывать функцию factorial().



Редактируем файл mathstat.c для добавления функции factorial().



Для этого нужно добавить функцию в “список” mathstat и сделать на неё заглушку, через макрос. Делаю все по аналогии как в других расширениях.



const zend_function_entry mathstat_functions[] = {
PHP_FE(confirm_mathstat_compiled, NULL) /* For testing, remove later. */
PHP_FE(factorial, NULL)
PHP_FE_END /* Must be the last line in mathstat_functions[] */
};





Реализация функции заглушки. Делается в обертке макроса. Как он работает в итоге, пока не ясно, оставляю изучение себе на будущее. Просто делаю в аналогичном формате.



PHP_FUNCTION(factorial)
{
RETURN_LONG(1000);
}



В данной случае под каждый тип возвращаемых данных, свой вариант RETURN_. Поиск в интернете покажет все возможные варианты. У нас просто целое значение. Тут вроде все просто.



Далее повторяем make clean && make && make install



[root@localhost mathstat]# make clean
find . -name \*.gcno -o -name \*.gcda | xargs rm -f
find . -name \*.lo -o -name \*.o | xargs rm -f
find . -name \*.la -o -name \*.a | xargs rm -f
find . -name \*.so | xargs rm -f
find . -name .libs -a -type d|xargs rm -rf
rm -f libphp.la modules/* libs/*

Build complete.
Don't forget to run 'make test'.

[root@localhost mathstat]# make install
Installing shared extensions: /usr/local/lib/php/extensions/no-debug-non-zts-20151012/

[root@localhost mathstat]# systemctl restart php-fpm
[root@localhost mathstat]# systemctl status php-fpm

https://habrahabr.ru/post/303572/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Создание блога на Symfony 2.8 lts [ Часть 6]

Суббота, 18 Июня 2016 г. 19:04 (ссылка)











Проект на Github

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





Тестирование в Symfony2



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



Совет



Если вы планируете писать свои собственные Open Source бандлы Symfony2, у вас гораздо больше шансов получить хороший отклик от пользователей, если Ваш бандл хорошо протестирован (и задокументирован). Посмотрите на список существующих Symfony2 бандлов, доступных на knpbundles.





Модульное (unit) тестирование



Модульное тестирование проверяет правильную работу отдельных единиц функции при использовании в изоляции. В объектно-ориентированном коде как в Symfony2, модуль это — класс и его методы. Например, мы могли бы писать тесты для классов сущностей Blog и Comment. При написании модульных тестов, тесты должны быть написаны независимо от других тестов, то есть, результат теста Б не должен зависеть от результата А. Модульное тестирование даёт возможность создавать фиктивные объекты, которые позволяют тестировать функции имеющие внешние зависимости. Фиктивные объекты(Моки) позволяют моделировать вызов функции вместо фактического выполнения. Примером этого может быть модульное тестирование класса, который оборачивает внешний API. Класс API может использовать протокол транспортного уровня для осуществления связи с внешним API. Мы могли бы сделать фиктивный метод запроса транспортного уровня, чтобы вернуть результаты, которые мы задали, а не получать на самом деле вернувшиеся с внешнего API. Модульное тестирование не проверяет, правильно ли функционируют компоненты приложения вместе, это показано в следующем разделе.



Функциональное тестирование



Функциональное тестирование проверяет интеграцию различных компонентов приложения, такие как маршрутизация, контроллеры и отображения. Функциональные тесты аналогичны ручным тестам, которые вы могли бы сделать у себя в браузере, например, запрос главной страницы, нажатие на ссылку записи и проверка правильности её отображения. Функциональное тестирование дает вам возможность автоматизировать этот процесс. Symfony2 поставляется в комплекте с целым рядом полезных классов, которые помогают при функциональном тестировании включая Client, который способен делать запросы на страницы, отправлять формы и DOM Crawler который мы можем использовать для обхода Ответа (Response) от клиента.



PHPUnit



Как было указано выше, Symfony2 тесты написаны с использованием PHPUnit. Вам необходимо будет установить PHPUnit для того, чтобы запустить тесты из этой части. Для получения более подробной информации по установке обратитесь к официальной документации на веб-сайте PHPUnit. Для запуска тестов в Symfony2 вам нужно установить PHPUnit 5.4 (требуется PHP 5.6). PHPUnit очень большая библиотека тестирования, в связи с этим будут сделаны ссылки на официальную документацию, где может потребоваться дополнительная информация.



Утверждения (assertions)



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



// Check 1 === 1 is true
$this->assertTrue(1 === 1);

// Check 1 === 2 is false
$this->assertFalse(1 === 2);

// Check 'Hello' equals 'Hello'
$this->assertEquals('Hello', 'Hello');

// Check array has key 'language'
$this->assertArrayHasKey('language', array('language' => 'php', 'size' => '1024'));

// Check array contains value 'php'
$this->assertContains('php', array('php', 'ruby', 'c++', 'JavaScript'));





Полный список утверждений(assertions) доступен в документации PHPUnit



Запуск тестов Symfony2



Перед тем, как приступить к написанию нескольких тестов, давайте посмотрим на то, как мы запускаем тесты в Symfony2. РНРUnit может использовать файл конфигурации. В нашем проекте Symfony2 этот файл находится app/phpunit.xml.dist. Так как этот файл с суффиксом .dist, вам необходимо скопировать его содержимое в файл с именем app/phpunit.xml.



Совет



Если вы используете VCS, такую как Git, вы должны добавить файл app/phpunit.xml в список игнорирования.





Если вы посмотрите на содержимое файла конфигурации PHPUnit вы увидите следующее.







../src/*/*Bundle/Tests
../src/*/Bundle/*Bundle/Tests






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



Совет



Для получения дополнительной информации о настройке PHPUnit с помощью файла XML смотрите документацию PHPUnit.





Запуск текущих тестов



Так как мы использовали одну из команд Symfony2 генератора для создания Blogger BlogBundle в первой части, она также создала тест контроллера для класса Default Controller. Мы можем выполнить этот тест, запустив следующую команду из корневого каталога проекта. -c опция указывает, что PHPUnit должен загрузить свою конфигурацию из каталога app.

$ phpunit -c app




После того, как тестирование завершится, вы должны быть уведомлены о том, что тест не удался. Если вы посмотрите на класс DefaultControllerTest, расположенного src/Blogger/BlogBundle/Tests/Controller/DefaultControllerTest.php вы увидите

следующее содержание

https://habrahabr.ru/post/303578/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Создание блога на Symfony 2.8 lts [ Часть 5.1]

Пятница, 17 Июня 2016 г. 16:09 (ссылка)

Привет, Хабр! Хочу немного вклиниться в цикл статей и показать как можно простым путём сделать обновление списка комментариев в ленте в режиме реального времени. Как это происходит, например, на github







Для реализации этой задачи будем использовать сервис Post Hawk.



Устанавливаем зависимости



Первое, что нам нужно это добавить в composer.json зависимость:

composer require post-hawk/hawk-api-bundle ~1.0


Или если вы переключились непосредственно на ветку 5.1, то достаточно просто

composer updae


и дождаться установки пакета.



Создаём симлинк на папку скиптов

Для windows:

cd path/to/project
mklink /J web\bundles\hawkapi vendor\post-hawk\hawk-api\Resources\public\


Для unix:

cd path/to/project
ln -s web\bundles\hawkapi vendor\post-hawk\hawk-api\Resources\public\


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




Далее устанавливаем erlang. Билды под разные системы находятся здесь, или, если есть желание, можно собрать из исходников.



Клонируем сервер и клиент

git clone https://github.com/postHawk/hawk_client.git
git clone https://github.com/postHawk/hawk_server




Собираем rebar:

$ git clone git://github.com/rebar/rebar.git
$ cd rebar
$ ./bootstrap


получившийся файлик (rebar) копируем в оба репозитория. Он нам необходим для сборки проекта.



Проект использует 2 версию rebar. Под rebar3 пока запустить не удаётся




Переходим в папку с сервером, собираем его и запускаем:

cd hawk_server
nano src/hawk_server.app.src
#заполняем данные о пользователе


{env, [
{statistic, [{use, false}]},
user, #{
<<"login">> => <<"symblog">>,
<<"domain">> => [ %список доменов с которых будут приниматься подключения
<<"127.0.0.1:8000">>
],
<<"key">> => <<"very secret key">> %api ключ. Должен совпадать на сервере и клиенте
}}
]}


mv .erlang .erlang_
rebar get-deps compile
mv .erlang_ .erlang

erl -name 'hawk_server@127.0.0.1' -boot start_sasl -setcookie test -kernel inet_dist_listen_min 9000 inet_dist_listen_max 9005




Аналогично собираем и запускаем клиент:

cd hawk_client
nano src/hawk_client.app.src
#заполните название server_node, например, 'test_hawk_server@127.0.0.1' и api_key (должен совпадать с серверным). Сохраните файл


{env, [
{api_key, <<"very secret key">>},
{server_node, 'hawk_server@127.0.0.1'}
]}


mv .erlang .erlang_
./rebar get-deps compile
mv .erlang_ .erlang
erl -name 'hawk_client@127.0.0.1' -boot start_sasl -setcookie test -kernel inet_dist_listen_min 9000 inet_dist_listen_max 9005




Если нужно запустить процесс в фоне, просто добавьте к набору параметров опцию -detached

Для пользователей windows утилиту запуска стоит изменить с erl на werl


Дорабатываем блог



Кофигурация бандла:

//app/AppKernel.php
$bundles = array(
...
new Hawk\ApiBundle\HawkApiBundle(),
new FOS\JsRoutingBundle\FOSJsRoutingBundle(),
);


#app/config/config.yml
hawk_api:
client:
host: '%hawk_api.client.host%' #ip или домен
port: '%hawk_api.client.port%' #порт, который слушает клиент
key: '%hawk_api.client.key%'


#app/config/parameters.yml
parameters:
hawk_api.client.host: 127.0.0.1
hawk_api.client.port: 7777
hawk_api.client.key: 'very secret key'


#app/config/routing.yml
hawk:
resource: '@HawkApiBundle/Controller/'
prefix: /hawk

fos_js_routing:
resource: "@FOSJsRoutingBundle/Resources/config/routing/routing.xml"




Ставим assets:

php app/console assets:install --symlink web




Дорабатываем контроллер:



...
use Blogger\BlogBundle\Entity\Blog;
use Hawk\ApiBundle\Event\GroupMessage;


В функцию добавления комментария помещаем отправку уведомлений:

...
$em->persist($comment);
$em->flush();

$this->sendNotification($comment, $blog);

return $this->redirect($this->generateUrl('BloggerBlogBundle_blog_show', array(
...


ну и добавляем саму функцию:



Код
/**
* Отправка уведомления о новом комментарии
* @param Comment $comment комментарий
* @param Blog $blog блог
*/
private function sendNotification(Comment $comment, Blog $blog)
{
//формируем тело комментария
$comment_text = $this->renderView('BloggerBlogBundle:Comment:index.html.twig', [
'comments' => [$comment]
]);

//формируем сообщение
$gMessage = new GroupMessage();
$gMessage
->setFrom('comment_demon')
->setGroups(['blog_' . $blog->getId()])
->setText(['comment' => $comment_text])
->setEvent('new_comment') //будет сгенерирован на клиенте
;

//отсылаем
$api = $this
->container
->get('event_dispatcher')
->dispatch(GroupMessage::NEW_MESSAGE, $gMessage)
->getResult() //HawkApi
;

//если возникли ошибки пишем их в лог
if($api->hasErrors()){
$logger = $this->get('logger');
$logger->error('Error sending message: ' . print_r($api->getErrors(), 1));
}
}






Немного остановлюсь на том, что здесь происходит. Отправка сообщений через сервис возможна двумя способами. Первый это как на примере выше, через систему событий symfony. Создаётся объект сообщения (простого или группового) и посылается с определённым типом события. Второй вариант — это отправка непосредственно с помощью апи, которое можно получить из контейнера:

$api = $this->get('hawk_api.api')->getApi();
$api
->registerUser($id)
->sendMessage($from, $to, $text, $event)
->execute()
->getResult('sendMessage')
;




Дорабатываем шаблоны:



В src/Blogger/BlogBundle/Resources/views/Blog/show.html.twig меняем строку

    



на

    



, так как нам необходим будет id блога для подписки пользователя.



Подключаем скрипты:

{#src/Blogger/BlogBundle/Resources/views/layout.html.twig#}
{% block javascripts %}
{% javascripts
'@BloggerBlogBundle/Resources/public/js/*'
output='js/plugins,js'
filter='?yui_js'
%}




{% endjavascripts %}
{% endblock %}




Ну и пишем немного js



код
$(document).ready(function () {
connectToHawk();
});

function connectToHawk()
{
//отправляем запрос за токеном
$.post(Routing.generate('hawk_token', {
useSessionId: 1
}), {}, function (data) {
if(data.errors === false){
//инициализируем подключение
HAWK_API.init({
user_id: data.result.id,
token: data.result.token,
url: data.result.ws,
debug: true
});

//подписываемся на новые комментарии
HAWK_API.bind_handler('new_comment', function(e, msg){
//игнорируем служебные сообщения
if(msg.from === 'hawk_client')
return;
//находим список комментариев и последний из них
//создаём объект нового
var $comments = $('.previous-comments'),
$last = $comments.find('.comment:last'),
cls = 'odd',
$comment = $(msg.text.comment)
;

//определяемся с классом комментария
if($last.size()){
cls = $last.hasClass('odd') ? 'even' : 'odd';
}

$comment
.removeClass('odd')
.addClass(cls)
.hide()
;
//показываем
$comments.append($comment);
$comment.show('normal')
});

//подписываемся на новые комментарии
HAWK_API.bind_handler('open', function(e, msg){
var id = $('.blog').data('blogId');
//добавляем пользователя в группу блога
//если её нет, то она будет создана с публичным доступом
HAWK_API.add_user_to_group(['blog_' + id]);
});
} else {
if(data.errors !== 'no_user') {
console.error(data);
}
}
});
}






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

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

Далее, инициализируем подключение и подписываемся на события. В данном случае, нас интересуют два из них. Первое — open, возникает после успешного подключения к сокету. Второе — new_comment (его мы передаём при отправке сообщения), непосредственно новый комментарий.



Вот собственно и всё. Благодарю за внимание. Код этой части доступен на github в соответствующей ветке.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/303098/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
vitaly80

Доступ к атрибуту XML с двоеточием в PHP на SimpleXML

Пятница, 17 Июня 2016 г. 19:52 (ссылка)
seo58.ru/sovety/41-dostup-k...-simplexml

Узнайте, как обратиться к атрибуту с двоеточием в PHP, поскольку квадратные скобки не срабатывают.
Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<php - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda