За чистый и ясный код!

Статьи на тему программирования под веб, используя PHP, MySQL, Jquery и многое другое

Веб формы. Основые построения на XHTML

Декабрь23
Светодиодные лампы лб производства Feron.

Вступление

По своей работе я создаю очень много разных и разнообразных веб форм. С использованием ajax, jQuery и тд. Веб формы от маленькой до великой. У меня накопился довольно большой багаж знаний с которыми я и хочу поделиться. Я хочу написать цикл статей посвященных построению веб форм, далее просто формы, их обработке с помощью фреймвеорка Zendframework и Kohana. Начну я с самого начало — построение формы на чистом XHTML.

Хочу сразу предупредить людей которые знают как строиться форма, какие бывают атрибуты, элементы и их особенности — статья не для вас, поэтому писать в комментариях «для зеленных» не стоит. Можете перейти к другим статьям.

Что есть форма

Определение формы пипец как много…. В данном контексте под формой подразумевается набор тегов которые позволяют передавать вводимую информацию от клиента на сервер.

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

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

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

Пример построения формы

Начнем с небольшого примера, в который я попытался собрать все теги, которыми обладает XHTML для построения формы.

Пример формы

Пример формы

Ссылка на пример формы

Во всех последующих примерах я буду брать за основу эту форму.

Ниже приведены коды для построения этой формы.

<h1>Контактная форма</h1>
<form action="/contact" method="post" id="contact" accept-charset="utf-8" enctype="multipart/form-data">
	<div class="require">Поля помеченные знаком <span>*</span> обязательны для заполнения</div>
	<fieldset title="Ваши данные"><br />
		<legend>Ваши данные</legend>
		<ul>
			<li>
				<label for="name">Ваше имя:<span>&nbsp;*</span></label><br />
				<input type="text" id="name" name="name" value="" />
			</li>
			<li>
				<label for="email">Ваш эл. адрес:<span>&nbsp;*</span></label><br />
				<input type="text" id="email" name="email" value="" />
			</li>
			<li class="sex">
				<div>Укажите Ваш пол:<span>&nbsp;*</span></div>
				<label for="your_sex_mail">муж:</label><br />
				<input type="radio" id="your_sex_mail" name="sex" value="1" /><br />
				<label for="your_sex_femail">жен:</label><br />
				<input type="radio" id="your_sex_femail" name="sex" value="0" />
			</li>
		</ul>
	</fieldset>
	<fieldset title="Ваш вопрос">
		<legend>Ваши вопрос</legend>
		<ul>
			<li>
				<label for="type_error">Описание проблемы:<span>&nbsp;*</span></label></p>
				<select id="type_error" name="type_error">
					<option value="0" selected="selected"></option><br />
					<option value="1">изменение информации о сайте</option><br />
					<option value="2">стилистические, грамматические, орфогр. ошибки</option><br />
				</select>
			</li>
			<li>
				<label for="descr">Описание проблемы:<span>&nbsp;*</span></label><br />
				<textarea id="descr" name="descr" cols="50" rows="10"></textarea>
			</li>
			<li>
				<label for="img">Картинка с ошибкой:</label><br />
				<input type="file" id="img" name="img" />
			</li>
			<li>
				<label for="track">Отслеживать вопрос:</label><br />
				<input type="checkbox" id="track" name="track" value="0" />
			</li>
		</ul>
	</fieldset>
	<ul class="captcha">
		<li>
			<span class="code">Код:</span><br />
			<span id="img"><img src="/captcha/default" alt="Введите код указаный на картинке" class="capt" /></span><br />
			<span id="change_captcha">сменить код</span>
		</li>
		<li>
			<label for="captcha">Введите код:<span>&nbsp;*</span></label><br />
			<input type="text" id="captcha" name="captcha" />
		</li>
	</ul>
	<div class="buttons">
		<input type="submit" name="submit" value=" ОТПРАВИТЬ" />
	</div>
</form>

Описание тегов и их атрибутов

Теги которые используются для построения формы:

<form>

С этого тега начинается форма. Форма в форме не существует!!! Кол-во форм на странице может быть много.

Каждый тег имеет свои атрибуты, которыми задается свойство тега.

Данный тег имеет следующие атрибуты:

action — в этот атрибут указывает путь к скрипту который будет обрабатывать данные формы. Атрибут может быть пустой, тогда за путь принимается текущий адрес страницы. Также можно указать путь на другой сервер, например вы можете построить на своём сайте поисковую форму какого-нибудь поисковика и в этом атрибуте указать адрес этого поисковика. После отправки данных формы, браузер перебросит вас на указанный урл, и если все параметры формы заданы правильно, то поисковик покажет ответы на заданный вопрос.

<form action="/contacts">....</form>

method — Есть два значения GET и POST (не чувствительны к регистру). Это способ передачи данных серверу.

Метод GET он стоит по-умолчанию, говорит серверу о том, что данные формы будет переданы, как параметры к урлу указанному в атрибуте action. С помощью метода GET передать файлы невозможно!!! Обычно такой метод формы используется для поисковых запросов.

<form action="/contacts" method="get">
	<input type="text" name="data" value="some value" />
	<input type="submit"  name="send" value="send data" />
</form>
в урле будет
http://test/contacts?data=some+value&send=send+data

Метод POST в отличии от метода GET ничего не добавляет к обрабатываемому УРЛу, а передает все данные формы через заголовки (юзеру явно не видно какие параметры передаются). Данный метод позволяет передать файлы.

<form action="/contacts" method="post">
	<input type="text" name="data" value="some value" />
	<input type="submit"  name="send" value="send data" />
</form>
в заголовках посланных к серверу будет следующее
POST /contacts HTTP/1.1
Host: test
....
я вырезал параметры не относящиеся к примеру
....
Content-Length: 30
data=some+value&send=send+data

enctype — этот атрибут указывает какой тип контента будет передаваться формой (просто текст или текст + файлы), если ничего не указано, то берется значение по-умолчанию application/x-www-form-urlencoded — означает что некоторые символы при передаче данных будут кодировться в предыдущих примерах, видно что вместо пробела появляется знак + data=some+value.

Если надо передать файлы + текст надо использовать тип multipart/form-data.

<form action="/contacts" method="post" enctype="multipart/form-data">
	<input type="file" name="somefile" />
	<input type="submit"  name="send" value="send data" />
</form>

accept — этот атрибут я не видел в использовании, он есть в документации, но чтобы он так сильно работал я не видел. Он позволяет определить какой тип файла должен обрабатывать сервер, но как показывает практика серверу по барабану!

<form action="/contacts.php" method="post" enctype="multipart/form-data" accept="image/png, image/gif">
	<input type="file" name="somefile" />
	<input type="submit"  name="send" value="send data" />
</form>
по-идеи должен только обрабатывать картинки типа png, gif.
Но на деле пропускает все подряд ... может есть какие-то
тонкие настройки сервера...

