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


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

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

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

[Из песочницы] Индивидуальный дневной лимит на исходящие звонки (ограничение платных направлений)

Пятница, 19 Августа 2016 г. 08:32 (ссылка)

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



Предыстория



Есть группа сотрудников, которая занимается обзвоном клиентов. Дабы экономить на исходящих звонках, для разных направлений используются разные номера телефонов. Это спокойно решается с помощью шаблонов (масок) номеров в Outbound Routes. Но часть направлений, например, звонки на мобильные, остается платным. Чтобы в конце месяца счет компании за телефонные услуги не перевалил XXX$, необходимо жестко контролировать и, при необходимости, ограничивать соответствующие направления звонков.



Задача



Установить индивидуальный дневной лимит для группы менедежеров. Запретить исходящие звонки на определенные направления при исчерпании лимита. При достижении пороговых значение: >50%, >90% и >100% отправлять соответствующее уведомление на email сотрудника. Если сотрудник в течении дня полностью не исчерпал свой дневной лимит, остаток должен перейти на следующий день.



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



Для начала нужно определить на какие номера мы ограничиваем дозвон. В нашем случае это мобильные операторы Казахстана. Находим соответствующую статью в Википедии и стараемся сформировать шаблоны (маски) номеров. Так как FreePBX не имеет возможности использовать полноценные регулярные выражения, 23 возможных префикса нам удалось упаковать в 3 шаблона:


  • 870[5780-2]XXXXXXX

  • 877[15-8]XXXXXXX

  • 8747XXXXXXX



Создаем соответствующие записи в Outbound Routes. На данном примере открываем направления для внутреннего номера 2055:







Делаем это для того, чтобы соответствующие правила создались в конфигурационном файле:
/etc/asterisk/extensions_additional.conf 


Так как при редактировании и применении настроек во FreePBX, система каждый раз переписывает конфигурационные файлы, мы находим нужные нам блоки и перемещаем в файл:
/etc/asterisk/extensions_custom.conf
в который FreePBX не лезет.



Блок следующего вида:



Outbound Routes
exten => _877[15-8]XXXXXXX,1,Macro(user-callerid,LIMIT,EXTERNAL,)
exten => _877[15-8]XXXXXXX/2055,1,Macro(user-callerid,LIMIT,EXTERNAL,)
exten => _877[15-8]XXXXXXX/2055,n,ExecIf($[ "${CALLEE_ACCOUNCODE}" != "" ] ?Set(CDR(accountcode)=${CALLEE_ACCOUNCODE}))
exten => _877[15-8]XXXXXXX/2055,n,Set(MOHCLASS=${IF($["${MOHCLASS}"=""]?default:${MOHCLASS})})
exten => _877[15-8]XXXXXXX/2055,n,ExecIf($["${KEEPCID}"!="TRUE" & ${LEN(${TRUNKCIDOVERRIDE})}=0]?Set(TRUNKCIDOVERRIDE=<7123456789>))
exten => _877[15-8]XXXXXXX/2055,n,Set(_NODEST=)
exten => _877[15-8]XXXXXXX/2055,n,Gosub(sub-record-check,s,1(out,${EXTEN},))
exten => _877[15-8]XXXXXXX/2055,n,Macro(dialout-trunk,10,${EXTEN},,off)
exten => _877[15-8]XXXXXXX/2055,n,Macro(outisbusy,)




Если вы дружите с синтаксисом конфигов Asterisk'а, можно пропустить два предыдущих шага и сформировать нужные вам блоки самостоятельно.



Теперь можно удалить созданные ранее Outbound Routes, нужные нам разрешающие правила теперь содержатся в extensions_custom.conf. Таким образом, мы разрешили сотрудникам звонить по этим направлениям. Дальше больше.



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


  • использовать существующую базу данных asterisk, и добавить необходимые нам поля в таблицу users;

  • создать свою базу данных с таблицами нужной структуры.



Выбор пал на вариант№2, и получилось примерно следующее:

