Создание SVG спрайтов |
Запись создана на основе статьи A few HTML tips.
SVG файлы можно использовать не только с помощью <img> тега:
<img src="acolyte_cartoon.svg" alt="acolyte">
Можно создавать SVG спрайты.
Для этого создается один SVG файл, в котором каждое изображение заворачивается в тег <symbol>:
<svg>
<symbol id="social-twitter" viewBox="...">
<!-- actual image data here -->
</symbol>
</svg>
Затем картинка может быть добавлена на страницу след. образом:
<svg class="social-icon">
<use xlink:href="icons.svg#social-twitter" />
</svg>
Для создания SVG спрайтов можно использовать плагин gulp-svgstore, который автоматически создает спрайты из отдельных файлов.
Особенно приятно, что используя <svg> вместо <img>, мы можем применять CSS стили:
.social-icon {
fill: #000;
transition: all 0.2s;
}
.social-icon:hover {
fill: #00f;
}
Есть, однако, некоторые CSS ограничения. При использовании SVG в теге <use> со связыванием <symbol>, картинка будет размещена в Shadow DOM и мы потеряем некоторые CSS возможности. Некоторые свойства (как fill) будут применены к элементам только, если они 'undefined'.
|
Салат из корневого сельдерея с огурцом "Праздничный" |
Корневой сельдерей, свежий огурец, крабовые палочки и ароматная руккола. Баланс вкусов этого салата украсит любой праздничный стол.

Подробнее о приготовлении: http://doctors.by/food/410-salad-celery-1.
Больше полезных блюд: http://doctors.by/food
|
|
Распознавание лиц на JQuery c помощью плагина FaceDetection |
Дублирую себе интересную статью:
http://habrahabr.ru/post/247077/?utm_campaign=emai...0106&utm_content=link2post
|
Легкий салат из кальмаров с яблоком |