name — просто название формы. Должно начинаться с буквы ([A-Za-z]), за которой может следовать любое число букв, цифр ([0-9]), символов переноса (‘-‘), символов подчеркивания (‘_’), двоеточий (‘:’) и точек (‘.’).

accept-charset — указывает серверу в какой кодировке принимать данные формы.

<form action="/contacts.php" method="post" enctype="multipart/form-data" accept-charset="WINDOWS-1251">
	<input type="text" name="somefile" value="привет"/>
	<input type="submit"  name="send" value="send data" />
</form>
Сама страница документа у меня UTF-8, но в форме я указал WINDOWS-1251.
В результате данные формы на сервер пришли в кодировке 1251.
<form action="/contacts.php" method="post" enctype="multipart/form-data" accept-charset="UTF-8">
	<input type="text" name="somefile" value="привет"/>
	<input type="submit"  name="send" value="send data" />
</form>
теперь UTF-8.

Если в параметр опускать, то кодировка соот. кодировке страницы.

onsubmit и тд — это методы для JavaScript их довольно много. Описывать в рамках этой статьи я не пока не буду.

class — указывает название класса для оформления формы стилями

style — указывает сами стили для оформления

<input>

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

Имеет следующие атрибуты (основные):

id — уникальный идентификатор тега в рамках загруженной страницы

type — самый важный параметр, который определяет внешний вид формы.

Если тип не указан, то принимается тип по-умолчанию type=’text’. Это означает что данное поле может принимать и отправлять на сервер любые строчные данные, т.е. те которые можно набрать на клавиатуре.

Внешний вид тега с данным типом:
Opera 11Вид в браузере Opera 11
Chrome 8Вид в браузере Chrome 8
FireFox 3.6Вид в браузере FireFox 3.6
Internet Explorer 9 betaВид в браузере Internet Explorer

Тип type=’password’ этот тип предназначен для поле в которое вводиться пароль или какая-то информация, которая, по-вашему мнению, обладает секретностью. Это не значит, что ваши данные как-то шифруются, просто при их вводе вместо вводимых символов показываются какие-то однотипные знаки. В каждой операционке они могут быть разными. При использовании тега с этим атрибутом не следует указывать секретную фразу в значении атрибута value, иначе при просмотре кода страницы можно легко узнать этот секрет, значение этого атрибута должно быть всегда пустым.

Внешний вид тега с данным типом:
Opera 11Вид в браузере Opera 11
Chrome 8Вид в браузере Chrome 8
FireFox 3.6Вид в браузере FireFox 3.6
Internet Explorer 9 betaВид в браузере Internet Explorer

Тип type=’radio’ этот тип предназначен для выбора из множества значений одного значения. Например, в рассматриваемой форме нам надо выбрать пол, т.е. из двух значений — мужской и женский пол (множество) какого-то одного. Но здесь есть один прикол. При формировании тега с данным типом, необходимо указывать одинаковое значение в атрибуте name.

<input type="radio" name="sex" value="мужской"/>
<input type="radio" name="sex" value="женский"/>

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

Внешний вид тега с данным типом:
Opera 11Вид в браузере Opera 11
Chrome 8Вид в браузере Chrome 8
FireFox 3.6Вид в браузере FireFox 3.6
Internet Explorer 9 betaВид в браузере Internet Explorer

Тип type=’checkbox’ этот тип предназначен для выбора из множества значений, одного, нескольких или всех. Для этого типа, в отличии от типа type=’radio’ значение атрибута name должны быть разными.

<input type="checkbox" name="checkbox1" value="привет1"/>
<input type="checkbox" name="checkbox2" value="привет2"/>

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

Внешний вид тега с данным типом:
Opera 11Вид в браузере Opera 11
Chrome 8Вид в браузере Chrome 8
FireFox 3.6Вид в браузере FireFox 3.6
Internet Explorer 9 betaВид в браузере Internet Explorer

Тип type=’file’ этот тип предназначен для загрузки файлов на сервер. Обратите внимание, что для загрузки файлов на сервер нужно иметь определенное значение атрибута ….. тега form (детальней читайте в описании тега form). Размер и тип загружаемого файла зависит от настроек сервера.

Внешний вид тега с данным типом:
Opera 11Вид в браузере Opera 11
Chrome 8Вид в браузере Chrome 8
FireFox 3.6Вид в браузере FireFox 3.6
Internet Explorer 9 betaВид в браузере Internet Explorer

Тип type=’submit’ этот тип предназначен для отправки всех данных формы на сервер.

Внешний вид тега с данным типом:
Opera 11Вид в браузере Opera 11
Chrome 8Вид в браузере Chrome 8
FireFox 3.6Вид в браузере FireFox 3.6
Internet Explorer 9 betaВид в браузере Internet Explorer

Тип type=’reset’ этот тип предназначен для очистки всех полей формы. Т.е. вы что-то набираете и захотели все стереть, нажимая на кнопку с соот типом все введенная инфа удаляется, форма переходит в состояние в котором она была загружена на страницу. Заметьте, если в форме уже стоят какие-то значения, то они удалены не будут!!!

Внешний вид тега с данным типом:
Opera 11Вид в браузере Opera 11
Chrome 8Вид в браузере Chrome 8
FireFox 3.6Вид в браузере FireFox 3.6
Internet Explorer 9 betaВид в браузере Internet Explorer

Тип type=’image’ этот тип предназначен для отправки данных на форму, аналогичен тегу с типом submit, но разница только в том, что вместо кнопки можно подставлять любое изображение, также, если форма с методом GET, то в УРЛе появляются дополнительные переменные — координаты клика по рисунку, пример

http://example.com/?key=value&img.x=7&img.y=10

где img - это аттрибут name тега с типом image

Внешний вид тега с данным типом:
Opera 11Вид в браузере Opera 11
Chrome 8Вид в браузере Chrome 8
FireFox 3.6Вид в браузере FireFox 3.6
Internet Explorer 9 betaВид в браузере Internet Explorer

name — имя тега, оно же имя переменной, которая принимает значение атрибута

value значение переменной с именем в атрибуте name, которое передается на сервер.

maxlenght — указывает на максимальную длину данных в элементе, если тип элемента text

checked в элементах формы с типом radio и checkbox указывает на выбранный элемент или элементы если тип checkbox.

disabled — Предназначен для отключения передачи данных элемента формы серверу. Переменная просто не передается вообще.

readonly — означает, что данные этого тега будут доступны только для чтения, изменять их нельзя. В отличии от атрибута disabled данные тега отправляются на сервер.

class — класс для стилей

style — предназначен для описания стилей данного элемента

onClick и д.р. события предназначенный для JavaScript. Описание выходит за рамки данной статьи

<select>

Тег предназначен для выбора или одного значения или множества из списка. Для выбора множества значения должен стоять атрибут multiple=’multiple’, атрибут name должен содержать название переменной и иметь в конце квадратные скобки [] — указывает, что возможна передача не одного значения, также атрибут size=’число’ указывает кол-во видимых элементов. Выбор множества осуществляется с удержанием клавиши ctrl и кликом на выбираемый элемент списка.