SQL Create table
CREATE TABLE `users` (
`user_id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'ФИО пользователя',
`extension` varchar(5) CHARACTER SET utf8 DEFAULT '000' COMMENT 'Внутренний номер абонента',
`mobile_limit_flag` int(11) DEFAULT '0' COMMENT 'Флаг для учета текущего лимита',
`mobile_limit` int(11) DEFAULT '0' COMMENT 'Текущий лимит',
`base_mobile_limit` int(11) DEFAULT NULL COMMENT 'Базовый лимит',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci




Описание основных параметров:


  • base_mobile_limit хранит индивидуальный лимит абонента (в секундах), устанавливается единовременно;

  • mobile_limit содержит текущий лимит на текущий день, с учетом не израсходованных минут;

  • mobile_limit_flag определяет какой порог исчерпания лимита преодолел пользователь (0 — <50%, 1 — >50 и <90%, 2 — >90% и <100%, 3 — >100%);



Создадим Васю Пупкина, с уже известным нам внутренним номером 2055.







Приступаем к формированию основной системы, логика следующая:


  • по расписанию (по крону) скрипт проверяет сколько наговорил каждый абонент по нужным нам направлениям;

  • если абонент перешел порог 0,1 или 2, параметр mobile_limit_flag меняется на соответствующий и отправляется сообщение на email;

  • если абонент оказался на пороге 3 (лимит полностью исчерпан), отправляется соответствующее уведомление на email, в конфигурационном файле комментируется соответствующий блок, выполняется dialplan reload.



Для хранения позиций блоков соответствующих внутренних номеров, сформируем XML файл следующего вида:



XML























Так как мы создали три маски для выхода на мобильные номера, для каждого внутреннего номера будет по три разрешающих блока. В XML мы указываем номера строк начала и конца каждого из этих блоков. Комментируем их с помощью следующего кода:



Функция комментирования блока
def commentBlocks(numb):
import xml.etree.cElementTree as ET
tree = ET.ElementTree(file='conf.xml')
root = tree.getroot()
f = open(r'extensions_custom.conf')
lines = f.readlines()
f.close()
for elem in tree.iterfind('block[@number="'+numb+'"]/element'):
lines[int(elem.get('first'))-2] = ";--\n"
lines[int(elem.get('last'))] = "--;\n"
f = open(r'extensions_custom.conf','w')
f.writelines(lines)
f.close()




И собственно основные мозги:



Main script
Дергается по расписанию, например, каждые 5 минут. Бонусом великолепный SQL запрос, и божественный код.

#мои функции
import send_email
import flags

print ('###########START_MOBILE_LIMIT############')

import pymysql
mainconn = pymysql.connect(host='10.10.2.1', user='user', passwd='password', db='asteriskcdrdb', charset='utf8')
maincur = mainconn.cursor()
maincur.execute("""SELECT SUM(billsec) AS sec, src
FROM cdr WHERE disposition = 'ANSWERED'
AND (dst LIKE '8700%' OR dst LIKE '8701%'
OR dst LIKE '8702%' OR dst LIKE '8705%' OR dst LIKE '8707%'
OR dst LIKE '8708%' OR dst LIKE '8747%' OR dst LIKE '8771%'
OR dst LIKE '8775%' OR dst LIKE '8776%' OR dst LIKE '8777%'
OR dst LIKE '8778%') AND DATE(calldate) = DATE(CURDATE())
AND src in (2055,2066,2077)
GROUP BY src;""")

row = maincur.fetchone()

print ('ROW COUNT: ' + str(self.maincur.rowcount))

while row is not None:

#row[1] - внутренний номер
#row[0] - исчерпанный лимит в секундах

#изменяем текущий лимит
flags.UpdateUserCurrentLimit(str(row[1]), str(row[0]))

per = row[0] * 100 / flags.checkUserLimit(row[1])
flag = flags.checkFlag(row[1])
#вытаскиваем почтовый ящик абонента, ищем его по внутреннему номеру
manager_mail = send_email.getEmail(row[1])

#показываем % израсходонного трафика
print (row[1] + ' (' + str(round(per,0)) + '%): ' + str(row[0]))

#проверяем порог
if per >= 50 and per < 90:
message = 'Nomer ' + row[1] + ', limit ischerpan na ' + str(round(per, 0)) + '%'
if flag == 0:
print ('go email to ' + send_email.getEmail(row[1]))
send_email.send_message(manager_mail, message)
flags.changeFlag(row[1], 1)
flags.insertLog(row[1], per)
print (message)
elif per > 90 and per < 100:
message = 'Nomer ' + row[1] + ', limit ischerpan na ' + str(round(per, 0)) + '%'
if flag == 1:
print ('go email to ' + send_email.getEmail(row[1]))
send_email.send_message(manager_mail, message)
flags.changeFlag(row[1], 2)
flags.insertLog(row[1], per)
print (message)
elif per >= 100:
message = 'Nomer ' + row[1] + ', limit polnostiu ischerpan'
if flag != 3:
print ('go email to ' + send_email.getEmail(row[1]))
send_email.send_message(manager_mail, message)
flags.changeFlag(row[1], 3)
flags.insertLog(row[1], per)
#комментируем соответствующие блоки в конфиге
flags.commentBlocks(str(row[1]))
import subprocess
#дергаем диалплан чтобы применить настройки
subprocess.call(['./dialplan_reload.sh'])
print (message)

row = maincur.fetchone()

maincur.close()
mainconn.close()

print ('############END_MOBILE_LIMIT#############')




В конце рабочего дня мы добавляем неиспользуемый лимит:



AddUnusedLimit
def AddUnusedLimit(ext):
conn = pymysql.connect(host='10.10.2.2', user='user', passwd='password', db='crm', charset='utf8')
cur = conn.cursor()

cur.execute ("""
UPDATE users
SET mobile_limit=base_mobile_limit+mobile_limit WHERE extension=%s
""", (ext))

conn.commit()
print('changed', cur.rowcount)
cur.close()
conn.close()




Сбрасываем mobile_limit_flag на дефолтное значение 0 и раскоменчиваем все блоки:



uncommentBlocks
def uncommentBlocks():
import xml.etree.cElementTree as ET
tree = ET.ElementTree(file='conf.xml')
root = tree.getroot()
for elem in tree.iterfind('block/element'):
first = int(elem.get('first'))
last = int(elem.get('last'))
lines[first-2] = "\n"
lines[last] = "\n"
f = open(r'/etc/asterisk/extensions_custom.conf')
lines = f.readlines()
f.close()

############################################

cur.execute ("""
UPDATE users
SET mobile_limit_flag=%s
""", (0))




Для решения возможных спорных ситуаций, пишем в лог данные об изменении порога лимита:



LOG
#функция логирования израсходованного лимита
def insertLog(ext, per):
import pymysql
conn = pymysql.connect(host='10.10.2.1', user='user', passwd='password', db='crm', charset='utf8')
cur = conn.cursor()

cur.execute ("""
INSERT INTO mobile_limit
(extension, percent)
VALUES (%s, %s)
""", (ext, per))

conn.commit()
print('insert', cur.rowcount)
cur.close()
conn.close()




Вот такое кривое решение поставленной задачи. В версии скрипта 2.0 мы будем динамически формировать разрешающие блоки, что позволит более гибко использовать систему, при каких-либо изменениях.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/308086/

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

Видео докладов с DevConf 2016

Среда, 27 Июля 2016 г. 15:39 (ссылка)

17-го июня в инновационном центре “Сколково” прошла очередная ежегодная конференция DevConf, а Badoo в очередной раз снимали видео выступлений. Программа была богата на именитых спикеров и интересные доклады, поэтому сделать подборку из самых «вкусных» выступлений было крайне сложно. Но мы, как минимум, постарались…



Познавательного вам просмотра!



«Развитие ветки PHP-7», Дмитрии

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

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

Релиз DataGrip 2016.2: Импорт CSV, поддержка JSON и XML в строках, динамический SQL, улучшения для PostgreSQL

Четверг, 21 Июля 2016 г. 16:18 (ссылка)

Привет! У нас пора релизов. Это пост о том, что интересного в новой версии DataGrip — нашей IDE для SQL. Эти изменения также касаются IntelliJ IDEA, PyCharm, PhpStorm и RubyMine — тех инструментов от JetBrains, где есть поддержка баз данных.



image



Вот, что мы добавили:







Импорт CSV



Старый способ был неудобный. Мы добавили интерфейс для импорта — теперь выбирайте из контекстного меню источника данных пункт Import from file…, указывайте путь к файлу и вперёд.



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







Выбор схем



Схемы, которые вы видите в окне базы данных теперь выбирайте прямо из дерева. Во вкладке Schemas свойств источника данных их больше нет. Помните, что консоль знает только об объектах из этого дерева.







Поддержка языков в строковых литералах



Строковому литералу можно присвоить определённый язык и пользоваться возможностями IDE по работе с ним — подсветкой, автодополнением и другими. Это может быть JSON, XML, регулярные выражения или любой диалект SQL.

Когда DataGrip понимает, что в поле содержатся JSON данные или XML — поддержка осуществляется автоматически.



Скажем, мы вставляем значение в поле типа JSON.







Если вы указываете значение для поля по умолчанию, происходит то же самое — здесь IDE поняла, что вы используете XML, и возможности по работе с этим языком стали доступны. Это переименование элементов, поиск вхождений, движение элементов в стороны и т. д. Не забудьте заглянуть на страницу документации о поддержке XML в наших инструментах.







По умолчанию встроены только два типа, для которых языки поддерживаются автоматически, — JSON и XML. Но если у вас есть тип данных, для которого вы хотите иметь то же самое, то выберите Inject by Type из меню подсказок по Alt+Enter.







В примере используется тип CUSTOMDATA, но, допустим, у нас всегда используется XML для типов, имя которых заканчивается на DATA. Имя типов, для которых будет осуществляться автоматическая поддержка, описывается в регулярном выражении (?i).*DATA. Можно на ходу проверить, соответствует ли шаблону та или иная строка, в данном случае — имя вашего типа.







Шаблоны имен типов для поддержки языков в литералах попадают в Settings/Preferences -> Editor -> Language Injections.







Проверить строку на соответствие регулярному выражению можно теперь где угодно. По Alt+Enter укажите соответствующий язык, а потом опять по Alt+Enter выберите Check Regexp.







Ещё один способ сообщить среде о языке в строковом литерале — комментарий вида language=%name%. В следующем примере применён динамический SQL — внутри строки заработало автодополнение и навигация: среда поняла, какие объекты используются в запросе внутри строки.







Табличный редактор



Для значений внутри таблицы мы добавили дополнение по значениям в поле, которое вызывается по Ctrl(Cmd)+Space. Это напоминает уже существующий тип дополнения, который вызывается по Alt+/, — оно ищет по всем используемым словам во всех открытых файлах.







Специфические улучшения для PostgreSQL: можно редактировать поля с типами range.







И поля с временными зонами.







Размер столбцов теперь меняется по Ctrl(Cmd)+Shift+Left/Right. Все столбцы выделяйте по Shift+Space, как в Excel.







Консоль



Как и все другие среды разработки на платформе IntelliJ, мы теперь поддерживаем лигатуры. Для этого их должен поддерживать и сам шрифт, который вы установите. Это могут быть FiraCode, Hasklig, Monoid или PragmataPro.







Получается вот что:







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







В меню Surround with (Ctrl/Cmd+Alt+T) появился пункт Surround with function — выбранные выражения возьмутся в скобки, а курсор будет помещен перед первой скобкой. Раньше эта штука не работала с мультикурсорами, теперь все нормально.







Для PostgreSQL мы поддержали search path — добавляйте и удаляйте схемы из меню в верхней части консоли.







Подключение



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







В прошлый раз было много комментариев о проблемах с подключением к SQL Server. Мы написали небольшое руководство по решению основных проблем с этим.



Перекомпиляция пакетов в Oracle



Соответствующий пункт добавлен в контекстном меню, причем перекомпилировать можно только те пакеты, которые в этом нуждаются. Для этого выберите Invalid objects only.







Экспорт схемы



Теперь можно экспортировать сразу всю схему или выбранные таблицы. Мы начали работу по интеграции DataGrip с внешними инструментами pg_dump и mysqldump, так что пишите пожелания в комментариях!







Изображения как фон IDE



В меню Find Action (Ctrl(Cmd)+Shift+A) найдите Set Background Image или выберите соответствующий пункт контекстного меню файла с изображением. Затем настройте прозрачность и другие параметры фона. Это появилось во всех IDE на платформе IntelliJ.







Если хотите узнать больше, добро пожаловать на страницу What’s new, и не забудьте заглянуть в Features, вдруг чего-то не знали?



Будем рады, если вы попробуете DataGrip 2016.2 и расскажете о впечатлениях, пока мы готовим первое небольшое обновление.



Команда DataGrip.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/306152/

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

[Из песочницы] ORM на php для MySQL реальность (часть первая)

Воскресенье, 17 Июля 2016 г. 10:52 (ссылка)

После долгих поисков интересующей меня библиотеки на php для связи с MySQL сел и написал свою, наиболее подходящую для использования в проектах. Данная тема займет небольшой цикл статей, который будет полезен не только профессиональным разработчикам веб-приложений, но и начинающим. Следует отметить, что представленная ниже ORM библиотека, которую, кстати, я назвал kitty, является результатом долгих мучений и не является обязательной библиотекой всех проектов.



Библиотека по моему видению должна иметь два файла (по крайней мере на начальных этапах):


  • файл библиотеки — kitty.php;

  • файл объектного изображения модели базы данных — modeldb.php.





Начнем с последнего. Файл изображения базы данных должен в себе содержать классы, по названию схожие с названием таблиц и содержать в себе поля в соответствии со столбцами таблиц. Т.е. если у нас есть таблица authors с полями idauthor,Name,Year (Идентификатор, ФИО, Годы жизни), то класс будет выглядеть следующим образом:

class authors extends kitty {
public $idauthor;
public $Name;
public $Year;
}


Идентификатор должен следовать первым.



Обычно, класс изображения базы данных содержит в себе все таблицы, которые kitty генерирует автоматически, но об этом позже (все в данной статье не уместишь), и подключается после kitty. А теперь приступим к самому интересному, к нашей библиотеке.



Свойства класса kitty



Класс kitty является абстрактным классом и имеет в своем составе (по моему видению) два ключевых свойства:

	private static $db;	//Объект базы данных
private static $stack; //Стэк запросов


Экземпляр класса $db хранит в себе подключение к базе данных, используя улучшенных класс mysqli.

Экземпляр класса $stack хранит в себе стек запросов и результаты этих запросов, используя класс SplStack.

На этом свойства закончились, все лаконично и просто, теперь перейдем к сладкому.



Методы класса kitty



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

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



Статические методы



Ключевым статическим методом для соединения с базой данных является setup:

	static public function setup(mysqli $dbi,$enc = "utf8"){
if (is_object($dbi)){
self::$db = $dbi;
self::$stack = new SplStack(); //Стэк запросов
return self::setEncoding($enc); //Запрос на кодировку
}else{
throw new Exception("Параметр $dbi не является объектом mysqli", 1);
return false;
}
}


В качестве параметра мы передаем экземпляр класса mysqli и кодировку, которая по умолчанию является utf8. При инициализации заносится экземпляр MySQLi и стек. Результатом ответа является запрос, т.е. проверка на корректность соединения. Строчка kitty::setup(new mysqli) является единственной настройкой библиотеки.

Кодировка устанавливается запросом setEncoding. Код метода представлен ниже:

	static function setEncoding($enc){
$result = self::$db->query("SET NAMES '$enc'"); //Отправляем запрос
self::$stack->push("SET NAMES '$enc' [".($result ? "TRUE" : self::getError())."]");
return $result ? true : false; //Возвращаем ответ
}


В случае возникновения ошибки, заносим в стек запрос и ошибку, и соответственно возвращаем false.

Функция получения ошибки очень лаконичная:

	static function getError(){
return self::$db->error." [".self::$db->errno."]";
}


Возвращаем текст ошибки (error) и код ошибки (errno).



Каждая, уважающая себя, ORM библиотека должна содержать экранирование (к.т.н., доц. Ковженкин В.С.)




Эту возможность реализует функция mysqli_real_escape_string, но она является длинной и принимает два параметра. Заменим, для удобства, эту функцию на представленную ниже:

	private static function escape($string) {
return mysqli_real_escape_string(self::$db,$string);
}


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



Чтобы выбрать поля таблицы, а конкретней свойства класса таблицы, воcпользуемся средствами php для работы с классами.

Код функции представлен ниже:

	private static function _getVars(){
return array_filter(get_class_vars(get_called_class()),function($elem){
if (!is_object($elem)) return true;
});
}


Функция забирает все свойства и фильтрует их. Если свойство является объектом, а она выбирает еще stack и db, то оно не входит. На выходе массив с полями таблицы. При вызове authors::_getVars(); функция вернет массив array(«idauthor»,«Name»,«Year»).



Выборка данных



Выборка данных является щекотливой темой для ORM библиотек и возникает вопрос, как данные доставать и как их представлять.

В текущей статье мы рассмотрим только один вариант запроса.



Метод является статическим и выбирает из базы данных один экземпляр по идентификатору (findID).

Код функции представлен ниже:

	static function findID($id){
if (is_numeric($id)){ //Если число, то ищем по идентификатору
$query = "SELECT * FROM `".get_called_class()."` WHERE `".key(self::_getVars())."` = $id LIMIT 1";
$result = self::$db->query($query); //Отправляем запрос
self::$stack->push($query." [".$result->num_rows."]"); //Заносим запрос в стек
if ($result->num_rows == 1){ //Если запрос вернул строку
$row = $result->fetch_object(); //Строку запроса в класс
$cName = get_called_class(); //Получем название класса
$rClass = new $cName(); //Создаем экземпляр класса
foreach ($row as $key => $value) $rClass->$key = $value; //Переносим свойства класса
return $rClass; //Возвращаем класс
} else return false; //Если строка не найдена, то ложь
} else return false; //Если не число возвращаем ложь
}


Код подробно описан комментариями и не требует дополнительного описания.

Получить экземпляр можно следующим образом:

    $auth = authors::findID(2);
if ($auth){
//Действия
}else{
//Если не найден
}




Не статические методы



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

Выше мы выбрали экземпляр автора с идентификатором 2. Если запрос успешно выполнится, то у нас окажется экземпляр класса:

    $auth->idauthor = 2;
$auth->Name = "Тургенев Иван Сергеевич";
$auth->Year = "1818—1883";


Изменять параметры очень просто, а как же сохранять?

Сохранять так же просто. Ниже представлен код функции для сохранения:

	public function Save(){									//Сохраняем объект - UPDATE	
$id = key(self::_getVars()); //Получаем идентификатор
if (!isset($this->$id) || empty($this->$id)) return $this->Add(); //Если пусто, добавляем
$query = "UPDATE `".get_called_class()."` SET "; //Формируем запрос
$columns = self::_getVars(); //Получем колонки таблицы
$Update = array(); //Массив обновления
foreach ($columns as $k => $v) { //перебираем все колонки
if ($id != $k) //Убираем идентификатор из запроса
$Update[] = "`".$k."` = ".self::RenderField($this->$k); //Оборачиваем в оболочки
}
$query .= join(", ",$Update); //Дополняем запрос данными
$query .= " WHERE `$id` = ".self::escape($this->$id)." LIMIT 1"; //Дополняем запрос уточнениями
$result = self::$db->query($query);
self::$stack->push($query." [".($result ? "TRUE" : self::getError())."]"); //Стек результатов
return ($result) ? true : false; //Возвращаем ответ
}


Код оснащен комментариями и дополнительного описания не требует. Для изменения имени в соответствии с предыдущим примером необходимо выполнить следующий код:

        $auth->Name = "Толстой Лев Николаевич";
echo $auth->Save() ? "Успешно" : "Запрос не удался((";




Функция Save имеет в себе замечательную функцию RenderField. Функция очень важная, является статической и отвечает за правильность построения запроса, ее код представлен ниже:

	private static function RenderField($field){
$r = ""; //Строка для возвращения
switch (gettype($field)) { //Селектор типа передаваемого поля
case "integer": case "float": //Тип int или float
$r = $field;
break;
case "NULL": $r = "NULL"; break; //Тип NULL
case "boolean": $r = ($field) ? "true" : "false"; break; //Тип boolean
case "string": //если тип строковой
$p_function = "/^[a-zA-Z_]+\((.)*\)/"; //Шаблон на функцию
preg_match($p_function, $field,$mathes); //Поиск соврадений на функцию
if (isset($mathes[0])){ //Совпадения есть, это функция
$p_value = "/\((.+)\)/"; //Шаблон для выборки значения функции
preg_match($p_value, $field,$mValue); //Выборка значений
if (isset($mValue[0]) && !empty($mValue[0])){ //Если данные между скобок существуют и не пустые
$pv = trim($mValue[0],"()"); //Убираем скобки по концам
$pv = "'".self::escape($pv)."'"; //Экранируем то что в скобках
$r = preg_replace($p_value, "($pv)" , $field); //Меняем под функцию
}
else $r = $field; //Возвращаем функцию без параметров
}
else $r = "'".self::escape($field)."'"; //Если просто строка экранируем
break;
default: $r = "'".self::escape($field)."'"; break; //По умолчанию экранируем
}
return $r; //Возвращаем результат
}


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



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

       $auth = new authors();
$auth->Name = "Тургеньев Иван Сергеевич";
$auth->Year = "1918-1983";
$auth->Add();




Код функции добавления представлен ниже:

	public function Add(){									//Добавляем объект - INSERT
$query = "INSERT INTO `".get_called_class()."` ("; //Подготавливаем запрос
$columns = self::_getVars(); //Получем колонки
$q_column = array(); //Массив полей для вставки
$q_data = array(); //Массив данных для вставки
foreach ($columns as $k => $v){ //Пробегаемся по столбцам
$q_column[] = "`".$k."`"; //Обертываем в кавычки
$q_data[] = self::RenderField($this->$k); //Рендерим обертку для данных
}
$query .= join(", ",$q_column).") VALUES ("; //Дополняем запрос столбцами
$query .= join(", ",$q_data).")"; //Дополняем запрос данными
$result = self::$db->query($query); //Делаем запрос
$insert_id = self::$db->insert_id; //Получаем идентификатор вставки
self::$stack->push($query." [".($result ? $insert_id : self::getError())."]"); //Стек результатов
return ($result) ? $insert_id : false; //Возвращаем ответ
}




Удаление объекта



Ну и напоследок удаление. В php нет функции delete и мы не будем нарушать традиции, поэтому назовем метод Remove();

Чтобы удалить запись автора из предыдущих примеров, необходимо выполнить код:

        $auth = authors::findID(2);
$auth->Remove();


Выбираем экземпляр и удаляем. Все очень просто и лаконично! Код функции для удаления представлен ниже:

	public function Remove(){								//Удаляем объект - DELETE
$id = key(self::_getVars()); //Выбираем идентификатор
if (!empty($this->$id)){ //Если идентификатор не пустой
$qDel = "DELETE FROM `".get_called_class()."` WHERE `$id` = ".$this->$id." LIMIT 1";
$rDel = self::$db->query($qDel); //Запрос на удаление
self::$stack->push($qDel." [".($rDel ? "TRUE" : self::getError())."]"); //Стек результатов
return $rDel ? true:false; //Возвращаем ответ
} else return false; //Отрицательный ответ
}




Данная ORM библиотека не является монстром современного мира, тем более писать я ее только начал, но вполне подходит для использования в небольших проектах. В следующей будет рассмотрено автоматическое генерирование модели базы данных.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/305786/

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

Технозавтрак «Эффективная работа с Percona Server for MySQL на высоконагруженных веб-кластерных проектах»

Понедельник, 11 Июля 2016 г. 16:51 (ссылка)





1. Мы в Битриксе очень любим делиться знаниями.

2. Мы любим использовать Percona Server вместо стандартного MySQL.

3. Иногда мы проводим бизнес-завтраки.



Соединив все эти факты вместе, мы решили провести техно-завтрак. :) Специальный гость — Петр Зайцев, директор Percona.



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



Подробности — под катом.



Ключевая тема мероприятия — нюансы использования MySQL / Percona в высоконагруженных проектах.



О чем будем говорить:



— Максимальная производительность и отказоустойчивость БД.

— Особенности решений Percona для оптимизации работы вашей БД.

— Использование master-master репликации для построения геораспределенного отказоустойчивого веб-кластера.

— Особенности работы Percona Server в облачной инфраструктуре.

— Как работать с тысячами баз на одном сервере.

— Расширенный мониторинг типичных и необычных характеристик БД.

— Практическое применение инструментов Percona Toolkit.



Отдельно расскажем о программе миграции решений «1С-Битрикс» с MSSQL и ORACLE Database на MySQL.



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



13 июля. 10:00. Регистрируйтесь и участвуйте!

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/305424/

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

Следующие 30  »

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

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

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