Подготовка:
30 минут.
Ингредиенты:
Салат листовой - 5 крупных листьев.
Яблоко 2-3 шт .
Перец сладкий - 1шт.
Кальмары - 2 тушки.
Сельдерей - 2 стебля.
Оливковое масло - 2 стол. ложки.
Лимон - сок 2 стол. ложки.
Гранат - зерна для украшения.
Больше проверенных рецептов на сайте doctors.by.
Метки: рецепт кальмары яблоко |
Drupal 7. Установка Drupal и основных модулей с использованием Drush. |
В предыдущей статье
| DRUPAL 7. КАКИЕ МОДУЛИ ИСПОЛЬЗОВАЛА |
было подробно описано, какие и для чего использовала модули в проекте на Drupal.
Для создания нового проекта использую Drush для установки основных необходимых модулей. Установка занимает намного меньше времени, чем обычная установка. Drush сам закачивает и устанавливает необходимые модули.
Устанавливаем Drush. Я работаю с Windows 7.
Установка Drush: http://drush.ws/drush_windows_installer. Подробнее http://www.myflash.in.ua/drush/drush-urok-1-ustanovka-drush.html
После установки захожу Drush Command Prompt. Проверяю, работает ли drush
>drush
Должен появиться help.
Установка drupal:
cd C:\OpenServer\domains
drush dl drupal-7.x
Загрузит последнюю версию в каталог с именем этой версии. Переименовываю папку. Создаю пустую БД и запускаю в браузере сайт. К примеру сайт назвала drupal.local. Прохожу процедуру установки сайта в браузере и далее с помощью drush устанавливаю дополнительные модули.
cd drupal.local
drush dl admin_menu
drush en admin_menu_toolbar
drush dl module_filter
drush en module_filter
drush dl email_registration
drush en email_registration
drush dl date
drush en date_api
drush en date_views
drush en date_popup
drush dl pathauto
drush en pathauto
drush dl path_breadcrumbs
drush en path_breadcrumbs_ui
|
Drupal 7. Какие модули использовала |
Данный модуль необходим также для модуля Calendar.
Форма ввода контента появляется стандартная.
Настройка форм была сделана в файле template.php
function sosp_theme($existing, $type, $theme, $path) {
$items = array();
return array(
'node_form' => array(
'render element' => 'form',
'template' => 'templates/node-form',
)
);
}
function THEME_preprocess_node_form(&$variables) {
// спрятаны все поля администрирования сохранения
hide($variables['form']['menu']);
hide($variables['form']['revision_information']);
hide($variables['form']['additional_settings']);
hide($variables['form']['options']);
hide($variables['form']['author']);
hide($variables['form']['actions']['preview']);
// максимально упрощено появление поля body
// появляется только само поле без дополнительной иноформации
$variables['form']['body']['und'][0]['summary']['#description']='';
$variables['form']['body']['und'][0]['format']['format']['#access']=false;
unset ($variables['form']['body']['und'][0]['format']['guidelines']);
unset ($variables['form']['body']['und'][0]['format']['help']);
unset ($variables['form']['body']['und'][0]['summary']['#prefix']);
unset ($variables['form']['body']['und'][0]['summary']['#suffix']);
// подключается обработка формы ajax без перезагрузки страницы
$form['#validate'] = array();
$form['actions']['submit']['#submit'] = array();
$form['actions']['submit']['#ajax'] = array(
'callback' => 'ajax_form_node_callback',
);
}
// добавлено появление сообщений об ошибках в нужном месте формы и сообщения о загрузке формы
// поля сообщений были сделаны после контейнера с самой формой.
function ajax_form_node_callback($form, &$form_state) {
module_load_include('inc', 'node', 'node.pages');
node_form_validate($form, $form_state);
if (!form_get_errors()) {
node_form_submit($form, $form_state);
$commands = array(
ajax_command_remove('.sosp-form-errors'),
ajax_command_remove('.sosp-form-messages'),
ajax_command_append('.form-actions','<div class="sosp-form-messages">Thanks, your item was uploaded. It is to be approved by a moderator before it shows up.</div>'),
);
}
else {
$errors = form_get_errors();
$commands = array(
ajax_command_remove('.sosp-form-errors'),
ajax_command_remove('.sosp-form-messages'),
ajax_command_append('.form-actions','<div class="sosp-form-errors">'.implode($errors,', ').'</div>'));
}
// Get view's content
$content = views_embed_view('recent_activities', 'block');
return array('#type' => 'ajax', '#commands' => $commands);
}
node-form.tpl.php
<div class="<?php print $class; ?>">
<?php print drupal_render_children($form) ?>
</div>
Также с помощью этого модуля был сделан импорт документов из почтового ящика.
Настройкой почтового ящика управляет Mailhandler. Создается и настраивается mailhandler mailbox, а затем с помощью Feeds принимаются письма.
Дополнительно был установлен модуль Elysia Cron для удобства конфигурирования периодического приема данных из почты.
Нужен для конференций и других событий.
Для настройки событий и view используем модуль Events calendar feature.
Закачиваем дополнительно требуемые модули Context, Features.
Настройка событий и календаря: https://www.drupal.org/node/1250714.
в settings.php добавлена БД сайта на Drupal 6
$databases['legacy']['default'] = array(
'driver' => 'mysql',
'database' => '549913_sosp', // this is the name used to define the SOURCE_DATABASE constant above
'username' => 'root',
'password' => '',
'host' => 'localhost',
'prefix' => '',
);
Создан модуль для миграции sites/all/modules/custom/our_migration
файл our_migration.info
Пример кода:
name = "Example migration"
description = "The DTEK drupal 6 to 7 migration."
package = "DTEK"
core = 7.x
dependencies[] = taxonomy
dependencies[] = image
dependencies[] = comment
dependencies[] = migrate
dependencies[] = list
dependencies[] = number
files[] = our_migration.module
files[] = documents.inc
files[] = terms.inc
файл our_migration.module
<?php
define("SOURCE_DATABASE", '549913_sosp');
define("SOSP_MIGRATION_FILES_DIRECTORY",'public://attachments');
function our_migration_migrate_api() {
$api = array(
'api' => 2,
'migrations' => array(
'Investigators' => array('class_name' => 'InvestigatorsMigration'),
),
);
return $api;
}
Сначала была сделана миграция пользователей.
Затем таксономия.
Затем по очереди все узлы.
Пример миграции узла с таксономией и вложенными файлами:
<?php
// file documents.inc
class DocumentsMigration extends Migration {
public function __construct() {
parent::__construct(MigrateGroup::getInstance('examplegroup'));
// migrate without attachment files, attachment files were added by hands
$this->description = t('Migrate Drupal 6 Publications');
$source_fields = array(
'nid' => t('Node ID'),
'field_tags'=>t('Tags'),
'attachments_filename' => t('attachments_filename'),
);
// Source
$query = db_select(SOURCE_DATABASE . '.node', 'n');
$query->join(SOURCE_DATABASE . '.users', 'u', 'n.uid = u.uid');
$query->leftJoin(SOURCE_DATABASE . '.node_revisions', 'nr', 'n.vid = nr.vid');
$query->leftJoin(SOURCE_DATABASE . '.content_field_link', 'fl', 'n.vid = fl.vid');
$query->fields('n', array('nid', 'vid', 'type', 'language', 'title', 'uid', 'status', 'created', 'changed', 'comment', 'promote', 'moderate', 'sticky', 'tnid', 'translate'));
$query->fields('nr', array('uid', 'title', 'body', 'teaser', 'log', 'timestamp', 'format'));
$query->fields('u', array('name'));
$query->fields('fl', array('field_link_url','field_link_title','field_link_attributes'));
$query ->condition('n.status', 1, '=')
->condition('n.type', 'publication', '=')
->orderBy('n.nid', 'ASC');
// ->condition('n.nid', '3502', '=')
$this->source = new MigrateSourceSQL($query, $source_fields);
$this->destination = new MigrateDestinationNode('documents');
$this->map = new MigrateSQLMap($this->machineName,
array(
'nid' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'description' => 'D6 Unique Node ID',
'alias' => 'n',
)
),
MigrateDestinationNode::getKeySchema()
);
$this->addFieldMapping('title', 'title');
$this->addFieldMapping('is_new')->defaultValue(TRUE);
$this->addFieldMapping('uid', 'uid');
$this->addFieldMapping('revision')->defaultValue(TRUE);
$this->addFieldMapping('revision_uid', 'uid');
$this->addFieldMapping('created', 'created');
$this->addFieldMapping('changed', 'changed');
$this->addFieldMapping('status', 'status');
$this->addFieldMapping('promote')->defaultValue(0);
$this->addFieldMapping('sticky', 'sticky');
$this->addFieldMapping('comment', 'comment');
$this->addFieldMapping('language')->defaultValue('und');
$this->addFieldMapping('path')->issueGroup(t('DNM'));
$this->addFieldMapping('pathauto_perform_alias')->defaultValue('1');
$this->addFieldMapping(NULL, 'name');
$this->addFieldMapping(NULL, 'vid');
$this->addFieldMapping(NULL, 'type');
$this->addFieldMapping(NULL, 'language');
$this->addFieldMapping(NULL, 'moderate');
$this->addFieldMapping(NULL, 'tnid');
$this->addFieldMapping(NULL, 'translate');
$body_arguments = MigrateTextFieldHandler::arguments(NULL, filter_default_format(), NULL);
$this->addFieldMapping('body', 'body')
->arguments($body_arguments);
$this->addFieldMapping('body:summary', 'teaser');
$this->addFieldMapping('body:format')->defaultValue('full_html');
$this->addFieldMapping('body:language')->defaultValue('und');
$this->addFieldMapping('field_tags', 'field_tags');
$this->addFieldMapping('field_tags:create_term', TRUE);
$this->addFieldMapping('field_tags:ignore_case', TRUE);
$this->addFieldMapping('field_tags:source_type', 'name');
$this->addFieldMapping('field_link_title', 'field_link_title');
$this->addFieldMapping('field_link_title:language')->defaultValue('und');
$this->addFieldMapping('field_link_url', 'field_link_url');
$this->addFieldMapping('field_link_url:language')->defaultValue('und');
//files
$this->addFieldMapping('field_file', 'attachments_filename');
$this->addFieldMapping('field_file:file_class')->defaultValue('MigrateFileUri');
$this->addFieldMapping('field_file:language')->defaultValue('und');
$this->addFieldMapping('field_file:destination_dir')->defaultValue('public://attachments');
$this->addFieldMapping('field_file:file_replace')->defaultValue('FILE_EXISTS_REUSE');
$this->addFieldMapping('field_file:source_dir')->defaultValue('sites/default/files/attachments/');
$this->addFieldMapping('field_file:description')->defaultValue('');
}
public function prepareRow($current_row) {
$nid = $current_row->nid;
$terms_query = db_select(SOURCE_DATABASE .'.term_node', 'tn');
$terms_query->leftJoin(SOURCE_DATABASE .'.term_data', 'td','tn.tid = td.tid');
$terms_query ->fields('td',array('tid', 'vid', 'name', 'description', 'weight'));
$terms_query ->fields('tn',array('tid', 'vid', 'nid'));
$terms_query ->condition('tn.nid', $nid, '=');
$results = $terms_query->execute();
$s = array();
foreach ($results as $row) {
$s[] = $row->name;
}
$current_row->field_tags = $s;
// Set file data for the attachment file fields.
$query = db_select(SOURCE_DATABASE . '.content_field_attachments', 'a')
->fields('a', array('field_attachments_data'))
->condition('a.vid', $current_row->vid, '=');
$query->join(SOURCE_DATABASE . '.files', 'f', 'a.field_attachments_fid = f.fid');
$query->fields('f', array('filename','filepath','filemime','filesize','timestamp'));
$query->orderBy('a.field_attachments_fid', 'ASC');
$result = $query->execute();
foreach ($result as $row) {
$field_data = unserialize($row->field_attachments_data);
$field = array(
'filename' => $row->filename,
'filepath' => str_replace($row->filename, '', $row->filepath),
'description' => $field_data['description'],
);
$current_row->attachments_filename[] = $field['filename'];
}
return TRUE;
}
}
|
Простая функция для анимации |
Функция pseudoAnimate позволяет анимировать элементы страницы, для которых созданы спрайты из нескольких картинок.
Спрайты устанавливаются, как background для элементов. Функция выполняет цикличную замену координаты Y для фона.
Функция позволяет установить время смены фрагментов спрайта, включить или выключить цикличность анимации, установить время промежутка между циклами и время, которое будет длиться анимация.
function pseudoAnimate(element, options, time) {
options = $.extend({
frames: 1,
timeout: 500,
cycle: true,
cycleDelay: 0,
timeForAllCycles: 0
}, options);
var _timeForAllCycles = 0;
if (time) {_timeForAllCycles = time;}
if (options.cycle == 'false') options.cycle=false;
if (navigator.userAgent.search("MSIE") < 0)
{
var offset = /([\S]+)\s([\S]+)/i.exec($(element).css('background-position').trim());
var offsetX = parseInt(offset[1]);
var offsetY = parseInt(offset[2]);
} else {
var offsetX = parseInt($(element).css('background-position-x'));
var offsetY = parseInt($(element).css('background-position-y'));
}
var frame = Math.abs(offsetY / $(element).height()) + 1;
var timeout = options.timeout
if (frame < options.frames) {
offsetY = offsetY - $(element).height();
} else {
offsetY = 0;
timeout = options.cycleDelay != 0 ? options.cycleDelay : options.timeout;
}
if(navigator.userAgent.search("MSIE") >= 0) {
$(element).css({
'background-position-y': offsetY +'px'
});
} else {
$(element).css({
'background-position': offsetX + 'px ' +offsetY+'px'
});
}
if ((frame < (options.frames-1)) || options.cycle) {
if ( options.timeForAllCycles == 0 || (options.timeForAllCycles != 0 && _timeForAllCycles<options.timeForAllCycles ))
setTimeout(function(){
pseudoAnimate(element, options,_timeForAllCycles+Number(timeout));
}, timeout);
}
}
В статье используется функция, применяемая на сайте http://www.lill-skansen.se/
Применение функции:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Animation</title>
<style>
/* Demo styles */
#chrismas {
position: relative;
}
#moon {
position: absolute;
top: 35px;
left: 85px;
height: 48px;
width: 46px;
background: url("images/moon.png") 0 0 no-repeat transparent;
}
</style>
<!-- load jQuery -->
<script src="js/jquery.min.js"></script>
<!-- load Galleria -->
<script src="js/script.js"></script>
</head>
<body>
<div class="content">
<h1>Animation</h1>
<div id="chrismas" ><img src="images/christmas.png" alt="">
<!--Element with id="moon" will be animated. Set options for pseudoAnimate in this tag wth attributes data-->
<!--data-frames - number of frames, data-timeout - time of changing each frame, data-cycle - true/false, data-delay - time between cycles,-->
<!--data-time - time For All Cycles-->
<div id="moon" class="animation" data-frames="4" data-timeout="400" data-delay="2000"></div>
</div>
</div>
</body>
</html>
Инициализация
$(document).ready(function(){
$('.animation').each(function() {
pseudoAnimate(this, {
frames: $(this).data('frames'),
timeout: $(this).data('timeout'),
cycleDelay: $(this).data('delay'),
cycle: $(this).data('cycle'),
timeForAllCycles: $(this).data('time')
});
});
})
Демо
Вложение: 4037655_animation.rar
|
Основные ssh команды |
Для работы с ssh использую:
putty - для работы с архивами и командами;
FileZilla - для работы с файлами.
Основные ssh команды:
ls - список файлов и каталогов
ls -al - форматированный список со скрытыми каталогами и файлами
cd dir - сменить директорию на dir
cd - сменить на домашний каталог
cd .. - подняться на уровень вверх
клавиша Tab - дополняет имя каталога, например, для перехода в каталог drupal набираю cd dr и клавишу Tab - она дополнит название каталога до drupal.
правая клавиша мыши вставляет содержимое буфера в командную строку
mkdir dir - создать каталог dir
rm file - удалить file
rm -r dir - удалить каталог dir
cp file1 file2 - скопировать file1 в file2
cp -r dir1 dir2 - скопировать dir1 в dir2; создаст каталог dir2, если он не существует
mv file1 file2 - переименовать или переместить file1 в file2. если file2 существующий каталог - переместить file1 в каталог file2
Работа с архивами:
tar --help - получить помощь по основным командам и опциям tar.
tar -cvf cop.tar . - создать tar-архив с именем cop.tar содержащий все файлы и каталоги текущей директории. Опция -v позволяет отследить процесс создания архива.
tar -cvf cop.tar styles.css - создать tar-архив с именем cop.tar содержащий файл styles.css. Если архив с таким именем существует в текущей директории, он будет перезаписан командой без предупреждения.
tar --list --file=cop.tar - показать содержимое архива
tar --list --verbose --file=cop.tar - показать содержимое архива с полной информацией о файлах и каталогах
tar -xvf cop.tar - извлечь файлы из архива cop.tar. Информация будет разархивирована с сохранением структуры каталогов, существующие файлы будут записаны поверх извлеченными из архива.
tar --extract --file=cop.tar styles.css - извлечь файл styles.css из архива cop.tar.
Необходимо извлечь один файл или каталог из архива:
Команда tar -cvf cop.tar . создала архив с включенными каталогами.
tar --list --file=cop.tar показывает содержимое
./
./css
./cop2/
./cop2/css.tar
tar -xvf cop.tar ./cop2/css.tar - создаст каталог cop2 извлечет файл css.tar.
tar -xvf cop.tar ./cop2/ - извлечет каталог cop2.
tar -czf file.tar.gz files - создать архив tar с сжатием Gzip
tar -xzf file.tar.gz - распаковать tar с Gzip
zip --help - посмотреть, установлена ли программа zip
unzip cop.zip - распаковать zip-архив cop.zip.
zip file1.zip file1 — создать сжатый zip-архив
zip -r file1.zip file1 file2 dir1 — создать сжатый zip-архив и со включением в него нескольких файлов и/или директорий.
http://new-wp.net/files/putty.htm
Создать БД mysql
mysql -h hostname -u root -p
перейдет в командную строку mysql
create database [databasename];
выйти из mysql - \q или exit
если не набрал ; в конце - закончить команду - \g
восстановить БД из дампа - в командной строке
mysql -u username -ppassword databasename < /tmp/databasename.sql
tar архив создаю с помощью 7Zip.
|
Установка PHPUnit под Windows |
При обучении Zend Framework стояла задача настроить тестирование проекта с помощью PHPUnit.
Необходимо установить PHPUnit и затем выполнить в приложении под Zend Framework тесты.
Официальный сайт: https://github.com/sebastianbergmann/phpunit/
Приложение можно установить тремя способами. Я установила с помощью пакета установки приложений PEAR.
Устанавливаю PEAR:
В командной стоке необходимо запустить
путь-к-php\go-pear.bat
Я работаю с использованием Zend Server Community Edition.
php каталог - c:/zend/ZendServer/bin
cd c:/zend/ZendServer/bin
запускаю go-pear.bat
В PHP каталоге находится файл PEAR/go-pear.phar. Bat файл разворачивает архив и устанавливает PEAR.
Можно скачать перед установкой новую версию http://pear.php.net/manual/en/guide.users.commandline.cli.php.
Важно не менять установки по умолчанию и на все вопросы нажимать enter(первый раз при установке на вопрос Are you installing system-wide PEAR or local copy? ответила local - не были произведены все необходимые установки и PEAR не работал нормально). Очистила каталог PEAR, оставив файл go-pear.phar и установила заново.
Очень подробно об инсталляции PEAR - http://vertstudios.com/blog/pear-installation-tutorial/.
Устанавливаю PHPUnit способом, указанным readme.md:
В командной строке
pear config-set auto_discover 1
pear install pear.phpunit.de/PHPUnit.
Установка прошла успешно. PHPUnit в каталоге PEAR/PHPUnit.
|
Лепка. Панно с дедом Морозом. |
Всем доброго утра! Поклонникам лепки предлагаю сделать к Новому году вот такое панно с дедом Морозом и елочкой. В качестве основы для панно можно использовать вырезанный лист МДФ, плотного картона или использовать имеющийся поднос. Лепить деда Мороза можно из чего угодно, из того материала для лепки, с которым вы больше всего любите работать, будь то соленое тесто, пластика, полимерная глина или холодный фарфор. Эту идею можно также использовать для создания коробочки для подарка (украсить крышку такой лепкой). Итак, смотрим фото мастер-класс по лепке атрибутов приближающегося праздника.
Авто мастер-класса - Bia Cravol. Фотографии - Ricardo Novelli