Внешний вид тега с данным типом:
Opera 11Вид в браузере Opera 11
Chrome 8Вид в браузере Chrome 8
FireFox 3.6Вид в браузере FireFox 3.6
Internet Explorer 9 betaВид в браузере Internet Explorer

<option>

Являеться частью тега select и предназначен для вывода одного элемента списка. Содежит атрибут value в который записывается значение, которое передается на сервер. Между открывающимся и закрывающимся тегом option содержится название описываемой переменной. Обычно в атрибуте value содержаться ID элементов, а между тегами значение элементов

<option value="1">apple</option>
<option value="2">pear</option>
<option value="3">cherry</option>

<optgroup>

Тег предназначен для разделения на группы элементов списка, например надо выделить группу фрукты и овощи в одном списке. Внутри тега содержаться список параметров, теги option. Сам тег optgroup имеет атрибут label — это текст которым называют выделенную группу.

Пример:

<optgroup label="фрукты">
	<option value="1">Апельсинка</option>
	<option value="2">Мандаринка</option>
	<option value="3">Лимончик</option>
</optgroup>
<optgroup label="овощи">
	<option value="4">Кабачок</option>
	<option value="5">Помидорка</option>
	<option value="6">Огурчик</option>
</optgroup>

Внешний вид тега:
Внешний вид тега optgroup

<textarea>

Тег предназначен для ввода и отправки текста с переносами строк. Отличается от тега <input type=’text’>, тем что поддерживается перенос строк.
Внешний вид элемента (размер) можно указывать с помощью стилей или с помощью атрибутов rows высота поля в строках текста, атрибут cols ширина поля в символах.

Внешний вид тега:
Внешний вид тега textarea

<button>

Позволяет выводить комбинированные с текстом и изображением.

<button><img src="image.png" alt="Кнопка с рисунком и текстом" />&nbsp;Кнопка с рисунком и текстом</button>

Внешний вид тега:
Внешний вид тега button

<fieldset>

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

<fieldset>
	<legend>чекеры</legend>
	<input type="radio" name="radio" value="мужской" checked="checked"/>
	<input type="radio" name="radio" value="женский"/><br /><br />
	<input type="checkbox" name="checkbox1" value="привет1"/>
	<input type="checkbox" name="checkbox2" value="привет2"/>
</fieldset>

Внешний вид тега:
Внешний вид тега fieldset

<legend>

Предназначен для вывода названия тега fieldset внутри которого содержится.

<label>

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

Существует два способа использования тега. Первый — привязывание идентификатора id элемента к атрибуту for тега label. При втором способе элемент формы оборачивается тегом label. Еще характеризуется тем, что при клике на лейбу, элемент к которому она привязана получает фокус.

<label for="textId">Приветствие</label><input id="textId" type="text" name="text" value="привет"/><br /><br />
<label>пароль<input type="password" name="password" value="привет"/></label>

Внешний вид тега:
Внешний вид тега label

Список используемой литературы

  1. Мои знания
  2. http://www.nbuv.gov.ua/books/19/html40/interact/forms.html
  3. http://htmlbook.ru

Статья просмотренна 127010 раз, зашло посетителей 20275

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

Ноябрь28

В этой статье я хочу рассказать, как я делал техническую документацию на перенос счетчика газа. Какие документы для этого нужны, какие трудности и тд.

Объект:
1 з-х комнатная квартира в новом 6-ти этажном доме. В новых, заселяемых домах газ сразу не включают, кто-то говорил цифры от 70-90% от всех проживающийх, чтобы включить газ.

План квартиры в соответствии с техпаспортом

План квартиры в соответствии с техпаспортом

фронтальный вид дома

фронтальный вид дома

2 Фото расположение счетчика до перепланировки.

Первоначальное расположение счетчика

Первоначальное расположение счетчика

Первоначальное расположение счетчика

Первоначальное расположение счетчика

3 ЖЕК застройщика, не муниципальный. Сайт застройщика Авантаж

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

Дизайн кухни

Дизайн кухни

понял, что месторасположение счетчика (1.6м от пола) не вписывается в мои планы. Пришлось счетчик просто переносить, на высоту шкафчика. Когда только начинались работы по ремонту квартиры, я нашел каких-то двух «строителей», которые мне перенесли счетчик на нужную мне высоту, но скрутили мне трубы (от трубы к счетчику и от счетчика к газовому шлангу) на металлических уголках. Заплатил за это 150 грн.

PD58

Металлический уголок

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

Пригласил "строителей" которые мне вот так сделали счетчик

Пригласил "строителей" которые мне вот так сделали счетчик

При монтаже кухни я открутил счетчик с трубой чтобы не мешал. И так у меня все отдельно и валялось, всё никак не мог договориться, чтобы пришли красиво все сделали…. Пока не наступил час Ч и не появилось объва о том, что подключают газ, быть всем дома, будет комиссия.

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

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

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

После первой комиссии я засуетился (как по пословице) и мне газовщик сделал все очень красиво, реально, все на швах, все аккуратно — умничка, за что и получил 500 грн, но без техдокументации. После первой, через какое-то время пришла вторая комиссия и сразу мне ВСЕ ЗАБРАКОВАЛА. Сказали, что все сделано не правильно, что по плану квартире счетчик находить не там где надо, что швы и прочее делал необразованный ламер, причем этот мастер работает у них не первый десяток лет)))). Мне поставили заглушку с пломбой — нет тебе газа. И послали меня по адресу, сказали, как сделаешь техдокументацию, все тебе подключат.

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

На следующий день я нашел сайтик http://www.1562.kharkov.ua/ru/article/view/id/137 и позвонил по какому-то из телефонов. Мужчина, который не представился, скзал мне какие документы нужны, после того как я объяснил своё положение.
Документы следующие
1 Техпаспорт на квартиру (оригинал + копия)
2 Документ на право собственности (оригинал + копия)
3 Паспорт и код (оригинал + копия)
4 Разрешение из ЖЭКа на то, что ЖЭК не против моих изменений.

По 4-му пункту у меня были вопросы. Оказывается в квартире мне принадлежит только «воздух», все коммуникации, в частности газопровод, это собственность ЖЭКа и меня его я должен получить разрешение этой службы. Пошел я в свой ЖЭК, переговорил с его руководителем, он сказал, что такого никогда не делал, мол иди так…

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

30.11.2010

Пошел я в эту службу, уже приготовился к самым большим очередям, нервам и тд…, но все оказалось приятней. Нашел кабинет который занимается техдокументацией № 1 прием с 9:30-15, перерывом с 12-13, рабочие дни пн-пт. Объяснил свою проблему девушке, сразу получил отрицательны ответ, мол 1.6 от пола и все, так прописано у них в каких-то ТУ (техническое условие), какой кретин его писал, почему нельзя газовый счетчик поднять до 2-х метров…. единственно объяснение какое я нашел, так это то, что на таком расстоянии трудно выключить газ в случае проблемы…. Спорил я спорил, все хорошо, без нервов. Пока девушка не ушла куда-то с моими документами (техпаспорт и право собственности), через 5 минут она пришла и написала список какие доки мне нужны. К тем которые мне сообщили по телефону еще приписалось обмер диаметра трубы (общей и моего отвода).

