Несколько изображений к товару средствами дополнительных полей

Материал из Umicms
Версия от 15:16, 25 марта 2014; Mad grant (обсуждение | вклад)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к:навигация, поиск

Актуально для версии 2.9.5

Задача

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

Решение

Задачу можно решить средствами модуля "Шаблоны данных", ниже дан пример.

Вариант 1

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

Fields simple.png

2) Создадим товар с этим типом данных и заполним созданные поля в карточке товара:

Fields simple page.png

3) Теперь осталось это вывести, вывод в tpl есть в статье Добавление_нескольких_фотографий_к_описанию_объекта_каталога, первый вариант. В xslt же все еще проще, у нас будет примерно следующий xml документ, который нужно обработать:

<group id="5573" name="kartinki">
	<title>Картинки</title>
	<property id="971" name="kartinka_1" type="img_file">
		<title>Картинка 1</title>
		<value path="./images/cms/data/sovet/sovet-cv_tc21.jpg" folder="/images/cms/data/sovet" name="sovet-cv_tc21" ext="jpg" width="680" height="499">/images/cms/data/sovet/sovet-cv_tc21.jpg</value>
	</property>
	<property id="972" name="kartinka_2" type="img_file">
		<title>Картинка 2</title>
		<value path="./images/cms/data/sovet/sovet-tc3.jpg" folder="/images/cms/data/sovet" name="sovet-tc3" ext="jpg" width="350" height="350">/images/cms/data/sovet/sovet-tc3.jpg</value>
	</property>
	<property id="973" name="kartinka_3" type="img_file">
		<title>Картинка 3</title>
		<value path="./images/cms/data/sovet/sovet-tv-tc1.jpg" folder="/images/cms/data/sovet" name="sovet-tv-tc1" ext="jpg" width="500" height="412">/images/cms/data/sovet/sovet-tv-tc1.jpg</value>
	</property>
	<property id="974" name="kartinka_4" type="img_file">
		<title>Картинка 4</title>
		<value path="./images/cms/data/sovet/soviet-tv-b1.jpg" folder="/images/cms/data/sovet" name="soviet-tv-b1" ext="jpg" width="500" height="375">/images/cms/data/sovet/soviet-tv-b1.jpg</value>
	</property>
	<property id="975" name="kartinka_5" type="img_file">
		<title>Картинка 5</title>
		<value path="./images/cms/data/sovet/soviet-tv-ba.jpg" folder="/images/cms/data/sovet" name="soviet-tv-ba" ext="jpg" width="680" height="573">/images/cms/data/sovet/soviet-tv-ba.jpg</value>
	</property>
	<property id="977" name="kartinka_6" type="img_file">
		<title>Картинка 6</title>
		<value path="./images/cms/data/sovet/soviet-tv-t7.jpg" folder="/images/cms/data/sovet" name="soviet-tv-t7" ext="jpg" width="890" height="630">/images/cms/data/sovet/soviet-tv-t7.jpg</value>
	</property>
</group>

Обработать это дерево можно с помощью следующей конструкции:

<div style="max-width: 300; max-height: 300;">
	<ul class="bxslider">
		<xsl:for-each select="./page/properties/group[@name = 'kartinki']/property[@type = 'img_file']">
			<li>
				<xsl:apply-templates select="document(concat('udata://system/makeThumbnail/(.', ./value, ')/200/auto'))"/>
			</li>
		</xsl:for-each>
	</ul>
</div>

и шаблона, знакомого нам по статье Несколько_изображений_к_товару_средствами_протокола_ufs (bxslider мы берем оттуда же):

<xsl:template match="udata[@module = 'system' and @method = 'makeThumbnail']">
	<img src="{src}"/>
</xsl:template>

Плюсы

  • Легко реализовать в административном интерфейсе
  • Легко вывести на сайте
  • Легко менять изображения, в том числе и через eip

Минусы

  • Нельзя добавить дополнительное изображение ни через eip, ни через редактирование страницы
  • Пользователю будет нужно редактировать типы данных, а это чревато Ошибка_(coreException):_Give_me_a_normal_type_to_create_;)

Вариант 2

1) Создадим в типе данных, к которому относится товар составное поле и справочник к нему:

Fields option.png

2) Создадим в типе данных этого справочника поле типа изображение:

Guid options.png

3) Заполним справочник элементами:

Guid options add.png

4) Выберем на странице товара эти элементы:

Fields option page.png

5) Теперь осталось это вывести. В tpl для этого понадобится макрос %data getProperty()%, который выведет опцию, а в шаблоне для вывода опции понадобится макрос %data getPropertyOfObject()%, для вывода картинки. В xslt же все еще проще, у нас будет примерно следующий xml документ, который нужно обработать:

<property id="976" name="pictures" type="optioned">
	<title>Изображения</title>
	<value>
		<option int="1">
			<object id="5726" name="Картинка 1" type-id="620" ownerId="2" xlink:href="uobject://5726"/>
		</option>
		<option int="1">
			<object id="5727" name="Картинка 2" type-id="620" ownerId="2" xlink:href="uobject://5727"/>
		</option>
		<option int="1">
			<object id="5728" name="Картинка 3" type-id="620" ownerId="2" xlink:href="uobject://5728"/>
		</option>
		<option int="1">
			<object id="5729" name="Картинка 4" type-id="620" ownerId="2" xlink:href="uobject://5729"/>
		</option>
		<option int="1">
			<object id="5730" name="Картинка 5" type-id="620" ownerId="2" xlink:href="uobject://5730"/>
		</option>
		<option int="1">
			<object id="5731" name="Картинка 6" type-id="620" ownerId="2" xlink:href="uobject://5731"/>
		</option>
	</value>
</property>

Обработать это дерево можно с помощью следующей конструкции (снова используется bxslider):

<div style="max-width: 300; max-height: 300;">
	<ul class="bxslider">
		<xsl:for-each select="./page/properties/group[@name = 'kartinki']/property[@type = 'optioned']/value/option">
			<li>
				<xsl:apply-templates select="document(concat('udata://system/makeThumbnail/(.', document(concat('uobject://', ./object/@id,  '.kartinka'))//value, ')/200/auto'))"/>
			</li>
		</xsl:for-each>
	</ul>
</div>

и уже знакомого темплейта:

<xsl:template match="udata[@module = 'system' and @method = 'makeThumbnail']">
	<img src="{src}"/>
</xsl:template>

Плюсы

  • Легко вывести на сайте
  • Легко менять изображения, в том числе и через eip
  • Можно добавить дополнительное изображение через редактирование страницы

Минусы

  • Нельзя добавить дополнительное изображение через eip
  • В интерфейсе страницы не видны изображения выбранных элементов
  • Муторно добавлять элементы в справочник, а потом еще и опции на страницу

Кастомизация административного интерфейса

Попробуем решить два последних минуса и облегчить жизнь пользователю, то есть будет нужно:

  • Сделать отображение картинок выбранных элементов.
  • Дать возможность заполнить справочник прямо со страницы товар.

Пример кастомизации даем ниже.