|
Рождественский винтаж |
Всем привет!
Уникальная мастерица! Все, что творят ее золотые ручки - элегантно, воздушно и очень стильно! Хочу порадовать вас подборкой рождественских работ талантливейшей Сони из Бельгии (sezoentje-sonja.blogspot.com). Винтажная атмосфера рождественского декора... Браво, Соня!! Приятного просмотра!





|
Ароматные новогодние ёлки из картона и специй |
Вот... сколько не клялась себе что больше ни одной ёлки, даже самой малюсенькой делать не буду, а не удержалась. Ну ведь это же просто нереально себя остановить, если уже новогоднее настроение...
А еще много картона под рукой и всякие пряности-вкусности. Так что результат на лицо, снова эти самые пряники-ёлки "напеклись". Причем они еще и правда вкусные-превкусные, во всяком случае пахнут сногсшибающе. Потому что обклеила картон бумагой, которую затонировала раствором кофе-ваниль-корица, да и сам декор каждый со своим ароматом. Ну видите, да? Все натуральное! Розочки из яблочной кожуры, коричные палочки, кофейные зернышки и еще что-то такое плодово-круглое, даже не знаю что это...
Так что проходим, нюхаем, любуемся и новогодним настроением проникаемся!
|
76 идей Рождественского декора из Скандинавии |
|
Я.Субботник в Минске пройдет 2 июня 2012 года |
Я.Субботник в Минске пройдет 2 июня по адресу: Минск, ул. Кирова 13, отель "Crowne Plaza", зал "King".
Регистрация на мероприятие начнется 16 мая. Количество мест ограничено.
Для тех, кто не попадёт в число участников или не сможет лично присутствовать на Я.Субботнике, будет организована онлайн-трансляция.
Подробную информацию о мероприятии читайте здесь.
|
|
Создание web-service c использованием модуля Веб-сервисы 1C Bitrix |
Задача: Необходимо создать веб-сервис для публикации документов в Битриксе из SharePoint с необходимым набором методов для добавления, изменения и удаления записей.
Создала папку ws в корне сайта, в ней папку spdoc для определенного веб-сервиса.
Папка должна быть настроена на пустой шаблон Битрикса, в котором содержится только #WORK_AREA#.
В ней index.php
<?php
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/header.php");
if (CModule::IncludeModule("webservice")) {
require($_SERVER["DOCUMENT_ROOT"] . "/ws/spdoc/spdoc.php");
$webservice = new CWebService();
if (!$webservice->RegisterWebService('CGenericWSDLSpdoc')) {
throw new Exception('Couldn't register webservice');
}
$result = $webservice->SOAPServerProcessRequest('spdoc.ws');
if (!$result) {
throw new Exception('Couldn't process request');
}
$response = $webservice->GetSOAPServerResponse('spdoc.ws');
echo $response;
} else {
throw new Exception('Couldn't initialize webservice');
}
Файл wsdl.php формирует страницу web-service
<?php
ini_set('display_errors', 1);
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/header.php");
if (CModule::IncludeModule("webservice") ) {
require($_SERVER["DOCUMENT_ROOT"] . "/ws/spdoc/spdoc.php");
$webservice = new CWebService();
if (!$webservice->RegisterWebService('CGenericWSDLSpdoc')) {
throw new Exception('Couldn't register webservice');
}
$wsdl = $webservice->GetWSDL('spdoc.ws');
if (!$wsdl) {
throw new Exception('Couldn't create WSDL');
}
echo $wsdl;
} else {
throw new Exception('Couldn't initialize webservice');
}
Файл spdoc.php реализует инициализацию веб-сервиса и методы.
<?php
class createFile
{
var $mimeType;
var $fileName;
var $fileSize;
var $fileContent;
}
class cInputSp
{
var $group; //Группа документа
var $subject; //Название
var $method; //Доп. информация
var $file_a; //Архив приложений
}
class CGenericWSDLSpdoc extends IWebService
{
var $paramInfoBlock = array(
'IBLOCK_ID' => 18, // код ID основного информационного блока для добавления документов
'IBLOCK_GROUP' => 19 // код ID информационного блока для групп документов
);
function _trim(&$obInput){
$a_class = get_class($obInput);
$attribs = get_class_vars($a_class);
foreach ($attribs as $key=>$val){
if (is_string($obInput->$key)){
$obInput->$key = trim($obInput->$key);
}
}
}
function loadAttachFile ($file, $nameFile, &$errString) {
// функция загружает файл на диск во временный файл и подготавливает массив для записи файла в инфоблок
$this ->_trim($file);
if (empty($file->fileName) or $file->fileName == '?') return false; // file
if (empty($file->fileContent)) {$errString .= 'No file content: '.$file->fileName.'. '; return false;}
if (empty($file->mimeType)) {$errString .= 'No mime-type: '.$file->fileName.'. '; return false;}
$fileArray = array();
$tmpFile = $_SERVER["DOCUMENT_ROOT"]."/ws/spdoc/".$nameFile;
($f = fopen($tmpFile,'w+b')) or die('Error create temp file.' );
if (!$fileArray['size'] = fwrite($f,base64_decode($file->fileContent))) {$errString .= 'Error write temp file. '; return false;}
fclose($f);
$fileArray['name'] = $file->fileName;
$fileArray['tmp_name'] = $tmpFile;
$fileArray['type'] = $file->mimeType;
return $fileArray;
}
function publication($data)
{
global $USER;
$this ->_trim($data);
$errString = '';
if ( CModule::IncludeModule("iblock") ) {
// в инфоблоке уже много документов и есть символьное поле NUMBER с номером документа в Битриксе. В Битриксе своя нумерация, отличная от SP.
// Нужно найти последний номер публикации и присвоить новой записи следующий
// last number of publication
$arSelect = Array("ID", "PROPERTY_NUMBER");
$arFilter = Array("IBLOCK_ID" => $this->paramInfoBlock ['IBLOCK_ID'],"INCLUDE_SUBSECTIONS" => "Y");
global $DB;
$strSql = '
SELECT MAX(CAST(VALUE AS UNSIGNED)) AS max_num
FROM b_iblock_element_property AS a
INNER JOIN b_iblock_property AS b ON b.ID = a.IBLOCK_PROPERTY_ID
WHERE b.CODE = "NUMBER"
';
$NumberPubl = $DB->Query($strSql)->getNext();
$NumberPubl = $NumberPubl['max_num'] + 1;
// Проверяю имя группы документа в инфоблоке с группами документов и создаю нужную группу, если ее нет
$arSelect = Array("ID", "NAME");
$arFilter = Array("IBLOCK_ID" => $this->paramInfoBlock['IBLOCK_GROUP'],"INCLUDE_SUBSECTIONS" => "Y","NAME"=>$data->group);
$items = CIBlockElement::GetList(false, $arFilter, false, false, $arSelect);
$idGroup = 0;
if ($lastEl = $items->GetNextElement()){
$idGroup = $lastEl->fields['ID'];
}
else {
$el = new CIBlockElement;
$arLoadProductArray = Array(
"MODIFIED_BY" => $USER->GetID(), // элемент изменен текущим пользователем
"IBLOCK_ID" => intval($this->paramInfoBlock ['IBLOCK_GROUP']),
"NAME" => $data->group,
"ACTIVE" => "Y", // активен
"PREVIEW_TEXT" => '',
"DETAIL_TEXT" => '',
);
$idGroup = $el->Add($arLoadProductArray);
}
// создаю элемент инфоблока
$el = new CIBlockElement;
$PROP = array();
$PROP['NUMBER'] = $NumberPubl;
$PROP['METHOD'] = $data->method;
$PROP['GROUP'] = $idGroup;
if ($fileArray = $this->loadAttachFile($data->file_a, 'file_a', $errString) )
$PROP['FILE'] = $fileArray; //
$arLoadProductArray = Array(
"MODIFIED_BY" => $USER->GetID(), // элемент изменен текущим пользователем
"IBLOCK_ID" => intval($this->paramInfoBlock ['IBLOCK_ID']),
"PROPERTY_VALUES" => $PROP,
"NAME" => $data->subject,
"ACTIVE" => "Y", // активен
"PREVIEW_TEXT" => '',
"DETAIL_TEXT" => '',
);
$product_id = 0;
if ($product_id = $el->Add($arLoadProductArray))
{return array('id' => intval($product_id),'errString'=> $errString);}
else
{return array('id' => intval($product_id),'errString'=> $errString.'Can not add record to DB');}
}
}
function delete($id)
{
if (CModule::IncludeModule("iblock")) {
if (!CIBlockElement::Delete($id)) {
return false;
}
else
return true;
}
}
function GetWebServiceDesc()
{
// описание web-service
$wsdesc = new CWebServiceDesc();
$wsdesc->wsname = "spdoc.ws";
$wsdesc->wsclassname = "CGenericWSDLSpdoc";
$wsdesc->wsdlauto = true;
$wsdesc->wsendpoint = 'http://'.$_SERVER['HTTP_HOST'].'/ws/spdoc/index.php';
$wsdesc->wstargetns = CWebService::GetDefaultTargetNS();
$wsdesc->classTypes = array();
$wsdesc->structTypes = array();
/* this tryed to be loaded into a class */
$wsdesc->classTypes["createFile"] =
array(
"mimeType" => array("varType" => "string", "strict" => "no"),// свойство "strict" => "no" указывается, если поле необязательно к заполнению
"fileName" => array("varType" => "string", "strict" => "no"),
"fileSize" => array("varType" => "string", "strict" => "no"),
"fileContent" => array("varType" => "string", "strict" => "no"),
);
$wsdesc->classTypes["cInputSp"] =
array(
"group" => array("varType" => "string"),
"subject" => array("varType" => "string"),
"method" => array("varType" => "string"),
"file_a" => array("varType" => "createFile")
);
$wsdesc->classes = array(
"CGenericWSDLSpdoc" => array(
"delete" => array(
"type" => "public",
"name" => "delete",
"description" => "",
"input" => array(
"id" => array("varType" => "integer"),
),
"output" => array(
"result" => array("varType" => "boolean")
)
),
"publication" => array(
"type" => "public",
"name" => "publication",
"description" => "Adds item with data, [out] array(integer id, string errString if attached file have name and haven't content or mime type)
([in] class (
group - группа,
subject - наименование,
method - способ закупки,
file_a - архив с приложениями)",
"input" => array(
"data" => array("varType" => "cInputSp")
),
"output" => array(
"id" => array("varType" => "integer"),
"errString" => array("varType" => "string"),
)
)
));
return $wsdesc;
}
}
Созданный веб-сервис имеет Initial WSDL /ws/spdoc/wsdl.php
Проверяем веб-сервис любым клиентом, например soapUI.
Приведенный выше код проверен.
|