Т.к. опять звучал документ — разрешение от ЖЭКа, то я поинтересовался на каком основании от меня это просят, причем этот ЖЭК не общий, а компании-застройщика. Она без всяких нервов, пошерстила в своих копиях и нашла мне и показала номера решений Харьковского городского совет №1186 от 20.12.2006 и №188 от 22.02.2007, по которым я обязан получить такое разрешение, но там четко написано ЖИЛКОМСЕРВИС — это муниципальный ЖЭК, я даже не знаю каким мы боком к ним, но поспорить пока не могу.

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

За сем я и ушел. Теперь собираю документы. Завтра иду в свой ЖЭК получать свой документ.

По мере поступления новостей, буду дописывать эту статью.

02.12.2010

Пошел обратно в свой ЖЭК, начальника не было, но я объяснил ситуацию людям там работающим. Они позвонили по телефон +38 057 763 04 15 в газовую службу и узнали на чьё имя и как писать разрешение. Формат очень простой.

Разрешение ЖЭКа на работу

Разрешение ЖЭКа на работу

07.12.2010

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

Но всё прошло как нельзя лучше. Меня приняла одна из девушек, которой я пояснил свою проблему. Она проверила мои доки и поинтересовалась, где оригинал техпаспорта (нотариус техпаспорта не заверяет). Ответил, что в банке на том вопросы и закончились.

Приступили к выяснению расположения и типа счетчика. Спросила застеклен ли балкон, слава Богу нет, если бы был застеклен то заставили бы снять остекление, т.к. по их ТУ не положено иметь две границы (1 окно на кухне, 2-сам балкон), бред, но куда попрешь против этого тупизма…

Единственная была запарка, что нельзя по ТУ располагать счетчик на высоте 2.1м от пола. Пошла выяснять к начу, предложили следующее — они не будут указывать высоту, а просто сместят положение счетчика на 5 см в бок, ну как бы план изменился — вот новые доки. Вроде все выяснили, спрашивали диаметры труб (был такой пункт в необходимых документах), пропускную способность счетчика (на счетчике G 1.6 написано).

Спросил самое интересное — сколько и как долго?! Ответ меня поразил, сами доки стоят около 100грн!!!!! там 3 квитанции, которые надо оплатить в Сбербанке или к ним в кассу. Срок исполнения 2 месяца, сказали перезвонить через 1.5. Пока вот такие расклады, а меня пугали цифрами в 3000-6000 грн!

10.12.2010

Сегодня оплатил эти квитанции, сканы внизу. Комиссия банка 3 грн с квитанции — итого 9грн.

Квитанция об оплате

Квитанция об оплате 1

Квитанция об оплате 2

Квитанция об оплате 2

Квитанция об оплате 3

Квитанция об оплате 3

10.02.2011

Сегодня уже прошло 2 недели, как мне должны были вернуть документацию, но её еще нет!
Звонил я и в первых числах месяца и сегодня, все отправляют меня на следующую пятницу)), говорят на согласовании у исполнительного директора.
Отныне я буду к ним звонить по 2 раза в день пока не получу свои документы.

18.02.2011

Ура, мой проект с одного отдела перекачивал в другой отдел. Сказали позвонить, опять в пятницу. Ждем.

24.02.2011

Ура, документация сделана. Сказали подъехать забрать и при себе иметь паспорт на газовый счетчик. Я его в жизни не видел, позвонил в ЖЭК сказали, перезвонить, т.к. чувак который за этот ответственный сейчас не на месте. Вот позвоню буду общаться, что мне делать дальше.
Из печального — когда я узнавал что мне делать после получения документов, мне девушка по телефону сказала, что нужно обратиться в монтажный участок, заплатить им 850грн!!!! и они произведут подключение, бля! чё за нах… у меня все полностью подключено!!!!!!!!!! И я буду платить только за то, чтобы мне закрутили вентиль на место…… охренно просто… ну ладно буду ждать, что скажет мой ЖЭК.

01.03.2011

Получил документа. Сделаны прикольно, всё в автокаде, красиво нарисовано, куча всего расписано не жалко 110 грн, которые за это заплатил.

схема проекта

схема проекта

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

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

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

Из более трудных — сертификат на трубы, но оказывается это не проблема. Звоним на металло-базу и узнаем у них. Метр трубы полдюймовой, то что написано в документации стоит 10.56 грн/м, документация дается без проблем. Это документ с завода производителя, где описаны всякие параметры испытаний, в общим этот документ говорит, что труба соот ГОСТу и пригодна для газа.

03.03.2011
Привез всю документацию, приняли, дали 3 счета которые надо оплатить, чтобы далее продлилась работа… Оплачиваю и 10.03.2011 поеду привезу чеки и узнаю что делать далее.

Какое-то техобслуживание

Какое-то техобслуживание

технический надзор

технический надзор

монтажные работы

монтажные работы

12.04.2011
Ура, у меня сегодня супер-пупер новость!!! У нас появился газ. В конторе мне назначили на 12 апреля бригаду которая переварить мне счетчик по моему проекту. Я даже не думал, что они приедут в 9 утра! К этому времени я успел снять только 2 из 4-х ящиков, но это долго времени не заняло. В общем снял, начал объяснять куда я хочу этот ящик, заранее с женой определились куда хотели бы разместить, на высоту в 1.6м ну никак не вписывалось, мы так за это переживали…. но ребята даже и не заикнулись об этой высоте они нас выслушали, посмотрели, подумали и согласились, еще раз все перемеряли. Ребята со снятыми мерками ушли на улицу варить и подготавливать трубы. Пришла какая-то другая бригада, которая отключила стояк от газа и проверяет работу первой бригады на утечки. В общем время шло, дело делалось, все мне приварили, проверили, расписался дал ребятам на чай за их работу и за то что не начали заёб… по поводу 1.6м. Также ребята позвонили в контору и им сказали принять работу полностью и подключить газ!!! Так и сделали и не выезжали всякие там эксперты, которые только и могут про 1.6м говорить, всё пучком.

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

Несколько фоток:

Теперь осталось покрасить в серебряный цвет и труб будет почти не видно.

Теперь осталось покрасить в серебряный цвет и труб будет почти не видно.

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

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

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

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

ЗЫ Следующее на смену — замена однотарифного электрического счетчика на двух-тарифный с целью снизить затраты на электричество из-за повышение оного на 45%.

Статья просмотренна 181603 раз, зашло посетителей 53369

Рекурсивный обход директории с помощью итераторов

Ноябрь15
Обращаю Ваше внимание на загородную недвижимость в области, найдите себе достойное жильё!

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

Для таких целей используется рекурсия.

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

Проход директории с помощью родных методов

К родным (native) методам я отнес функции opendir(), closedir(), readdir() и rewinddir(). Больше казать об этих ф-циях нечего, чистая классика. Открыли каталог (если он существует), получили дескриптор (указатель) на него и начинаем с ним работать, по окончанию желательно закрыть каталог.

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

$dir = 'c:\\windows\\system32';

$odir = opendir($dir);

while (($file = readdir($odir)) !== FALSE)
{
	if ($file != '.' && $file != '..')
	{
		echo $file.'<br>';
	}
}

closedir($odir);

Проход директории с помощью предопределенного класса dir()

Предопределенных классов довольно много, они или являются родными, как класс dir(), Exception, Reflection, или такие которые подключаются с помощью соот. библиотек — mysqli, curl, GD и тд

$cat = dir($dir);

while (($file = $cat->read()) !== FALSE)
{
	if ($file != '.' && $file != '..')
	{
		echo $file.'<br>';
	}
}

$cat->close();

Методы класса dir()

Название метода Описание метода
path путь к директории
handle ресурс, дескриптор
close() закрыть директорию
rewind() сброс дескриптора в начало директории
read() Чтение одного элемента директории и передвигаем указатель на одну позицию вниз.

Проход директории с помощью Итератора (DirectoryIterator)

Что есть итератор хорошо описано в Википедии не буду копи-пастить…

Класс DirectoryIterator реализует интерфейс итератора (могут проходить коллекцию в цикле foreach).

$idir = new DirectoryIterator($dir);

foreach($idir as $file)
{
	if ($file != '.' && $file != '..')
	{
		echo $file->__toString().'<br>';
	}
}

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

Методы класса DirectoryIterator()

Название метода Описание метода
getFilename() возврат имени файла или поддиректории
getBasename() похож на getFilename(), но может удалять суфикс,если таковой передать в виде параметра *
isDot() Определяет является ли текущий элемент «.» или «..»
rewind() сброс указателя на первый элемент
valid() проверка является ли текущий элемент правильным файлом.
Честно не понял.
key() возврат ключа текущего элемента
current() возврат текущего элемента
next() на 1 шаг вперед передвигает указатель
__toString() оопшный метод, приводит свойство к строке
getPath() возврат просто имени директории/файла и все
getPathname() возврат пути к файлу/директории+само название
getPerms() возврат прав доступа только для UNIX
getInode() х.з. что это, судя по названи наверное какое-то имя узла,
думаю только для UNIX
getSize() размер файла в байтах, для директории всегда ноль
getOwner() возврат имя владельца, только для UNIX
getGroup() возврат ИД группы, только для UNIX
getATime() последний доступ к файлу/директории в сек (начало с 1970)
getMTime() последний модификации  файла/директории в сек (начало с 1970)
getCTime() последний изменения к файла/директории в сек (начало с 1970)
getType() возрат dir или file для сотв элемента.
isWritable() думаю понятно из названия, возврат истина/ложь
isReadable() думаю понятно из названия, возврат истина/ложь
isExecutable() думаю понятно из названия, возврат истина/ложь
isFile() думаю понятно из названия, возврат истина/ложь
isDir() думаю понятно из названия, возврат истина/ложь
isLink() думаю понятно из названия, возврат истина/лож,только для  UNIX
getLinkTarget() для данных методов не нашел описание даже на оф.сайте.
getRealPath() для данных методов не нашел описание даже на оф.сайте.
getFileInfo() для данных методов не нашел описание даже на оф.сайте.
getPathInfo() для данных методов не нашел описание даже на оф.сайте.
openFile() для данных методов не нашел описание даже на оф.сайте.
setFileClass() для данных методов не нашел описание даже на оф.сайте.
setInfoClass() для данных методов не нашел описание даже на оф.сайте.

* — за подробностями обращайтесь к официальной документации.

Рекурсивный обход директории с помощью родных методов

Рассмотрев как можно пройтись по директории теперь рассмотри как можно пройтись абсолютно по всему каталогу.

function recursive($dir)
{
	static $deep = 0;

	$odir = opendir($dir);

	while (($file = readdir($odir)) !== FALSE)
	{
		if ($file == '.' || $file == '..')
		{
			continue;
		}
		else
		{
			echo str_repeat('---', $deep).$dir.DIRECTORY_SEPARATOR.$file.'<br>';
		}

		if (is_dir($dir.DIRECTORY_SEPARATOR.$file))
		{
			$deep ++;
			recursive($dir.DIRECTORY_SEPARATOR.$file);
			$deep --;
		}
	}
		closedir($odir);
}

recursive($dir);

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

Рекурсивный обход директории с помощью итератора (RecursiveDirectoryIterator)

Решение для обхода каталога на ООП нашлось и его скрипт ниже.

$rdir = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir), TRUE);

foreach ($rdir as $file)
{
	echo str_repeat('---', $rdir->getDepth()).$file.'<br>';
}

Красиво, всего одна строка, два класса и полный набор данных.

Из существующий методов , которые я уже не привожу, т.к. многие уже описал в других классах (key, current, rewind, valid etc), хотелось бы подчеркнуть метод setMaxDepth(integer); — он позволяет задать глубину прохода.

Другие методы которые есть у данного класса даже не описаны на оф. сайте.

Тесты

Как я их проводил. В цикле (1000) я засекал время перед открытие директории и после её закрытия. Затем я высчитывал среднее арифметическое. Т.к. результаты сильно зависят от железа (винчестера и др параметров), то приводить просто время в секундах не кошерно, поэтому я перевел их проценты. За 100% я принял время работы родных функций.

Проход 1000 раз директории $dir = ‘c:\\windows\\system32’;
native — 100%
dir() — 107%
DirectoryIteratior — 115%

Рекурсия директории $dir = ‘c:\\windows\\system32’;
native — 100%
RecursiveDirectoryIterator — 115%

Как видно нативные почти всегда рулят, но и не так далеко отстают ООПшные фичи.
Кто что будет юзать — уж дело личное.

UPD
Прошу прощения у общественности, я не верно провел тест с рекурсивным обходом.
Вот более детальные данные.
native — 100%
RecursiveDirectoryIterator — 185%

Как видно нативные фичи всегда рулят!

Статья просмотренна 96595 раз, зашло посетителей 26602

Как убрать index.php из адресной строки используя фреймверк Kohana

Октябрь12
Быть красивой легко, загляните в салон-красоты http://salon-aquarelle.ru/.

kohanaСегодня просматривал ключевые слова по каким ко мне попадают на блог и увидел, что есть много вопросов касающихся исключению index.php из урла. Решил написать как это можно сделать.

Когда скачиваете фреймворк Kohana то в корне архива увидите файлик example.htaccess, переименовываем его в .htaccess.

Далее меняем путь к папке в которой установлен фреймворк, если это необходимо, по-дефолту там написано:

RewriteBase /kohana/
я заменил на 
RewriteBase / т.к. у меня весь фрейм лежит в корне

Далее идем в папку в папку application и находим файлик bootstrap.php — это настроечный файл для всего сайта, его изменения важны для сайта, в нем осуществляется первоначальная настройка модулей, роутинга и тд.

Находим в этом файле строчки

/**
 * Initialize Kohana, setting the default options.
 *
 * The following options are available:
 *
 * - string   base_url    path, and optionally domain, of your application   NULL
 * - string   index_file  name of your index file, usually "index.php"       index.php
 * - string   charset     internal character set used for input and output   utf-8
 * - string   cache_dir   set the internal cache directory                   APPPATH/cache
 * - boolean  errors      enable or disable error handling                   TRUE
 * - boolean  profile     enable or disable internal profiling               TRUE
 * - boolean  caching     enable or disable internal caching                 FALSE
 */
Kohana::init(array(
	'base_url'   => '/',
));

и вот чтобы избавиться от вида строки http://example.com/index.php/contoller/action/
на вид http://example.com/contoller/action/

изменяет инициализацию

Kohana::init(array(
    'base_url'   => '/',
    'index_file' =>'',
));

Удачи.

Статья просмотренна 110446 раз, зашло посетителей 28258

Как построить запрос типа WHERE MATCH AGAINST в Kohana3

Сентябрь2

Конструктор запросов

Нравиться мне Фреймворк Kohana, он легкий простой, пока дает все что мне нужно от моих задач.

И вот случилось у меня некая трудность, как я думал в начале, с написание запроса в условиях которого содержится конструкция MATCH(col1, col2,…) AGAINST(»text search»). На данный момент ORM я не юзаю, т.к. не представляю как можно там получить записи при объединении нескольких таблиц, ил запись с таблицы со сложным условием, но то ли еще будет…

Немного отступлю от проблемы, вкратце расскажу, для непосвященных, что это за конструкция. Это конструкция позволяет делать полнотекстовый поиск в наборе указанных полей. Имеет некие настройки для поиска, ищет в указанных полях. Для работы нужна таблица только! типа MyISAM, а также индекс FULLTEXT на искомые поля. Поля должны быть типа VARCHAR, CHAR, TEXT. Более детально на официальной документации.

И так, нужно составить запрос типа:

SELECT * FROM `table` WHERE MATCH(`col1`) AGAINST("search text");

Можно поступить двумя способами.
1 Просто написать такой запрос и запихнуть его в конструкцию:

$data = DB::query(Database::SELECT, 'SELECT * FROM `table`
WHERE MATCH(`col1`) AGAINST("search text")')->execute()->as_array();

В переменной $data у нас будет результат запроса.

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

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

$data = DB::select()->from('table')->execute()->as_array();

Теперь как же быть с условием? Для условий where() существует целый класс Database_Query_Builder_Where в нем содержаться куча методов для построения запросов с логикой AND и OR.
Сам запрос сводиться к 3-м обязательным параметрам:

$db->where('column', 'operator', 'value');
например WHERE id=2 будет записано в виде:
$db->where('id', '=', 2);

Причем если значение это integer кавычек не будет, а если string система сама поставит кавычки.

Вернемся к нашему выражению.

SELECT * FROM `table` WHERE MATCH(`col1`) AGAINST("search text")

Что же здесь у нас столбец, что оператор и что значение??? Поставив такое выражение

$db->where('MATCH(col1)', '', 'AGAINST ("search text")');

я получи вид

WHERE `MATCH(col1)` 'AGAINST(\"search text\")'

естественно запрос не сработал… Немного поразмыслив я попытался обратиться к классу DB::expr(), который позволяет вставить в запрос выражение «как есть», т.е. не обрамляет его символами ` . И вот что получилось:

$query_m = DB::expr(' MATCH(`col1`) ');
$query_a = DB::expr(' AGAINST(addslashes("search text")) ');

$db->where($query_m, '', $query_a);

Естественно при использовании класса DB::expr() приходиться самому заботиться об SQL-инъекциях добавляя ф-цию addslashes, в итоге получилось выражение вида:

WHERE MATCH(`col1`) AGAINST("search text")

И так, подводим итог всей этой ночной писанины:

Для использования в условиях запроса сложных выражений при использовании конструктора запросов, необходимо прибегать к помощи класса DB::expr().
Вот полный пример:

$query_m = DB::expr(' MATCH(col1) ');
$query_a = DB::expr(' AGAINST(addslashes("search text")) ');

DB::select()->from('table')->where($query_m, '', $query_a);

получим запрос вида:

SELECT * FROM `table` WHERE MATCH(col1) AGAINST("search text")

Также можно построить такой запрос:

SELECT * FROM `table` WHERE FIELD_IN_SET('1,2,4,5', `column`);

пишем

$f = DB::expr(' FIND_IN_SET('1,2,4,5', ');
$c = DB::expr(' `column` ');

DB::select()->from('table')->where($f, '', $c);

В итоге

SELECT * FROM `table` WHERE FIELD_IN_SET('1,2,4,5', `column`)

Всем удачи в работе!

Статья просмотренна 114251 раз, зашло посетителей 29189

Создание модуля на фреймворке Kohana

Июль14

В этой статье хочу рассказать как создать свой модуль на фреймворке Kohana.

Что такое модуль, описывается тут

Немного теории

Сам фреймворк имеет 3 основные папки:

application — тут храниться ваш проект
modules — тут модули
system — тут ядро

Все названия папок и файлов, новых и старых, пишутся с маленькой буквы, желательно латинского алфавита, т.к. в методе Kohana::auto_load() все файлы приводятся к нижнему регистру. На это стоит обратить внимание, т.к. на ОС *unix это вылезет и будут потом куча вопросов, а чего у меня (под ОС Windows) работает, а тут нет!!!!! Насчет латиницы, ну тут особых ограничений нет, но принято всё писать латиницей!

Создания модуля

Заходим в папку modules и создаем необходимую нам папку.

Для того, чтобы это было наглядней создадим модуль для получения валюты из центробанка РФ на текущий день (украинского НБУ, не нашел api). Назовем папку модуля — currency (в названии папки можно использовать знак _).

modules

currency

Далее нужно создать простой класс, для какой-то работы, то просто в этой папке его и создаем, например класс назовем Test, значит файл будет называться test.php (расширение должно быть такое, какое описано в index-файле вашего проекта, константа define(‘EXT’, ‘.php’);)

Если же будите использовать MVC паттерн, то надо создать особую структуру папок.

classes -эта папка для классов контроллера и моделей

controller — если есть контроллер, то он храниться тут (назв Controller_Name, файл name.php)

model — тут модель, если есть (Model_Name, name.php)

config — хранятся всяческие настройки для модуля

views — шаблоны для отображения

vendor — библиотеки сторонних производителей

init.php — файл, инициализируемый при подключении модуля

Ессно, что всех этих папок может не быть, это структура папок, скажем по-умолчанию.

Как подключить модуль

Заходим в файл проекта — bootstrap.php и добавляем в описание модулей свой

Kohana::modules(array(
	'auth'       => MODPATH.'auth',       // Basic authentication
	'database'   => MODPATH.'database',   // Database access
	'image'      => MODPATH.'image',      // Image manipulation
	'orm'        => MODPATH.'orm',        // Object Relationship Mapping
	'pagination' => MODPATH.'pagination', // Paging of results
	'cache'      => MODPATH.'cache',      // Cache module
	'currency'	 => MODPATH.'currency',   // Подключения модуля получения валюты!!!!!
));

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

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

Переходим к практике

Структура папок описано, начнем писать.

Описываем файл инициализации init.php:

// Роутеры для работы с валютами
Route::set('currency', 'getcurrency(/<date>)', array('date'=>'([0-9\/]+)'))
    ->defaults(array(
            'controller' => 'currency',
            'action'     => 'index',
            'date'		 => NULL,
    )
);

Далее описываем работу с контроллером Controller_Currency (currency.php):

class Controller_Currency extends Controller {

	/**
	 * Получение данных по указанному дню
	 *
	 * @return void
	 */
	public function action_index()
	{
		$date = $this->request->param('date', date('d/m/Y'));

		$currency_model = new Model_Curr;
		$currency_data = $currency_model->get_currency_from_server($date);

		print_r($currency_data);
	}
}// End Currency Controller

Описываем работу модели Model_Curr (curr.php):

class Model_Curr extends Model {

	/**
	 * Получения данных с сервера ЦБРФ (http://www.cbr.ru/)
	 *
	 * @param string $date текущая дата
	 * @return string
	 */
	public function get_currency_from_server($date)
	{
		$allow_currency = array('EUR', 'USD');
		$link = "http://www.cbr.ru/scripts/XML_daily.asp?date_req=$date";
		$text = @file_get_contents($link);

		$xml = new SimpleXMLElement($text);

		foreach ($xml->Valute as $curr)
		{
			if(in_array($curr->CharCode, $allow_currency))
			{
				$currency[] = $date . ' ' . $curr->CharCode . ' ' . UTF8::str_ireplace(',', '.', (string)$curr->Value);
			}
		}

		return $currency;
	}
} // End Currency Model

В итоге набираем в строке адреса вашего браузера ссылку http://yourprojectname/getcurrency/14/06/2010

и на экране получаем ответ:

Array
(
    [0] => 24/03/2012 USD 29.4038
    [1] => 24/03/2012 EUR 38.8189
)

Демо тут

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

Подводные камни

При работе с модулями могут произойти некоторые проблемки.
1 Если имеется в проекте роутер с таким же урлом как в файле инициализации модуля, то роутер модуля будет замещен роутером проекта.
Для избегания, просто делаем другой роутер или ставим описание роутера проекта раньше чем описание загрузки модулей в файле bootstrap.php.

2 Если одинаковое название моделей, то модель будет вызвана из проекта, а не из модуля!!! Обойти эту проблему мне не удалось, т.к. само ядро ищет файл в проекте и если найдено поиск дальше не идет, а если нет, то ищется пока не будет найдено. Единственный выход — прописать другое название для модели.

UPD: Пересобрал модуль для версии Kohana 3.2, часть комментариев уже не валидны. Через время выложу на github.com

UPD2: Выложил всё на GitHub

Статья просмотренна 102743 раз, зашло посетителей 28195

Работа с функцией GROUP_CONCAT()

Июнь15

Всем привет!

Хочу рассказать о работу с функцией GROUP_CONCAT.

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

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

И так, представим две таблицы, author(авторы) и books(книги авторов).

Заполним данные, ниже представлены две эти таблицы:

Таблица авторов:

CREATE TABLE `author` (
	`id` INT(10) NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(200) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	`fam` VARCHAR(200) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	`birthday` DATE NULL DEFAULT NULL,
	PRIMARY KEY (`id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=3;

Заполняем таблицу:

INSERT INTO `author` (`id`, `name`, `fam`, `birthday`) VALUES (1, 'Николай Николаевич', 'Носов', '2008-11-23');
INSERT INTO `author` (`id`, `name`, `fam`, `birthday`) VALUES (2, 'Артур Конан', 'Дойль', '1859-05-22');

Таблица книг авторов:

CREATE TABLE `books` (
	`id` INT(10) NOT NULL AUTO_INCREMENT,
	`id_author` INT(10) NULL DEFAULT NULL,
	`book` VARCHAR(500) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
	PRIMARY KEY (`id`),
	INDEX `id_author` (`id_author`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=8;

Заполняем таблицу:

INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (1, 1, 'Незнайка учится');
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (2, 1, 'Незнайка-путешественник');
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (3, 1, 'Винтик, Шпунтик и пылесос');
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (4, 2, 'Затерянный мир');
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (5, 2, 'Шерлок Холмс');
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (6, 2, 'Шерлок Холмс');
INSERT INTO `books` (`id`, `id_author`, `book`) VALUES (7, 2, NULL);

Сделаем выборки :

mysql> select * from author;
+----+-------------------------------------+------------+------------+
| id | name                                | fam        | birthday   |
+----+-------------------------------------+------------+------------+
|  1 | Николай Николаевич                  | Носов      | 2008-11-23 |
|  2 | Артур Конан                         | Дойль      | 1859-05-22 |
+----+-------------------------------------+------------+------------+
2 rows in set (0.00 sec)

mysql> select * from books;
+----+-----------+------------------------------------------------+
| id | id_author | book                                           |
+----+-----------+------------------------------------------------+
|  1 |         1 | Незнайка учится                                |
|  2 |         1 | Незнайка-путешественник                        |
|  3 |         1 | Винтик, Шпунтик и пылесос                      |
|  4 |         2 | Затерянный мир                                 |
|  5 |         2 | Шерлок Холмс                                   |
|  6 |         2 | Шерлок Холмс                                   |
|  7 |         2 | NULL                                           |
+----+-----------+------------------------------------------------+
7 rows in set (0.00 sec)

Обратите внимание, во второй выборке я специально добавил дублирующееся поле (Шерлок Холмс) и также поле с NULL записью, для чего это я сделал объясню позже.

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

SELECT a.id, a.name, a.fam,  b.book  as books
FROM `author` a
LEFT JOIN `books` b ON a.id=b.id_author;

В итоге мы получил все книги по всем авторам:

+----+-----------------------+----------+----------------------------+
| id | name                  | fam      | books                      |
+----+-----------------------+----------+----------------------------+
|  1 | Николай Николаевич    | Носов    | Незнайка учится            |
|  1 | Николай Николаевич    | Носов    | Незнайка-путешественник    |
|  1 | Николай Николаевич    | Носов    | Винтик, Шпунтик и пылесос  |
|  2 | Артур Конан           | Дойль    | Затерянный мир             |
|  2 | Артур Конан           | Дойль    | Шерлок Холмс               |
|  2 | Артур Конан           | Дойль    | Шерлок Холмс               |
|  2 | Артур Конан           | Дойль    | NULL                       |
+----+-----------------------+----------+----------------------------+
7 rows in set (0.00 sec)

А мне бы получить записи авторов, т.е. две записи, в нашем случае, и чтобы в поле books были все книги автора…

Это можно сделать применив как раз ф-цию GROUP_CONCAT().
Схема ф-ции:

GROUP_CONCAT([DISTINCT] expr [,expr ...]
             [ORDER BY {unsigned_integer | col_name | expr}
                 [ASC | DESC] [,col_name ...]]
             [SEPARATOR str_val])

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

mysql> SELECT a.id, a.name, a.fam, GROUP_CONCAT(DISTINCT b.book ORDER BY b.book ASC SEPARATOR ', ') AS books
    -> FROM `author` a
    -> LEFT JOIN `books` b ON a.id=b.id_author
    -> GROUP BY a.id;
+----+--------------------+-------+---------------------------------------------------------------------+
| id | name               | fam   | books                                                               |
+----+--------------------+-------+---------------------------------------------------------------------+
|  1 | Николай Николаевич | Носов | Винтик, Шпунтик и пылесос, Незнайка учится, Незнайка-путешественник |
|  2 | Артур Конан        | Дойль | Затерянный мир, Шерлок Холмс                                        |
+----+--------------------+-------+---------------------------------------------------------------------+
2 rows in set (0.05 sec)

Как видно после использование этой ф-ции я получил то, что хотел — дву строчки и в поле books все книги автора.

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

DISTINCT — позволяет выбрать не повторяющиеся значения, т.е. книга с дублирующим названием будет откинута, для этого я ввел дважды название книги Шерлок Холмс;
ORDER BY col_name ASC | DESC — позволяет сортировать данные;
SEPARATOR — позволяет разделить данные через нужный вам делитель, по-умолчанию это запятая «,» (без кавычек)

Также эта функция относится к групповым функциям, поэтому использование её без оператора GROUP BY не желательно, иначе в нашем примере получим одну строку с первым автором в таблице и всеми книгами которые есть в таблице книг.

Есть еще одно ограничение. Кол-во символов которые будут отображены в сгруппированном поле по-умолчанию 1024, если надо больше, то использую переменную group_concat_max_len устанавливаем своё значение:

синатксис:
SET [GLOBAL | SESSION] group_concat_max_len = val;

пример:
SET group_concat_max_len = 2048;

Всем спасибо, в пользу тебе %username%.

Статья просмотренна 267098 раз, зашло посетителей 96305

Попробуем работу с Блогун

Июнь11

БлогунВсем привет!
Вчера я почитал, что есть Блогун.

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

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

Вроде справился — в путь!

Статья просмотренна 48768 раз, зашло посетителей 11159

Работа с Zend_Session

Июнь10

Всем привет! В статье будет рассмотрено работа с сессией средствами ZendFramework.

Простейшая работ с сессией

$sess = new Zend_Session_Namespace('MyNS');

MyNS– название пространства имен, должно быть не NULL, не должен нач. с цифры и _
Если пространство имен не задано, то по умолчанию Default

Данная конструкция аналогична

$_SESSION[‘MyNS’]

Добавления данных в сессию:

$sess->someData = 'some info';    аналог $_SESSION['MyNS']['someData'] = 'some info'; 

Получение название пространства имен:

$sess->getNamespace();

Доступны магические методы

__isset(), __unset(), __get(), __set()

Расширенная работа сессий

Время жизни пространства имен

$sess = new Zend_Session_Namespace('MyNS');
$sess->someData = 'some info';

$sess->setExpirationSeconds(5, 'someData'); - время жизни ключа someData будет 5 сек
$sess->setExpirationSeconds(3); - время жизни пространства имен Dialog будет 3 сек

$sess->setExpirationHops(5 , 'someData');  - через 5 успешных обращений к ПИ (NS) someData будет удалена
$sess->setExpirationHops(3); - через 3 «прыжка» всё ПИ будет удалено

Работа с массивами в пространствах имен

$sess = new Zend_Session_Namespace('MyNS');
$sess->array = array();
$sess->array['testKey'] = 1; // Не работает в версиях ниже PHP 5.2.1

Хранение сессии в БД

Если Вы используете высоко нагруженное веб-приложение и у вас стоит несколько серверов и есть аппаратные/программные средства по контролю за нагрузкой, то каждая страница может обрабатывать разные сервера, вспомним сайт Одноклассники. Из-за этого файл сессии может быть недоступен. Для устранения такой проблемы можно использовать хранение сессии в БД.
Вообще PHP позволяет переопределить место хранения сессии, переопределить ф-ции которые отвечают за открытие, закрытие, запись и тд сессии, за это отвечает ф-ция session_set_save_handler

Вот пример использования сессии средствами Зенда:

Создаем таблицу в БД
CREATE TABLE `session` (
  `id` char(32),
  `modified` int,
  `lifetime` int,
  `data` text,
  PRIMARY KEY (`id`)
);

настраиваем Zend:

$db = DbManager::getInstance(); // тут получения объекта подключения к БД (у каждого может быть свой)
Zend_Db_Table_Abstract::setDefaultAdapter($db);

$config = array(
    'name'           => 'session',
    'primary'        => 'id',
    'modifiedColumn' => 'modified',
    'dataColumn'     => 'data',
    'lifetimeColumn' => 'lifetime'
);
 
Zend_Session::setSaveHandler(new Zend_Session_SaveHandler_DbTable($config));
 
Zend_Session::start();

// дальнейшая работа с сессией

Статья просмотренна 49103 раз, зашло посетителей 12204

Вчера мне исполнилось 32 года

Май20

Всем привет!

Все наверняка слышали выражение:»Отмечали всем селом». Так вот я могу сказать, вчера отмечал со всем подъездом)). Не удивляйтесь, дом новый, пока постоянно живут 5 пар в подъезде.

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

Подарили прикольные подарочки, особенно сильно понравился подарок дочки, она начала писать стихи:

У папы День Рожденья,
Любимый День Варенья.
Желаем мы все дружно
Того, что очень нужно.
Здоровья, счастья, радости
Поешь побольше сладостей
Будь добрый, милый, жизнерадостный
Веселый и загадочный
Побольше ешь варенья 
И еще раз "С Днем Рожденья!!!"

Дальше фотки:

Решили открыть наше свадебное шампанское

Решили открыть наше свадебное шампанское

Разливаем

Разливаем

Мои детки

Мои детки

Статья просмотренна 34194 раз, зашло посетителей 8568

 « предыдущие статьи 

Облако тегов

cli csv dump events form Kohana locale models MySQL mysqldump orm PHP tools trigger validate газ газовый счетчик итоги кеширование переменные

Облако тегов плагина WP Cumulus для WordPress требует для просмотра Flash Player 9 или выше.

Я на твиттере!

  • у твиттера тоже бывают перерывы...

Календарь

Апрель 2024
Пн Вт Ср Чт Пт Сб Вс
« Июл    
1234567
891011121314
15161718192021
22232425262728
2930  

Сейчас на сайте