Исправлена проблема в последних Chrome, из-за которой страница не перезагружалась после её редактирования, а также не закрывалась страница удаления. В последних версиях Chrome не передаёт window.opener при открытии обычных ссылок, поэтому страницы редактирования теперь открываются при помощи window.open()
.
27.04.2021
Изменено обращение к подстроке с фигурных скобок на квадратные (DEPRECATION ошибка в PHP 7.4)
18.04.2021
Методы stub
и fetch_column
для ActiveRecord
stub возвращает "пустой" элемент ActiveRecord, fetch_column - быстро получает массив значений по одному столбцу.
28.01.2019
Поддержка .ini
и .ini.ini
файлов в директориях без "mod_" в имени.
12.09.2018
Новый формат блоков в файлах "*.ini"
.
Должен начинаться со знака {
и заканчиваться на }
. Будет сохранен как ассоциативный массив под числовым индексом в предыдущем объявленном блоке ([block]
);
Пример: имеем файл mydata.init.ini
со следующим содержимым:
[admin.menu.content]
;Можно перемешивать с обычными блоками
pages "Текстовые страницы"
;Разрешены знаки вопроса в значениях
;Разрешены отступы (табуляция и пробел)
{
link= /admin/?le=1
title=Управление опциями
},
;Запятая после блока допустима, но не обязательна
;Отступы не обязательны
{
link= /admin/?le=2
title=Управление товарами
}
{
link= /admin/?le=3
;Поддерживается вложенность ключей
title.usual=Управление Меню
title.advanced=Управление Конфигурацией
}
;Поддерживается вложенный JSON
{
content = json: ["a", "b", "c"]
}
Итоговый массив d()->admin
(включая опции, заданные в admin.ini
), полученный через json_encode(d()->admin , JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );
, будет иметь следующий вид:
{
"menu": {
"content": [
[
"pages",
"Текстовые страницы"
],
{
"link": "\/admin\/?le=1",
"title": "Управление опциями"
},
{
"link": "\/admin\/?le=2",
"title": "Управление товарами"
},
{
"link": "\/admin\/?le=3",
"title": {
"usual": "Управление Меню",
"advanced": "Управление Конфигурацией"
}
},
{
"content": [
"a",
"b",
"c"
]
}
]
},
"editor": {
"login": [
"admin",
"developer"
],
"password": [
"c4ca4238a0b923820dcc509a6f75849b",
"c4ca4238a0b923820dcc509a6f75849b"
]
},
"leftmenu": [
[
"pages",
"Текстовые страницы"
]
]
}
11.09.2018
Метод ActiveRecord->id_or_insert_id
. Для нового элемента возвращает insert_id
, для существующего - id
.
Короткий синоним: ioi
Например:
$news = d()->News->new;
$news->title="Новая запись";
$news->save();
$id = $news->id_or_insert_id;
$id = $news->ioi; //Короткий синоним
31.08.2018
Исправлена невозможность использования функций вида d()->funcname=function(){}
в шаблонизаторе, при использовании конструкции {.property|funcname}
.
<?php
d()->myfunc = function($x){
return mb_strtoupper($x);
}
?>
{this.title|myfunc} <!-- Так работало --> <br>
{.title|myfunc} <!--Ранее не так работало--> <br>
30.08.2018
Метод save_and_load()
ActiveRecord. После сохранения возвращает новый объект с сохранённым id/insert_id.
<?php
$x = d()->News->new;
$x->title = "Новый заголовок";
$result = $x->save_and_load(); //$result - копия класса
print $result->id.' '; //ID новой записи
print $result->title; //Новый заголовок
29.08.2018
Параметр inline
функции preview
превращает путь в base64 строку с изображением. Пример:
<img src="{.image|preview '100', '100', 'inline'=>true}">
29.08.2018
Возможность переопределить заголовок вида "Список объектов из таблицы pages" в ini файле. Заготовка есть при генерации ini файла (нужно обновить кеш, т.к. находится в js файле).
Синтаксис:
[admin.titles]
list_title = Текстовые страницы
28.08.2018
Скаффолдинг - Миграция схемы теперь умеет сохранить сгенерированный schema.ini
в директорию app.
28.08.2018
Метод f
ActiveRecord, синоним find()
, но ищет строго по столбцу id.
28.08.2018
Доработан и исправлен метод Date->ago (склонения слов, правильный подсчёт). Убран мусорный код.
31.07.2018
Добавлено несколько функций и валидатор для работы с сотовыми телефонами.
d()->convert_phone($phone)
- Приводит номер телефона к форме 79876543210d()->convert_phone_clean($phone)
- Приводит номер телефона к форме 9876543210d()->convert_phone_plus($phone)
- Приводит номер телефона к форме +79876543210d()->convert_phone_human($phone)
- Приводит номер телефона к форме +7(987) 654-32-10validate_phone($phone)
- Проверяет телефон на валидность.Все, кроме последней доступны только через вызов d()->
. Её можно использовать в валидаторе:
[validator.registration.phone]
required.message=Вы не ввели телефон
validate_phone.message=Неправильно введён номер телефона
Внимание! Если уже была объявлена функция validate_phone
, то при обновлении системы произойдёт коллизия. Необходимо использовать другое имя или написать if(!function_exists('validate_phone')){
.
Ряд примеров использования можно найти в файле phonevalidatortest.class.php.
27.03.2018
Исправлен баг предыдущего исправления d()->view
. Исправлено "не найден шаблон" и в некоторых случаях зависание страницы.
24.03.2018
Добавлена функция d()->page_not_found()
(by @targrik).
При вызове возвращает заголовок 404, очищает предыдущий вывод, выводит шаблон d()->error_404_tpl()
в обёртке d()->main_tpl()
.
20.03.2018
Добавлен компонент admin_eval
. Принимает три параметра. Первый - указать id
. Не влияет ни на что. Второй - надпись. Третий - PHP строка, которая будет выполнена. На момент выполнения доступна переменная d()->row_data
, содержащая текущий объект. Можно применять, чтобы выводить какую-либо строчку. Например, при редактировании варианта товара, привязанному к товару, можно использовать в app/fields/product_variant.ini
, как в примере ниже, выведет название товара, к которому привязан вариант товара:
[admin.fields]
eval id "Товар" "d()->row_data->product->title"
eval id "Товар безопасно" "h(d()->row_data->product->title)"
small title "Название" "Например, 2кг"
;.....
Вывод никак не экранируется. Если нужно сделать ссылку, использовать теги, реализовать маленькую фотогалерею или что-то сложнее, можно использовать метод ActiveRecord
(или собственноручно написанный компонент).
Примечание: на данный момент система администрирования устроена так, что она запрашивает поле, указанное во втором параметре любого компонента панели администрирования. Например, legend "Это Опции"
выполнит d()->row_data->{Это Опции}
. В некоторых случаях это приводит к непредсказуемым последствиям, поэтому временно используется поле id
в качестве первого параметра.
17.03.2018
В поддиректориях папки app, cms и так далее, которые не начинаются на mod_
, можно включать другие поддиректории. Для этого вложенная поддиректория должна начинаться на "+"
.
Например, /app/bonjorno/+hello/+world/routes.php
. Глубина вложенности неограничена (кроме ограничений файловой системы).
Пример использования (дерево директорий):
/app
/pages
/import
/+source1
/+source2
/import.php
/+source3
/import.php
/ImportClass/ImportCore.php
11.03.2018
Теперь в простых директориях (без mod_
) автолоадер также ищет файлы с подчеркиваниями внутри имени файла, в том числе с двойными. Файлы с стандартной PSR-0
схемой загрузки по прежнему поддерживаются и имеют приоритет.
Пример:
/app/bonjorno/Uber__Buber_Class.php
:
<?php
class Uber__Buber_Class {
function yes(){
return 'Uber__Buber_Class';
}
}
/app/bonjorno/Uber_Class.php
:
<?php
class Uber_Class {
function yes(){
return 'Uber_Class';
}
}
/app/bonjorno/routes.php
:
<?php
print d()->Uber__Buber_Class->yes();
print "\n";
print d()->Uber_Class->yes();
exit;
Вывод:
Uber__Buber_Class
Uber_Class
25.02.2018
Возможность добавить свои расширения файлов для загрузки при помощи элемента управления file
. Расширения добавляются к дополнительным как часть регулярного выражения. Расширения добны разделяться символом "|"
. Указываются в опции $_ENV['DOIT_UPLOAD_EXTENSIONS']
в файле config.php
:
$_ENV['DOIT_UPLOAD_EXTENSIONS'] = 'css|rar';
20.02.2018
Исправлена вторая ошибка с зависанием d()->view
с несуществующими шаблонами. В случае, если в качестве имени шаблона используется строка, начинающаяся на "/", поиск по пути, совпадающем с адресом страницы, не просходит.
18.02.2018
Пункт 1: исправлена ошибка зависания в одном из случае при отсуствии шаблона.
Теперь если в пути указана папка app, зависание не происходит (например, d()->view->partial("/app/components/custom_pagination.html");
);
Внимание! Изменен приоритет и механизм поиска файла шаблонизатором. Теперь если указать "/app", поиск будет работать. Т.е. шаблонизатор ищет файлы не только в папке app в одном из случаев.
Пункт 2: две автогенерируемые переменные d()->paginator_current
и d()->paginator_count
, содержащие номер страницы и количество соотвественно. Пример:
<div>Страница {paginator_current} из {paginator_count} </div>
Пункт 3: возможность указать любой кастомный шаблон для пагинации.
<?php
d()->Paginator->custom_template("/app/components/custom_pagination.html")->generate($list);
Содержимое файла "custom_pagination.html" с описанием данных:
@ if ( ~paginator_left !== '') {
<a href="{paginator_left|h}" class="control prev">Назад</a>
@ }
<ul class="pagination">
<foreach paginator_list>
<?php /*
//Доступны следующие данные:
d()->paginator_left;// - ссылка на предыдущю страницу или пустая строка
d()->paginator_right;// - ссылка на следующую страницу или пустая строка
d()->paginator_current;// - номер страницы (страница X из 10)
d()->paginator_count;// - количество страниц (страница 2 из X)
d()->this['type'];//"EMPTY" - многоточие, "ACTIVE" - текущая страница,"LINK" - не текущая страница
d()->this['is_link'];//true - ссылка на страницу, false - многоточие
d()->this['is_active'];//true - текущая страница активна, false - многоточие или не текущая страница
d()->this['link'];//ссылка на страницу или пустота для многоточия
d()->this['title'];//номер текущей страницы или "..." для многоточия
*/ ?>
@ if (d()->this['type']=="LINK") {
<li><a href="{.link}">{.title}</a></li>
@ }
@ if (d()->this['type']=="ACTIVE") {
<li><a class="active" href="{.link}">{.title}</a></li>
@ }
@ if (d()->this['type']=="EMPTY") {
<li class="disabled"><a href="#">...</a></li>
@ }
</foreach>
</ul>
@ if ( ~paginator_right !== '') {
<a href="{paginator_right|h}" class="control next">вперед</a>
@ }
{paginator_current} из {paginator_count}
18.02.2018
Исправлена ошибка при отсутствии папки, указанной в APP_DIRS (by @targrik).
12.12.2017
Для developer выводится файл, номер строки и трассировка при получении Exception.
12.12.2017
checkboxes
четвертый параметр теперь указывает на имя таблицы, и он обязателен для использования пятого параметра.
06.12.2017
Новые водяные знаки. Больше не создается черный фон при накладывании png на png.
Появилась возможность указывать расположение водяного знака или задать его повторение (по умолчанию "center"), а также задать прозрачность (число от 1 до 100, по умолчанию 100). Указывается так:
<img src="{.image|preview '200', '200' , 'watermark'=> array("/images/watersmall.png", "center-right", 50) }">
Доступные значения для положения:
* repeat - заполнение повторением картинки
* top-left
* left-top
* center-top
* bottom-left
* center-left
* center-center
* center
* и любые другие сочетания двух значений "left", "center", "right" и "top", "center", "bottom" в любом порядке.
Также исправлена проблема, из-за которой конкатенация JS файлов происходила с ошибкой, если один из файлов не оканчивался на ";".
06.12.2017
Метод to_json_by_id
объектов ActiveRecord
аналогичен to_json
- возвращает все данные, но в качестве ключей - значение поля id
:
d()->News->select('id, title')->to_json_by_id;
//Результат:
{
"21":{"id":"21","title":"title1","table":"news"},
"34":{"id":"34","title":"title2","table":"news"},
"17":{"id":"17","title":"title3","table":"news"}
}
12.11.2017
Функция preview
автоматически поворачивает изображение, если в EXIF записан поворот. Исправляет баг "я загрузил картинку, а она повёрнута".
31.10.2017
Функция javascripts
для объединения и сжатия js файлов. Обработчиков и компиляторов (например, ES2015) нет, только сжатие и объединение.
Использование:
{{javascripts '/js/jquery-1.12.4.min.js', '/js/jquery-migrate-1.1.0.js' , '/js/main.js' , 'minify'=>true, 'to'=>'/js/minified_bundle.js'}}
Обратите внимание: для сайтов на HTTP/2 объединение не нужно.
28.09.2017
Поддержка необязательного параметра $_ENV["APP_DIRS"]
(указывается в config.php). Можно указать дополнительные директории с кодом, помимо app
и cms
, например, для собственных наработок компании. МОдули будут переопределять друг друга последовательно. В дополнительных директориях не будет активироваться мультиязычность (app/lang
) и статические шаблоны (app/static
).
Пример:
<?php
$_ENV["APP_DIRS"]="cms,custom, app";
20.09.2017
Поддержка @include "file.scss";
в scss файлах, обрабатываемых функцией stylesheets
. Ищет файлы в директории с указанным файлом, для каждого файла независимо.
05.09.2017
В элемент управления connected_checkboxes
и checkboxes
добавлен новый необязательный параметр (четвёртый в connected_checkboxes
и третий в checkboxes
). В него передается имя метода класса, который будет запрошен у соответствующей таблицы перед выводом списка, для фильтрации данных. Например, для таблицы users
, при указанном параметре activated
для построения списка галочек будут использоваться данные из списка d()->User->activated;
Внимание: классы Table_Safe
не используются, используется обычный ActiveRecord.
Пример:
<?php
class Filial extends ActiveRecord {
function limites(){
return $this->limit(2);
}
}
class Scriptstep extends ActiveRecord {
function onlyquestions(){
return $this->only('question');
}
}
[admin.fields]
small title "Название"
checkboxes to_filials "Филиалы" limites
connected_checkboxes connected_question_id_in_script_questions "Следующие вопросы" scriptsteps onlyquestions
04.09.2017
Исправлена ошибка, из-за которой системе не удавалось правильно определить название many_to_many
таблицы при сообщении об ошибке вида: "Создать столбец XXX в таблице YYY"?
Ошибка возникала, когда в many_to_many
таблице отсутствовали столбцы с ID элементов и была попытка прочесть список элементов.
04.09.2017
Элемент управления для системы администрирования connected_checkboxes
для вывода "галочек" для списка соединенной таблицы. Имеет обязательный для указания параметр (четвёртый).
Нужен только для вывода свойства title
из выбранной таблицы.
Примеры:
;scriptsteps
[admin.fields]
small title "Название"
connected_checkboxes connected_question_id_in_script_questions "Связанные ответы" scriptsteps
;users
[admin.fields]
small title "Название"
connected_checkboxes friend_id_in_users_friends "Друзья" users
;products
[admin.fields]
small title "Название"
connected_checkboxes connected_similar_product_id_in_similars "Рекомендуемые товары" products
Для использования элемента управления не обязательно использовать запись connected_*_in_*
. Система работает и с обыкновенным текстовым полем, просто записывая в базу данных id через запятую.
;products
[admin.fields]
small title "Название"
connected_checkboxes regionslist "Регионы" regions
connected_checkboxes just_title "ID категорий" categories
04.09.2017
Виртуальное свойство connected_field_in_table
в ActiveRecord. Позволяет привязывать списки числовых идентификаторов к элементу таблицы, без указания точной таблицы, в которой эти идентификаторы представляют данные.
Можно использовать, например, для связи many_to_many
одной и той же таблицы.
При сохранении принимает строку с идентификаторами, разеделенными запятой, при запросе возвращает её же.
Пример 1:
<?php
d()->product = d()->Product->find(14);
d()->product->connected_similar_product_id_in_similars = "1,2,4";
d()->product->save();
/* ... */
print d()->product->connected_similar_product_id_in_similars; //"1,2,4";
В данном примере в таблице similars появятся строки:
/* таблица similars */
----------------------------------------
| id | product_id | similar_product_id |
|----|------------|--------------------|
| 1 | 14 | 1 |
| 2 | 14 | 2 |
| 3 | 14 | 4 |
----------------------------------------
04.09.2017
Для всех файлов функция stylesheets
теперь по умолчанию подставляет дату изменения файла вида /css/compiled.min.css?1504332381
. Чтобы выключить это поведение, надо указать параметр "mtime"=>false
:
{{stylesheets '/css/style.less', 'minify'=>true, 'mtime'=>false}}
02.09.2017
Автолоадер теперь не создает экземпляры ActiveRecord, если класс начинается с маленькой буквы.
Большое обновление функции stylesheets
. Теперь она включает:
* Компилирование SCSS
* Компилярование LESS
* Объединение (конкатенацию) CSS файлов
* Минификацию
Функция автоматически сверяет дату изменения оригинального файла и скомпилированной/сжатой версии.
Для включения минификации нужно указать параметр 'minify'=>true
.
Для включения конкатенации нужно указать параметр 'concat'=>true
или указать имя файла, которое будет содержать результат: 'to'=>'result.min.css'
.
Без указания имени будет браться md5 от всех имен файлов.
Если не указан путь, файлы будут искаться в папке css
.
Для нормальной работы папке css
должны быть переданы права за запись.
Примеры использования.
{{stylesheets '/css/style.scss','/css/style2.less', 'main.css', 'minify'=>true, 'to'=>'/css/result.css'}}
{{stylesheets '/css/style.scss'}}
{{stylesheets '/css/style.less'}}
{{stylesheets '/css/style.less', 'minify'=>true}}
27.08.2017
Элементы управления file
и image
теперь отображают процент загрузки.
10.08.2017
Объект d()->params
теперь отдает правильные значения не только при вызове вида d()->params['email']
, но и при вызове вида d()->params->email
.
Это позволяет использовать его значение в шаблонах (например, шаблонах писем): {params.email|h}
.
Добавлена ссылка на скачивание архивов модулей с сайта системы.
10.08.2017
Внимание! Beta версия! (см. описание 2.8)
Добавлены три метода: as_date_ru_month
- получение строки вида "Май", as_date_day
- получение дня в виде числа, as_date_mm_yyyy
- получение строки вида "04.2017".
Используется для простого вывода даты в разных местах шаблона:
<div class="review-day">{.created_at_as_date_day}</div> <!-- 8 -->
<div class="review-month">{.created_at_as_date_mm_yyyy}</div> <!-- 07.2017 -->
09.08.2017
Внимание! Beta версия! (см. описание 2.8)
Защита от двойной отправки формы при медленном интернете.
Добавлен CSS класс js-disabled
. Если этот класс указать для кнопки отправки формы, то она получит HTML свойство disabled
сразу до отправки, и потеряет его после получения ответа сервера (но до его фактической интерпретации). Работает полностью автоматически.
Работает только для AJAX форм.
Пример (HTML):
<input type="submit" class="submit-button js-disabled" value="Отправить">
Пример (CSS):
.submit-button[disabled]{
opacity:0.5;
}
09.08.2017
Внимание! Beta версия! (см. описание 2.8)
Добавлен новый загрузчик плагинов/расширений. Сами расширения хранятся на сервисе github и доступны для дополнения сообществом.
08.08.2017
Внимание! Beta версия!
Появилась конструкция ~
в шаблонизаторе, которая заменяется на d()->
Позволяет городить такие конструкции:
@ ~objects_list = ~Object->order('sort DESC');
{{add 'users', 'category_id'=>~title}}
<?php if(~Auth->id == ~current_user){ /* */ } ?>
Не срабатывает после закрывающихся скобок, для арифметических операций ожидает перед собой пробел. Потенциально безопасна, не должна влиять на работу сайта и пересекаться с другими знаками ~
, но без долгого тестирования считается beta версией.
07.08.2017
В режиме разработчика выводится база данных, путь к сайту и phpinfo()
27.07.2017
Теперь элемент управления file
работает без flash в связи с последними обновлениями браузеров.
29.06.2017
Добавлен метод and_select()
у ActiveRecord. Добавляет дополнительный параметр к полю SELECT запроса. Параметр является обязательным. Предварительный вызов select()
обязателен, иначе запрос будет вида SELECT * , user_id
.
Например:
d()->users->select('id');
d()->users->and_select('min(price) as price');
d()->users->and_select('user_id, category_id');
//Будет преобразовано в SELECT id, min(price) as price, user_id, category_id
24.05.2017
Добавлен метод clone
у ActiveRecord. Возвращает клон объекта, либо сохраняет именованный клон и возвращает его.
Алиасы: copy()
, clone_copy()
.
Использование:
<?php
d()->objects_list = d()->Object->order('sort DESC');
d()->objects_list->copy; //Клон объекта
d()->objects_list->copy(); //Клон объекта
d()->objects_list->clone; //Клон объекта
d()->objects_list->clone(); //Клон объекта
d()->objects_list->clone_f2->where('user_id = 1');
d()->objects_list->clone_f2; //Сохранённый клон под именем f2
d()->objects_list->clone("f2"); //Сохранённый клон под именем f2
d()->objects_list->copy("f2"); //Сохранённый клон под именем f2
Использование на практике:
<?php
//Старый вариант
$dp = clone d()->objects_list;
$ss = $dp->select('user_id')->group('user_id')->fast_all_of('user_id');
d()->user_list = d()->User->where('id IN (?)', $ss);
foreach (d()->user_list){ /* ... */ }
//Новый вариант
d()->objects_list->clone_for_users->select('user_id');
foreach (d()->objects_list->clone_for_users->_users){ /* ... */ }
24.05.2017
Трейт Tree для работы с деревьями внутри ActiveRecord.
class Category extends ActiveRecord
{
use Tree;
}
Добавляет методы для определения наддерева и поддерева: subtree_ids()
, subtree
, suptree_ids
, suptree
.
17.04.2017
Новый элемент управления для автотранслита. Пример использования:
[admin.fields]
urltranslit url "Адрес" title "(необязательно)"
small title "Заголовок"
10.01.2017
Исправлена ошибка admin_authorisation : Using $this when not in object context
.
29.12.2016
Расширенные опции для оптимизатора изображений (на случай, если необходимо максимальное сжатие). Например, для JPG разница в 75%.
Для использования необходимо установить mozjpeg(https://mozjpeg.codelove.de/binaries.html) и pngquant(https://pngquant.org/), и настроить пути к ним в config.php
Пример (на примере Windows):
$_ENV["DOIT_OPTIMIZE_IMAGES"] = true;
$_ENV["DOIT_OPTIMIZE_IMAGES_EXTEND"]=array(
'PNG'=>'pngquant --quality=60-90 - < #SOURCE# > #DEST#',
'JPG'=>'E:\OpenServer\modules\php\PHP-5.6\ext\cjpeg -quality 70 #SOURCE# > #DEST#',
);
Допустимо использовать другие инструменты.
15.12.2016
Оптимизатор изображений, встроенный в функцию preview. Активируется опцией в config.php
:
$_ENV["DOIT_OPTIMIZE_IMAGES"] = true;
Для работы необходимы внешние библиотеки, установленные на сервере. В противном случае просто игнорирует задачу Подробнее об оптимизаторах написано тут: https://github.com/psliwa/image-optimizer
Например, для установки оптимизатора для jpeg (jpegtran) для ubuntu/debian необходимо выполнить
apt-get install libjpeg-progs
14.12.2016
Внимание! Beta версия!
Конструкция
{.image|preview "136", "136"}
Теперь всегда делает проверки на is_object по всей длине цепочки.
09.11.2016
Внимание! Beta версия!
Конструкция
{.image|preview "136", "136"}
Компилировалась в
<?php print $doit->preview(array( $doit->this->image , "136", "136")) ; ?>
Таким образом, для массивов не работала. Сейчас компилирует в
<?php print $doit->preview(array( $doit->this['image'] , "136", "136")) ; ?>
Возможны проблемы при вызове методов объектов.
09.11.2016
Поддержка подсветки синтаксиса в полях big в админке. Использование следующее:
big text "HTML код" html
;Для обычного текста без подсветки
big text2 "код" text
big text3 "PHP код" php
В ini файл для полей по умолчанию записана закомментированная строка опции сортировки.
;[admin]
;list.sort_field=created_at
;list.sort_direction=desc
27.10.2016
Функция or_is_empty()
, которая возвращает второе значение, если первое пустое.
Например:
Заработная плата: {.money|h|or_is_empty "не указана"}
21.10.2016
Поддержка конструкции _as_
.
Например,
d()->product->image_as_preview;
d()->product->category_id_as_object_title;
d()->product->category_id_as_title;
При вызове ищет функцию, которая начинается на as_
и вызывает её, передавая три параметра: значение, имя метода (часть перед _as_
), и ссылку на объект.
Может использоваться в панели администрирования для удобного вывода значений в списке:
[admin.use_model]
list=yes
[admin.columns]
title=Название
category_id_as_object_title="Категория"
image_as_preview="Картинка"
19.10.2016
Поддержка событий.
Регистрация события:
d()->on('auth',function($id,$method){
var_dump($id);
var_dump($method);
});
Вызов события:
d()->emit('auth',12);
01.07.2016
Отныне Doit - PSR-7 совместимый фреймворк.
Внимание: по-прежнему beta-версия.
Поддержка PSR-7 middleware. Завершено внедрение zend-diactaros
, внедрение zend-stratigility
.
Это позволяет использовать собственные или сторонние middleware стандарта PSR-7.
Кроме этого, открывается новый способ построения веб-приложения вообще без использования контроллеров или роутов микрофреймворка (route
, get
, post
), при помощи
одних middlewares.
Пример добавления middleware:
<?php
d()->add(function($request, $response, $next){
$response->getBody()->write('before');
$next($request,$response);
$response->getBody()->write('after');
});
//С привязкой к адресу
d()->add('/news/',function($request, $response, $next){
$response->getBody()->write('before');
$next($request,$response);
$response->getBody()->write('after');
});
Также можно создать новый MiddlewarePipe
при помощи d()->new_pipe()
. Полученный объект может сам служить в роли middleware, но при этом
сам может при помощи метода pipe()
принимать вложенные middleware. Подробнее можно посмотреть по адресу https://github.com/zendframework/zend-stratigility/blob/master/doc/book/executing-middleware.md
Возможности middleware доступны только для PHP версии 5.4.8 и выше. Для более старых версий middleware, request, response не создаются и не используются, использование метода add
приведёт
к ошибке отсутствия класса. При этом совместимость с другими проектами полностью сохраняется - если не использовать возможности middleware, то всё будет продолжать работать как и раньше на любой версии PHP, старше чем 5.3.
28.04.2016
PHP 5.4 - минимальная версия PHP для всех возможностей системы. Минимально поддерживаемая версия PHP по прежнему 5.3.
Подключен zend-diactoros
. Впоследствии будет включён глубоко в систему. Доступен следующим образом:
d()->http_request->getHeaders();
Для PHP 5.3 не используется. Для использования обязательно иметь PHP 5.4. 5.4 становится минимально совместимой версией системы. На PHP 5.3 система по прежнему работает без сбоев в режиме совместимости, d()->http_request
при этом недоступен.
27.04.2016
Короткая запись для правил роутера. Если путь не начинается на "/"
, то срабатывает автопоиск пути по имени директории:
d()->get(function($url){
print $url;
});
Также можно указать путь явно при помощи d()->group('/news/')
;
Если первый параметр функций route()
, get()
, post()
пропущен, то вставляется ":param*"
- полный путь, включая пустую строку.
Альтернативная запись:
d()->group('/news/',function(){
d()->get(':url', function($url){
print $url;
});
})
27.04.2016
Поиск шаблонов для d()->view
. Новая лицензия (MIT). Методы get()
и post()
для роутера. Метод via()
для роутера.
d()->post('/feedback/send',function(){
//обработчик формы
});
d()->get('/feedback/',function(){
//показать форму
});
Класс d()->view
теперь может искать файлы шаблонов в текущих директориях для анонимных функций и роутов:
<?php
//для анонимной функции
d()->my_function=function(){
print d()->view->render('template.html');
};
//для роута
d()->get('/feedback/',function(){
print d()->view->render('template.html');
});
Новая лицензия (MIT) расширяет возможности по использованию фреймворка в коммерческих целях.
26.04.2016
Внимание! Beta версия.
Появление composer для пользователя системы. Появление composer внутри системы администрирования. Перевод SwiftMailer внутрь composer.
Для использования необходимо выполнить команду composer require "пакет"
- установится composer и появится папка vendor в корне системы.
21.04.2015
Передача в переменную Closure для дальнейшего запуска через вызов функции. Приоритетнее, чем остальные способы передачи функции. Пример вызова:
d()->summa = function($a,$b){
return $a + $b;
};
print d()->summa(2,3); //5
Благодаря высокому приоритету может переопределить функцию summ()
, даже если она есть. Благодаря этому можно переопределять некоторые внутренние функции системы, заданные в виде PHP функций, например, edit()
, не используя возможностей роутера.
05.04.2016
Исправление умного автоподставлятеля символа "=>". Теперь конструкция
{{edit "href"=> "/admin/edit/plugins/name?fields=textblock" }}
не превращается в
<?php print $doit->call("edit",array(array( "href"=> "/admin/edit/plugins/name?fields=>textblock" )));?>
25.01.2016
Поддержка нотации json в ini-файлах
Синтаксис на данный момент следующий:
[params]
element.title=Метро
element.list=json:["Авиастроительная", "Аметьево", "Горки", "Козья Слобода", "Кремлёвская", "Площадь Тукая", "Проспект Победы", "Северный вокзал", "Суконная слобода","Яшьлек"]
Может использоваться в значениях, переданных через знак =
. Строка должна начинаться на :json
.
20.11.2015
Вывод ошибки при неудаче найти файл шаблона в новом классе view;
19.11.2015
Рекурсивный итератор
<?php d()->this = d()->Region->where('region_id is null') ; ?>
<select name="region_id">
<option value="">-не указано-</option>
<tree regions>
<option value="{.id}">
{level|times "—"} {this.title}
</option>
</tree>
</select>
27.10.2015
Функция times для повтора символов и текста:
<?php d()->level = 5; ?>
{level|times "—"}
26.10.2015
Базовая поддержка постпроцессора CSS. (autoprefixer, cssnano, и т.д.)
Синтаксис следующий:
<head>
{{stylesheets '/css/style.scss'}}
</head>
Компиляция CSS проводится в облаке, соответственно, без подключённого Интернета не работает.
10.08.2015
Новый валидатор, поддержка bootstrap 3 в автоматической подсветке ошибок.
10.08.2015
Запись {{/projects/_one.html}} для отображения партиала для версии 2.0
06.08.2015
Значительно переработан шаблонизатор.
Появились конструкции:
@print 2+2;
{* comment *}
{user.product.source.parent.author|h|preview '200', 'auto'}
07.07.2015
Требование PHP 5.3.
Появление контейнера объектов. Появление Swift mailer. Появление cms/vendor/
07.07.2015
Ace Editor в редакторе ini файлов
В папке sites теперь можно указывать не полное имя домена, а только поддомен.
05.06.2015
Кнопка "сохранить и добавить ещё" при добавлении объекта демо. Багфиксы.
21.04.2015
Файлы в загрузчике картинок и файлов, включая tinymce, теперь имеют человекопонятные имена.
21.04.2015
Поддержка времени в датах, передаваемых в Date()
09.09.2014
0.29.7
Вставка картинок в TinyMCE через CTRL+V;
09.09.2014
Поддержка произвольных HTML в конфигах форм администратора.
Для вставки в fields/tablename.ini надо вписать код:
include "mycontainer"
mycontainer
- имя HTML файла, либо метод контроллера, либо функция. Например, допустимо:
include "users#editform"
Для вставки классических элементов в подобные шаблоны можно использовать следующий синтаксис:
{{form_row 'small', 'subtitle', 'Подзаголовок'}}
Может использоваться для вывода инструкций и другой информации прямо в формах администратора, а также для создания элементов управления повышенной сложности.
Поддержка третьего необязательного параметра для container
в админке. Указывает на массив доступных модулей (ini) вместо container.ini
.
06.09.2014
Поддержка названий в контейнерах container
. Меняется двойным щелчком.
05.09.2014
Поддержка нескольких получателей события через socket.io.
Используется так:
d()->SocketIO->emit('bb156e7e617ad61894cbdf35481705a0' ,'server_event','Привет1');
d()->SocketIO->emit('7a30bb1f473b2d6dc642c05d83adbb75' ,'server_event','Привет2');
d()->SocketIO->emit(array('7a30bb1f473b2d6dc642c05d83adbb75','bb156e7e617ad61894cbdf35481705a0') ,'server_event','Привет 1 и 2');
В качестве удобства также теперь доступна конструкция d()->Socketio->userid
, устанавливаемая по-умолчанию;
02.09.2014
Поддержка строк, массивов любой вложенности при передаче на сервер сообщений (socket.io). Облачный сервер прописан по-умолчанию (если не указывается иной адрес)
29.08.2014
Базовая поддержка Push запросов с сервера через прокси node.js.
29.08.2014
Новое правило автоподставления шаблонов теперь работает только с контроллером pages. С остальными контроллерами поведение старое. Соответственно обратной совместимости стало немного больше.
25.08.2014
Новая версия системы.
Значительные изменения в системе роутинга.
router.init.ini
устарел. Все изменения вносятся в файл router.func.php
. Для старых проектов можно ничего не делать - всё будет продолжать работать. Также можно удалить router.func.php
и всё будет работать по-прежнему. Однако использование правил роутера в виде функций даёт ряд преимуществ: более лаконичный синтаксис, возможность ставить условия, циклы, анонимные функции, поддержка роутеров для ленивых, а в дальнейшем дополнительные фильтры на типы запросов. Пока этот файл удалять не стоит - скаффолдинг использует именного его. Однако сейчас при наличии функции route_all
в файле router.func.php
галочку "добавить запись в роутер" при использовании скаффолдинга можно не делать.router.func.php
и любых других можно указывать команды route()
, которые добавляют правила роутинга. При этом слово content
можно игнорировать.router.func.php
по-умолчанию запускается функция route_all()
, которая автоматически добавляет правило роутить контроллеры автоматически, например, /news/
на news#
. Таким образом, теперь класс NewsController
будет доступен по адресу /news/
полностью автоматически. Это не будет активировано для старых проектов (т.к. функция route_all()
не запущена. Это правило отменяется для любых адресов, для которых зарегистрировано хотя бы одно правило в роутере./users/vasya
методом show()
и файл _vasya.html
существует, то именно он будет использоваться в качестве шаблона. Это может поменять поведение в некоторых случаях! Пример такого случая: для роутинга на /index
не создавалось правил вообще, использовался classname#
(например, users#
или news#
), при этом метода index
не создавалось (и зря). Использовался шаблон _index.html
без вызова метода контроллера. Теперь же метод show()
контроллера будет вызван.
Эта новая возможность делает работу немного легче. Например, чтобы переопределить шаблон главной страницы, достаточно создать файл _index.html
и всё.Blabalbacontroller
(заканчивающийся на controller
) не будет создан автоматически (как ActiveRecord
) при обращении к нему.route
может принять на вход анонимную функцию. Это позволяет использовать систему как микрофреймворк, но в данном случае версия PHP должна быть уже 5.3 или выше (5.2 не поддерживает анонимные функции).25.08.2014
Новый роутер.
24.08.2014
Исправлен баг: delete
не очищал кеш ActiveRecord;
21.08.2014
Поддержка ватермарков (водяных знаков) в функции preview
. Используется параметр watermark
, указывающий на картинку.
Использовать так:
<img src="{.image|preview 'watermark'=>'/images/header_watermark.png', 512,320}" alt="{.title|h}">
Или так:
{{preview d()->this->image, '200', '300', 'watermark'=>'/images/watermark.png'}}
Картинка-watermark помещается по центру. Рекомендуется использовать для картинки-накладки тот же самый размер, что и генерируемая превью.
15.08.2014
UniversalSingletoneHelper
стал немного универсальнее. Минорное изменение.
06.06.2014
Поддержка записи вида {variable|function 'param'}
.
06.06.2014
Исправлен баг: не генерировались paginator_left
и paginator_right
на bootstrap режиме пагинатора.
06.06.2014
Поддержка контейнеров. Контейнер позволяет вставить на страницу множество различных элементов, таких как заголовки, столбцы, картинки, формы. Может использоваться для создания посадочных страниц и богатого оформления заранее заготовленными блоками. Для использования необходимо:
Первое. Создать функцию, которая может быть контейнером. Например, contactform#show
, а также другие функции.
Второе. Создать файл container.ini
со следующим содержимым (перечислить функции):
[container]
contactform#show=Форма обратной связи
contactform#show1=Первый модуль
contactform#show2=Второй модуль
news#index=Список новостей
Третье. В файле /fields/pages.ini
или другом, соответствующем нужной таблице написать строчку:
container text2 "Элементы управления"
Перетащить туда несколько элементов.
Четвёртое. В шаблоне написать {.text2|container}
.
Всё. Элемент управления, ini-файл, функция-обработчик - все они называются container
. Если привязать контейнер к опциям, можно делать сквозные элементы (которые повторяются по всему сайту).
Внутри кода контейнера доступна переменная d()->plugin_id
с уникальным строковым идентификатором, указывающим на конкретный компонент внутри контейнера.
11.05.2014
Класс Mail теперь принимает свойство from даже в том случае, если не используется SMTP (вариант отправки через mail()
без вложенных файлов).
Использовать, например, так:
d()->Mail->from('Робот сайта <noreply@example.com>');
07.05.2014
Исправление AJAX части формы для IE8.
04.04.2014
Полиморфные объекты для linked
. Изменения довольно важные и полезные, поэтому будут описаны в отдельном документе. Теперь можно делать похожие товары, аксессуары, друзья, и так далее.
04.04.2014
Введён новый метод ActiveRecord->ne
, возвращает true, если есть хотя бы один результат.
02.04.2014
Введён новый метод ActiveRecord->is_not_empty
, возвращает true, если есть хотя бы один результат.
02.04.2014
plus
Поддержка метода plus
. Позволяет добавить к массиву ещё один. Не переопределяет текущий объект, а создаёт новый.
Например:
d()->goods = d()->Good->where('cost < 100');
d()->goods = d()->goods->plus(12);//12 - ID товара
//Также умеет принимать массив товаров
d()->goods = d()->goods->plus(d()->Good->where('cost > 1000'));
Принимает число, массив чисел, массив ассоциативных массивов с полем id
, объект ActiveRecord.
all_linked
или _all_catalogs
Подержка метода all_linked
. Делает linked
рекурсивно, пока получается. Не столь явно и универсально, как linked
, но зато позволяет получить всё дерево в глубину. Имеет псевдоним _all_*
, например, _all_catalogs
.
d()->Catalog(3)->_all_catalogs; //Все дочерние каталоги и их дочерние каталоги и т.д.
Пример получения всех товаров каталога c ID=$id и всех его дочерних каталогов. С постраничной навигацией.
d()->catalog = d()->Catalog($id);
d()->catalog = d()->catalog->_all_catalogs;
d()->catalog->plus($id);
d()->goods = d()->catalog->_goods->paginate(2);
Тоже самое одной строкой:
d()->goods = d()->Catalog($id)->_all_catalogs->plus($id)->_goods->paginate(2);
Допустим, товары дополнительно хранятся в catalogs_to_goods
через альтернативную связь many_to_many
.
/*
Данный код получает все каталоги, подкаталоги,
под-под-каталоги и т.д. каталог с id=$id,
затем получает все товары всех этих каталогов,
в том числе и указанных напрямую через catalog_id,
и через дополнительную связь many_to_many,
а также товаров самого каталога $id.
Полученные товары подвергаются пагинации.
*/
d()->goods = d()->Catalog($id)
->_all_catalogs
->plus($id)
->_goods
->plus(d()->Catalog($id)->_all_catalogs->_catalogs_to_goods->_goods)
->paginate(2);
Конечно, вот так вот "однострочничать" не рекомендуется.
01.04.2014
Значительное обновление в ActiveRecord. Появление метода linked
, который получает связанные объекты. Для массива каталогов linked('goods')
вернёт массив товаров в этих каталогах, для массива товаров linked('catalogs')
вернёт массив каталогов этих товаров.
Если товар или каталог один - ничего страшного.
Массивы являются объектами ActiveRecord, поэтому к ним можно применять where
, limit
, paginate
и так далее.
Более удобная сокращённая запись: d()->Good->_catalogs
(аналог d()->Good->linked('catalogs')
). Предположительно, станет основным инструментом получения данных (обычный способ останется для совместимости).
d()->Catalog(13)->catalogs->_goods; // Вернёт все товары всех подкаталогов каталога 13
d()->Catalog(13)->catalogs->_goods->_users; // Вернёт всех пользователей всех товаров каталога 13
// Вернёт все каталоги, в которых есть товары с ценой меньше 100, с постраничной навигацией
d()->Good->where('cost < 100')->_catalogs->paginate(10);
//Пользователи, которые оставляли комментарии за последний день
d()->Comment->where('created_at > ?',d()->Date('yesterday')->to_mysql)->_users;
Рассмотрим более сложный случай:
works
с портфолио.portfoliodirections
с тегами для портфолио (направления работы). Одна работа может иметь несколько направлений.portfoliodirections_to_works
, у которой есть столбцы portfoliodirection_id
и work_id
.Итого: many_to_many
таблица связей.
Мы хотим получить список всех работ по тегу с ID=3, а также всех работ по тегам, ID которых больше 2
Решение:
d()->Portfoliodirection(3)->_portfoliodirections_to_works->_works;
d()->Portfoliodirection->where('id > 2')->_portfoliodirections_to_works->_works;
Кроме того, добавлен метод ActiveRecord для более быстрого получения all_of('ids')
.
Вызывается так:
d()->Catalog->fast_all_of('id');
Склонять во множественном числе не надо, объекты не создаются, данные берутся напрямую из массива. В некоторых случаях такой вызов на 2-3 порядка быстрее обычного. В любом случае в дальнейшем метод linked
должен привести к тому, что all_of
просто не пригодится.
Кроме того, оптимизирован where('id IN (?)',$array)
, который теперь делает array_unique
, что на пару процентов ускоряет запрос.
31.03.2014
Отныне d()->Page('')
ничего не вернёт (количество записей будет равно нулю).
27.03.2014
Поддержка записей вида d()->Page('index')
. Ищет по url
, является синтаксическим сахаром. Будет использоваться в модуле "меню".
27.03.2014
В роутере теперь проще писать алиасы для html-шаблонов - .html
автоматически меняется на _tpl
. Например, теперь можно писать так:
/index main.html index.html
27.03.2014
Поддержка метода where_equal
в ActiveRecord. Первый аттрибут - название поля, второе - значение. Например:
d()->news_list = d()->News->where_equal('title', 12);
Может пригодиться в том случае, когда названия столбцов передаются через переменные. Всё экранирование происходит автоматически.
25.03.2014
Параметр в валидаторе для отображения скрытого поля. Если поле пришло не пустым - валидатор дальше не пустит. Необходимо для защиты от ботов. В валидаторе пишется следующее:
[validator.contactform#send.city]
must_be_empty.message=Возможно, вы робот. Уйдите.
В код формы вставляется примерно следующее:
<div style="display:none">
<input type="text" name="city" placeholder="Город" autocomplete="off">
</div>
autocomplete="off" необходимо, чтобы в это поле не вбился автоматически город. Поле city
можно изменить на любое подходящее.
Внимание! название поля в виде city
, а не data[city]
актуально только для форм с 'simple_names'=>true,
! Это обычное поле с обычными данными и обычным валидатором, просто работает наоборот.
24.03.2014
{{sort_icon}} без параметров берёт опции предыдущего {{add}}. Это сделано потому, что в большинстве случаях (срого говоря, на практике - во всех) параметры этих иконок всегда одинаковы.
23.03.2013
Теперь администратор может сортировать столбики в таблице вывода списка элементов путём щелчка по ним.
22.03.2014
Поддержка записи вида
d()->News(array(12,5,7));
//Идентично следующему
d()->News->where('id IN (?)', array(12,5,7));
21.03.2014
Поддержка TRUNCATE в ActiveRecord. Вызывается так:
d()->Konkurs->truncate(true);
d()->Page->truncate(true);
true - обязательный параметр, его не надо настраивать или передавать как переменную. Это сделано для безопасности.
Внимание! Выполнение функции как переменной или вызов без обязательного параметра true
приведёт к ошибке. Будьте внимательны и осторожны со своими данными.
19.03.2014
Функция declOfNum
(определяющая множественное число) теперь имеет несколько альтернативных синтаксисов:
//Было
d()->declOfNum(81,array('попугай','попугая','попугаев'))
//Теперь ещё можно так
d()->declOfNum(1,'комментарий','комментария','комментариев');
d()->declOfNum(2,'комментарий','комментария','комментариев');
Также теперь можно вовсе не передавать все слова - функция сама попытается определить грамматически правильную форму:
d()->declOfNum(2,'комментарий'); //комментария
d()->declOfNum(20,'новость'); //новостей
Это также работает для английских слов (на всякий случай):
d()->declOfNum(20,'child'); //children
Также шаблонизатор поддерживает конструкцию вида {obj.prop|func "params"}
. В итоге, теперь можно писать так:
{news_list.count} {news_list.count|declOfNum "новость"}
{Comment.count} {Comment.count|declOfNum "комментарий"}
Также обновлены тесты для всего этого.
18.03.2014
Обновлён TinyMCE 3.5.6 (2012-07-26) → 3.5.10 (2013-10-24).
17.03.2014
Поддержка татарского языка в датах (мультиязычность). Поддержка обработок дат вида
d()->Date('12 января 2014');
d()->Date('12 гыйнвар 2014');
d()->Date('12 02 2014');
16.03.2014
htmlimage
загрузчик картинок теперь поддерживает перетаскивание нескольких файлов одновременно (для multiple=yes
).
Модуль image
теперь полностью замещён новым загрузчиком. Для старых браузеров автоматически отображается старый вариант на flash.
Таким образом, сейчас основной элемент image
для загрузок картинок администратором обновлён, выглядит и работает по другому. Сам механизм и принцип работы остались прежними, в первую очередь добавились удобства - скорость работы, работа на некоторых устройствах без flash (некоторые планшеты и т.д.), появилось перетаскивание файлов в браузер, вставка из буфера обмена, внешний вид.
13.03.2014
htmlimage
загрузчик картинок теперь поддерживает multiple=yes
, позволяя выбрать несколько изображений одновременно.
13.03.2014
htmlimage
загрузчик картинок теперь может вставлять изображения перетаскиванием файла в браузер.
12.03.2014
htmlimage
загрузчик картинок теперь может вставлять изображения из буфера обмена (изображения, не файлы изображений) и автоматически загружать их в виде файлов.
12.03.2014
Поддержка автогенерируемого sitemap.xml.
В роутере необходимо прописать
/sitemap.xml main show_sitemap
Файлы sitemap.func.php
и sitemap.ini
должны находиться в папке app (они не создадутся при обновлении). Сами правила описаны в файле sitemap.ini
, там перечислены адреса и таблицы, которые должны быть видны в карте сайта.
Исправлено поведение загрузчика в IE11.
11.03.2014
Новый тип файлового загрузчика для панели администратора, без использования flash. Вызывается тем же синтаксисом, но называется htmlimage
:
htmlimage image "Изображение" galleries 180 auto
Работает немного отзывчивее, чем на основе flash, но работает только начиная с IE9 и Opera 12. (http://caniuse.com/xhr2).
Если опыт покажет положительный результат, обычный image
будет заменён на этот, либо в старых браузерах будет подставляться flash-версия.
11.03.2014
Поддержка пользователей для системы администрирования с правами на разные таблицы.
Для того, чтобы воспользоваться, следует раскомментировать строки в admin.ini
(или вписать их):
[admin.users]
enabled=yes
И добавить ссылку на редактирование пользователей.
[admin.leftmenu]
admin_users "Администраторы системы"
Система предложить создать таблицу admin_users
. Для создания нового пользователя системы администрирования необходимо указать его логин, пароль и список таблиц, в которые он имеет доступ через запятую, например, pages, news, options
.
Все иконки администратора будут автоматически скрываться, если у администратора нет соответствующего доступа.
Доступ закрывается к таблицам, включая иконки, страницы редактирования и списка объектов, а также на сами действия по сохранению, созданию или удалению.
Более подробно будет описано в документации.
11.03.2014
Поддержка нормальных дат.
Наконец появилась возможность задавать даты в админке в поле формата date
, а не строки.
Итого, для использования в админке необходимо вписать:
date date_at "Дата"
Если будет передана пустая строка, то дата сохранится как NULL
, тоже самое касается класса ActiveRecord
в целом.
Внимание! Если вы манипулировали в своих проектах строками вида "0000-00-00 00:00:00", то теперь вместо них будет записываться NULL
Обязательное условие - название поля должно оканчиваться на _at
, например, date_at
, fired_at
, posted_at
.
Функция userdate
, преобразующая к нормальному виду, по-прежнему работает.
Появилась возможность написать
<?php
d()->Date(d()->this->posted_at)->to_simple(); // "24.03.2014"
d()->Date(d()->this->posted_at)->to_mysql(); // "2014-03-24 12:00:00"
Также обновлены тесты для пагинации и для проверки дат.
10.03.2014
Класс Upload
для простой загрузки файлов изображений.
Для самого простого использования:
$filename = d()->Upload->save();
В переменной $filename
будет находиться адрес к файлу (в случае картинки - готовой к созданию превью). По-умолчанию пустит только картинки и распространённые файлы.
Параметр upload
для формы, указывающий enctype
для загрузки файлов.
09.03.2014
Вывод текущей версии в админке (только для developer, подвал и страница обновления).
08.03.2014
Оптимизирован код ActiveRecord, убраны некоторые лишние проверки, которые никогда не будут вызваны.
Заведена история версий, которая будет использоваться для определения текущей версии системы (для обновления).
08.03.2014