1) Создадим в директории /styles/skins/mac/data/modules/catalog файл form.modify.custom.xsl следующего содержания:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet SYSTEM "ulang://common">
<xsl:stylesheet version="1.0"
	xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	xmlns:umi="http://www.umi-cms.ru/TR/umi"
	xmlns:php="http://php.net/xsl"
	>
	<xsl:template match="field[@type = 'optioned']" mode="form-modify">
		<div class="field text">
			<label for="{generate-id()}">
				<span>
					<xsl:call-template name="std-optioned-control_cus" />
				</span>
			</label>
		</div>
	</xsl:template>

	<xsl:template match="field[@type = 'optioned' and @name = 'stores_state']" mode="form-modify">
		<div class="field text">
			<label for="{generate-id()}">
				<span>
					<xsl:call-template name="std-optioned-control_cus">
						<xsl:with-param name="type" select="'int'" />
					</xsl:call-template>
				</span>
			</label>
		</div>
	</xsl:template>
	
	<xsl:template name="std-optioned-control_cus">
		<xsl:param name="guide-id" select="@guide-id" />
		<xsl:param name="input-name" select="@input_name" />
		<xsl:param name="title" select="@title" />
		<xsl:param name="tip" select="@tip" />
		<xsl:param name="type"><xsl:text>float</xsl:text></xsl:param>
		<xsl:choose>
			<xsl:when test="@name = 'pictures'">
				<h3>Добавить изображение:</h3>
				
				<xsl:variable name="filemanager">
					<xsl:text>elfinder</xsl:text>
				</xsl:variable>
				<span>
					<strong>Выберите изображение:</strong>
				</span>
				<div class="field file" id="{generate-id()}" umi:input-name="photo"
					umi:field-type="img_file"
					umi:name="photo"
					umi:folder="{@destination-folder}"
					umi:file="{@relative-path}"
					umi:folder-hash="{php:function('elfinder_get_hash', string(@destination-folder))}"
					umi:file-hash="{php:function('elfinder_get_hash', string(@relative-path))}"
					umi:lang="{/result/@interface-lang}"
					umi:filemanager="{$filemanager}"
					>
					<label for="symlinkInput{generate-id()}">
						<span id="fileControlContainer_{generate-id()}">
						</span>
					</label>
				</div>
				
				<xsl:variable name="gen_id" select="string(concat('fileControlContainer_', generate-id()))"/>
				<xsl:variable name="guid_id" select="number(./@guide-id)"/>
				<xsl:variable name="rel_id" select="string(concat('relationSelect', generate-id()))"/>
				
				<script type="text/javascript">
					$(document).ready(function(){
						$('#make_element').click(function(){
							
							$('#make_element').attr('src', "/images/cms/loading.gif");
							
							$photo_name = $('#option_name').val();
							$photo_path = $('#<xsl:value-of select="$gen_id"/> option:selected').val();
							
							if($photo_name == '' || $photo_path == ''){
								$('#make_element').attr('src', "/images/cms/admin/mac/table/ico_add.gif");
								return jQuery.jGrowl('Выберите изображение и укажите его имя', {
													 'header': 'Поля не заполнены',
													 'life': 1500
													});
							}
							
							$.ajax({
								  type: "POST",
								  url: "/udata://custom/makeElement/.json",
								  dataType: "json",
								  data: { photo_name: $photo_name,
								          photo_path: $photo_path,
										  guid: '<xsl:value-of select="$guid_id"/>'
								  }
							}).done(function(json) {
								$('#make_element').attr('src', "/images/cms/admin/mac/table/ico_add.gif");
								$object_id = json.result;								
								$option = "<option value=" + $object_id + ">" + $photo_name + "</option>";								
								$('#<xsl:value-of select="$rel_id"/>').append($option);					
								return jQuery.jGrowl('Элемент успешно добавлен, теперь можно добавить еще', {
													 'header': 'Элемент успешно добавлен',
													 'life': 1500
													});
							  })
							  .fail(function() {
								$('#make_element').attr('src', "/images/cms/admin/mac/table/ico_add.gif");
								return jQuery.jGrowl('При добавлении элемента произошла ошибка', {
													 'header': 'Ошибка',
													 'life': 1000
													});
							  })
						});
					});
				</script>
				<span style="width: 47%;">
					<strong>Укажите имя изображения:</strong>
					<input id="option_name" type="text"/>
					<img id="make_element" src="/images/cms/admin/mac/table/ico_add.gif"/>
				</span>
				
				<h3>Выбрать изображение:</h3>
				<table id="{generate-id()}" class="tableContent optioned">
					<thead>
						<th umi:type="rel">
							<acronym>
								<xsl:if test="$tip">
									<xsl:attribute name="title"><xsl:value-of select="$tip" /></xsl:attribute>
								</xsl:if>
								<strong><xsl:value-of select="$title" />:</strong>
							</acronym>
						</th>
						<th umi:type="{$type}" class="center" />
						<th class="center narrow" />
					</thead>
					<tbody>
						<xsl:apply-templates mode="field-optioned_cus">
							<xsl:with-param name="input-name" select="$input-name" />
							<xsl:with-param name="type" select="$type" />
						</xsl:apply-templates>
					</tbody>
					<tfoot>
						<tr>
							<td style="padding-left:0;">
								<select id="relationSelect{generate-id()}" umi:guide="{$guide-id}" umi:name="{$input-name}" class="relation-add"></select>
								<input type="text" id="relationInput{generate-id()}" />
								<input type="hidden"  id="relationButton{generate-id()}" />
							</td>
							<td class="center"><input type="text" umi:type="{$type}" /></td>
							<td class="center narrow">
								<a href="#" class="add"><img src="/images/cms/admin/mac/table/ico_add.gif" /></a>
							</td>
						</tr>
					</tfoot>
				</table>
				<div>
					<a href="{$lang-prefix}/admin/data/guide_items/{$guide-id}/"><xsl:text>&label-edit-guide-items;</xsl:text></a>
				</div>			
			</xsl:when>
			<xsl:otherwise>
				<table id="{generate-id()}" class="tableContent optioned">
					<thead>
						<th umi:type="rel">
							<acronym>
								<xsl:if test="$tip">
									<xsl:attribute name="title"><xsl:value-of select="$tip" /></xsl:attribute>
								</xsl:if>
								<xsl:value-of select="$title" />
							</acronym>
						</th>
						<th umi:type="{$type}" class="center" />
						<th class="center narrow" />
					</thead>
					<tbody>
						<xsl:apply-templates mode="field-optioned">
							<xsl:with-param name="input-name" select="$input-name" />
							<xsl:with-param name="type" select="$type" />
						</xsl:apply-templates>
					</tbody>
					<tfoot>
						<tr>
							<td style="padding-left:0;">
								<select id="relationSelect{generate-id()}" umi:guide="{$guide-id}" umi:name="{$input-name}" class="relation-add"></select>
								<input type="text" id="relationInput{generate-id()}" />
								<input type="hidden"  id="relationButton{generate-id()}" />
							</td>
							<td class="center"><input type="text" umi:type="{$type}" /></td>
							<td class="center narrow">
								<a href="#" class="add"><img src="/images/cms/admin/mac/table/ico_add.gif" /></a>
							</td>
						</tr>
					</tfoot>
				</table>
				<div>
					<a href="{$lang-prefix}/admin/data/guide_items/{$guide-id}/"><xsl:text>&label-edit-guide-items;</xsl:text></a>
				</div>
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<xsl:template match="field/values/value" mode="field-optioned_cus">
		<xsl:param name="input-name" />
		<xsl:param name="type"><xsl:text>float</xsl:text></xsl:param>
		<xsl:variable name="position" select="position()" />
		<tr>
			<td>
				<span><xsl:value-of select="object/@name" /></span>
				<span><xsl:apply-templates select="document(concat('udata://system/makeThumbnail/(.', document(concat('uobject://', object/@id))/udata/object/properties/group[@name='kartinki']/property[@name='kartinka']/value, ')/50/auto'))" mode="optioned_pic"/></span>
				<input type="hidden" name="{$input-name}[{$position}][rel]" value="{object/@id}" />
			</td>
			<td class="center">
				<xsl:choose>
					<xsl:when test="$type = 'int'">
						<input type="text" umi:type="{$type}" name="{$input-name}[{$position}][{$type}]" value="{@int}" />
						<input type="hidden" umi:type="float" name="{$input-name}[{$position}][float]" value="1" />
					</xsl:when>
					<xsl:when test="$type = 'varchar'">
						<input type="text" umi:type="{$type}" name="{$input-name}[{$position}][{$type}]" value="{@varchar}" />
						<input type="hidden" umi:type="int" name="{$input-name}[{$position}][int]" value="1" />
					</xsl:when>
					<xsl:otherwise>
						<input type="text" umi:type="float" name="{$input-name}[{$position}][float]" value="{@float}" />
						<input type="hidden" umi:type="int" name="{$input-name}[{$position}][int]" value="1" />
					</xsl:otherwise>
				</xsl:choose>
			</td>
			<td class="center narrow">
				<a href="#" class="remove">
					<img src="/images/cms/admin/mac/table/ico_del.gif" />
				</a>
			</td>
		</tr>
	</xsl:template>
	
	<xsl:template match="udata[@module = 'system' and @method = 'makeThumbnail']" mode="optioned_pic">
		<img src="{src}"/>
	</xsl:template>

	<xsl:include href="udata://core/importSkinXsl/form.modify.xsl"/>
</xsl:stylesheet>

2) Добавим в файл /classes/modules/custom.php следующий кастомный метод:

public function makeElement(){
	$name = urldecode($_POST['photo_name']);
	$name = htmlspecialchars($name);
	
	$guid = intval($_POST['guid']);
	$path = $_POST['photo_path'];

	$objectsCollection = umiObjectsCollection::getInstance();
	$id = $objectsCollection->addObject($name, $guid);
	if($id){
		$object = $objectsCollection->getObject($id);
		$object->setValue('kartinka', $path);
		$object->commit();
		return $id;
	}else{
		return 'Не удалось создать объект';
	}			
}

3) Теперь в карточке товара мы увидим следующее:

Custom adm option.png

Дополнительно

Также, есть и другие способы вывода нескольких картинок для товара: