Конфигурации в Coresky - energy-coresky/air GitHub Wiki
В Coresky, конфигурации бывают статические и динамические. Статические кэшируются в плане cache, а источником данных, обычно, являются Yaml или JSON файлы. Иногда бывает необходимо иметь возможность быстро изменить конфигурацию на продакшн. Для таких целей можно использовать Ghost SQL, которые сохраняют информацию в реляционных базах данных, а изменение данных, возможно из web-интерфейса или консоли. Ghost SQL можно рассматривать как функционал не только для конфигураций, а как специализированный функционал для работы с реляционными базами данных, который можно использовать различными способами.
Файлы config.yaml
И SKY-приложения и SKY-продукты, обязательно содержат файл config.yaml в главной директории плана app. В консоли всегда можно проверить, как парсятся yaml-файлы. В команду y скрипта sky также можно передать inline-Yaml, если второй параметр содержит пробел:
# parse config.yaml
> sky y mercury
# parse inlne-yaml
> sky y "- # array(0 => null)"
В первой команде выше, второй аргумент - имя продукта, по умолчанию main, основное приложение. Третий - имя файла (в примере выше отсутствует), по умолчанию config.yaml.
Файлы config.yaml, являются ключевыми. Можно определить сколь угодно файлов конфигураций, но ссылка на каждый, должна присутствовать в указанном файле, в этом случае, всегда возможно получить доступ к кэшированным конфигурационным данным с помощью функции cfg(..)
. Ключ верхнего уровня определяет раздел конфигурации, и раздел core обязателен. Вся информация этого раздела (и приложений и подключенных продуктов), кэшируется в файле var/cache/sky_plan.php, который подгружается всегда. Большинство данных, указанных в нём необходимо для работы ядра Coresky:
core: # mandatory section
timezone: $APP_TZ(UTC)
define:
DEV: $APP_DEV(false)
DEBUG: 0
DEV+DEBUG: 1 # 1, 2, 3 - verbosity level, 0 - debugging off
_PUBLIC: hole.sky
DEFAULT_LG: ''
ini_set:
log_errors: 0
display_errors: 0
DEV+display_errors: 1
profiles:
- Anonymous # pid=0 when don't authorized !!!
- Root # pid=1 for ultimate full access
- Mia # pid=2 for minimal access
databases: {driver: sqlite3, dsn: hole.base}
auth: # mandatory in web for users
crypt: false
test: ../.env
Для продуктов, подраздел plans также обязателен:
# this is an example of config.yaml from mercury ware
core: # mandatory section
plans: # sub-section is mandatory for wares
app:
type: dev # ware type definition is mandatory here
require: SQLite3
view: {path: $SELF/mvc}
cfg: {path: $SELF/mvc}
databases:
driver: sqlite3
dsn: $SELF/mercury.base
test2: ok
test3: composer.json
Подразделы plans, define, timezone, ini_set интегрируются в файл кэша особым образом. Информацию других подразделов раздела core, как и информацию других разделов, всегда можно прочесть с помощью функции cfg(..):
echo cfg()->databases['dsn']; # ware=main, name=core by default
echo cfg('auth')->crypt # ware=main by default, name=auth
echo cfg(['mercury'])->test2 # name=core by default, ware=mercury
print_r(cfg('test')); # ware=main (application) by default
print_r(cfg(['mercury', 'test3'])); # return stdClass object
Кэш-файлы других разделов, отличных core, сохраняются в отдельных файлах в директории var/cache (если план cache работает с помощью драйвера dc_file, но возможно использование dc_redis):
var/cache/cfg_{ware}_{name}.php
# where
# {ware} - ware name
# {name} - section name
Кэш-файлы разделов config.yaml, значениями которых являются массивы, генерируются одновременно с генерацией файла var/cache/sky_plan.php. А разделы, значениями которых является строка, т.е. указатель на внешний файл, генерируются во время первого опроса данных. Если нужно, чтобы такой раздел сгенерировал кэш во время генерации основного кэш-файла, нужно добавить оператор @inc: test: @inc ../.env
. Формат внешних файлов, определяется по расширению: .php php-файлы, .txt текстовые файлы, .yml, .yaml yaml-файлы, .json - json-файлы, в других случаях будет считаться, что формат файла - bang. В случае присоединения PHP-файлов, делается require
, т.е. подразумевается, что они организованы по схеме:
<?php
return [ # array or scalar
. . .
];
Для запуска функции cfg(..)
, в консоли, можно использовать команду eval:
> sky eval "print_r(cfg('test'));"
yml(..)
Функция Помимо извлечения конфигурационных данных с помощью функции cfg
, доступна к использованию функция yml
. Эту функцию удобно применять для случаев, когда yaml-описания, используются для программирования, а не просто для извлечения кэшированных конфигурационных данных:
# inline yaml не кэшируется:
yml('+ @json @inc(timezones)';
# inline yaml кэшируется в файле var/cache/yml_dev_dev.cfg.php:
yml('dev.cfg', '+ @inc(dev_cfg)');
# при использовании данных, передаются переменные, подобно работе Jet:
yml('dev.form', '+ @inc(dev_form)', [
'key' => $key,
'val' => $val,
]);
Формат "Bang"
Функция PHP explode(..)
разбивает строку в массив, где ключи - целочисленные значения. Функция Coresky bang(..)
похожа на предыдущую, но имеет два разделителя и разбивает строку в массив, где ключи - строки. С помощью такого формата, обычно упаковывают данные в файлах .env. Также, по сути, HTTP заголовок любого запроса или ответа - данные в формате "Bang". Это одноуровневый хэш, кодированный простейшим способом. В идеалистическом смысле, алгоритм работы с bang довольно быстр. В файле main/w2/core.php, имеются функции:
# упаковка
unbang($array, $via1 = ' ', $via2 = "\n") : string
# распаковка
bang($string, $via1 = ' ', $via2 = "\n") : array
Части строк, не содержащие разделитель via1 игнорируются:
$my_env_file = '
# this is an comment
KEY1=VAL1=..
KEY2=VAL2
'; # unl(..) - UnixNewLine: \r\n => \n, \r => \n
print_r(bang(unl($my_env_file), '=')); # array (
# 'KEY1' => 'VAL1=..',
# 'KEY2' => 'VAL2',
#)
Этот формат широко используется в Coresky, например в парсере Yaml или функционале Ghost. Во втором случае используются разделители " ", "\n" (via1, via2), а значения эскейпятся, так, что можно сохранять любые символы. Смотрите пример, как упаковывается массив. Обратное преобразование, также проходит без проблем:
$array = [
'k1' => "dat \n 1",
'k2' => "dat2 \\",
];
# упаковывается в:
$string = "k1 dat \\n 1\nk2 dat2 \\\\";
Синтаксис YML парсера
Парсером можно воспользоваться в любом месте кода или сделать проверку синтаксиса Yaml:
# parse inline yaml string:
$php_array = YML::text('- test: data');
# parse from file:
$php_array = YML::file('/path/filename.yml');
# lint the Yaml-string:
$is_ok = YML::lint('+ the scalar');
Coresky YML парсер, в основном, поддерживает стандартный Yaml-формат, хотя некоторые вещи не поддерживаются и есть собственные дополнения. Изменения, с одной стороны способствуют тому, чтобы сделать поведение парсера более простым и предсказуемым. С другой, более эффективно интегрируют парсер в фреймворк и раскрывают всю потенциальную мощь Yaml описаний.
Поддерживаются: комментарии, стандартная иерархия с помощью отступов, дефисов, двоеточий, а также JSON-нотация. Неявный многострочный режим с помощью отступов, а также явный, с помощью символов | и >. Нельзя использовать символ табуляции для отступов. Неявная типизация сведена к минимуму:
bool: true|false only! yes/no isn't bool!
null: null|`empty_string` only! ~ isn't null!
empty string: ""|'' only!
int: 100|+100|-100 decimal numbers only, same like PHP decimals
float: 100.0|1e2 & with sign, same like PHP floats
string: value # all other is string or just quote string
Не поддерживаются: директивы, начинающиеся с символа %...
, директивы: ---
, ...
. Не поддерживается явная типизация, например !!int
и неявная типизация, которая не включена в список поддерживаемой, например преобразование дат.
Дополнительный функционал YML
Стандартный multiple-yaml-document не поддерживается, но поддерживаются именованные множественные документы с помощью маркеров. Маркеры в yaml файлах, работают по той же схеме, что и маркеры компилятора представлений Jet (Coresky адаптация/модификация компилятора Laravel/Blade), и оператор @inc(..), работает по той же схеме. Это даёт возможность свободно применять принцип DRY и произвольно компоновать Yaml-данные:
#.run =========================
- @inc(.test)
- 2
#.run
#.test =========================
+ 123
#.test
# php code:
print_r(yml('+ @inc(run) filename.yml'));
# stdout: array(0 => 123, 1 => 2)
PHP поддерживает гибридные массивы со строковыми и целочисленными ключами, поэтому, разрешено совмещать такие ключи Yaml-нотации. Это даёт большие возможности для использования Yaml парсера в программировании, например можно выразительно и компактно описывать HTML-формы с помощью Yaml, смотрите пример в w2/__data.yaml. Ввиду того, что имеются операторы @inc
и @path
, для полноты по Тюрингу, в Yaml-нотации, к минусу добавлен плюс:
a:
b: @hex 11
x: ^y
+ d: # здесь + d: равносильно просто d: без плюса и отступа
e: eee
+ @path(a)
- @path(a)
+ @path(a.x)
- @path(a.x)
# return php array:
['a' =>
['b' => 17, 'x' => '^y'],
'd' => [
'e' => 'eee',
'b' => 17,
'x' => '^y',
'0' => ['b' => 17,'x' => '^y'],
'^y' => null,
'1' => '^y'
]
]
Второй пример Yaml: + scalar
. Yaml-код на выходе - скаляр (строка), а не массив PHP. Когда плюс на топ уровне иерархии и значение - скаляр, парсинг останавливается!
Yaml-файлы могут содержать TAIL/tilda-комментарии/данные. Вначале парсинга, Yaml разбивается на части с помощью следующего кода PHP: $TAIL = explode("\n~\n", $input)
. Парсером, всегда разбирается только часть $TAIL[0]
. В остальных частях хвоста, можно написать комментарии к файлу, без использования символа #, либо ссылаться на них в коде Yaml с помощью псевдопеременных $TAIL0 (основной Yaml), $TAIL или то-же самое $TAIL1, $TAIL2 и т.д., а также $TAILS. В последнем случае вернется массив хвостовых данных, но без $TAIL0:
+ $TAILS # int можно получить так: @dec @each $TAILS
- 555
+ $TAILS # здесь целочисленные ключи 0,1 изменятся на 3,4 !
- $TAILS
- $TAIL
- $TAIL2
~
123
~
2
# return php array:
[0 => '123', 1 => '2', # в $TAILS только строки !
2 => 555,
3 => '123', 4 => '2',
5 => [0 => '123', 1 => '2'],
6 => 123,
7 => 2,
]
Псевдопеременные можно указать только вначале значений Yaml или JSON нотаций. Их имена соответствуют регулярному выражению (только верхний регистр): /\$[A-Z_\d]+
. Кроме псевдопеременных группы $TAIL, имеется также $SELF - директория текущего файла. Продукты (ware) могут располагаться в разных местах и $SELF позволяет явно определять относительные пути.
Вместо явного значения, можно использовать подстановку переменных окружения (если есть скобки), например: $APP_DEV(false)
. Точнее будет производиться вызов метода Rare::env($key, $default)
, смотрите код в файле w2/rare.php. Если переменной окружения APP_DEV не существует, но существует файл .env в главной директории приложения, он будет считан и трактован как файл формата bang. Если и в нём не будет найдена переменная, будет подставлено значение по умолчанию, указанное в скобках - false. Имена переменных окружения могут быть только в верхнем регистре. Если необходимо указать в значении подобную строку - просто заключите её в кавычки. Также, в настройках можно использовать альтернативные DEV-конфигурации с помощью префиксов DEV+
, смотрите пример:
core:
define:
DEV: $APP_DEV(false)
TEST: "$JUST_STRING(false)" # строка в кавычках всегда просто строка
DEBUG: 0
DEV+DEBUG: 2 # альтернативное DEV значение
'DEV+TEST': # строка в кавычках всегда просто строка
file: $SELF/other.yml
Здесь, если DEV == true
, то значением ключа DEBUG будет 2, а если DEV == false
, то DEBUG будет равен 0. Псевдопеременная $SELF
: если вначале любого значения указана такая переменная, то вместо неё, будет подставлен путь к текущему yaml-файлу. Но если в парсер имя файла не передано, то будет подставлено ???
. Также можно ссылаться на глобальные константы (в основном это пути или константы определенные модулями PHP), и применять функции трансформации, например:
rss: $WWW/rss.xml
data: $DIR/var/data
pi: $M_PI # return 3.1415926535898
img: @base64 | # transformation function, same like !!binary in standard Yaml
R0lGODdhDQAIAIAAAAAAANnZ2SwAAAAADQAIAAACF4SDGQ
ar3xxbJ9p0qa7R0YxwzaFME1IAADs=
Известный модуль PECL yaml, позволяет использовать теги для значений Yaml, передавая callback-функции в функцию yaml_parse
. В Coresky применяется более мощный функционал с использованием функций трансформации (операторов), которые начинаются с символа @, за которым может следовать значение. Операторы Yaml используют тот-же формат, что и операторы Jet. Имеется некоторое множество встроенных функций, смотрите раздел ниже. Они могут использоваться со скобками или без, как и в Jet. Если скобок или значения нет - передается null
. Если скобка открылась и сразу закрылась, в $x передаётся пустая строка. При вызовах таких функций-операторов, им передаются следующие переменные:
- $v - значение, следуемое за оператором
- $x - параметр передаваемый оператору в круглых скобках
- &$a - массив, в котором содержится распарсенная часть файла, к моменту, когда вызывается оператор
- $has_var - булева переменная указывает на то, что значение, передаваемое в $v взято из переменной или указано явно
Приложения и продукты, могут дополнять список встроенных операторов, custom операторами. Они могут быть определены inline способом с помощью оператора @eval смотрите ниже. Также, их можно определить в общем или мастер контроллерах приложений, ровно как и custom операторы Jet. Однако следует знать, что такие операторы не подгружаются при работе в консоли:
. . . # Controller file
function yml_c() {
YML::directive('addhash', fn($v) => "#$v");
}
. . .
Также, custom операторы, можно определить в файлах mvc/yaml.php. В этом случае, они подгружаются при работе в консоли:
<?php
return [
'addhash' => fn($v) => "#$v",
];
Для одного значения, можно указать несколько операторов и операторы могут применяться каскадно для всех значений под-массива. Порядок выполнения - справа налево и снизу вверх. Для частной отмены каскадного выполнения, можно использовать @deny:
# yaml:
one: @right( RR)
two: @bin
- 0b11
- 101 # можно и без префикса 0b
- @deny @left(LL ) 1010
three: four
color: @left(#) @each @bang(. ) @sar(| +| ) > # not in cascade
aliceblue.f0f8ff antiquewhite.faebd7
beige.f5f5dc bisque.ffe4c4
# return php array:
['one' =>
['two' => [
0 => '3 RR',
1 => '5 RR'],
2 => 'LL 1010',
'three' => 'four RR',
],
'color' => ['aliceblue' => '#f0f8ff', 'antiquewhite' => '#faebd7',
'beige' => '#f5f5dc', 'bisque' => '#ffe4c4'],
]
Встроенные операторы
Трансформация значения:
@time - применить функцию PHP strtotime(..)
: int|false. Обрабатывается значение, а в скобках можно указать baseTimestamp
@date - применить функцию PHP date_create_immutable(..)
: DateTimeImmutable|false. Обрабатывается значение, а в скобках можно указать временную зону в формате, пригодном для функции PHP date_default_timezone_set(..)
, которое будет преобразовано в объект DateTimeZone
@ip - применить функцию PHP ip2long(..)
@hex2bin - применить функцию PHP hex2bin(..), байты можно разделять пробелом:
- @hex2bin >
48 65 6C 6C 6F 20 77 6F 72 64
21
array(0 => 'Hello word!')
@base64 - декодирование с помощью base64_decode(..)
. Эквивалентно !!binary стандартного Yaml.
@dec - все примеры десятичное integer:
- @dec 1234_5678_9012_3456 # card >>> 1234567890123456
- @dec 1 000 000 000 # big number >>> 1000000000
- @dec 2-777-222-22-22 # phone >>> 27772222222
@bin, @oct, @hex - трактовать значение, как integer в двоичной, восьмеричной или шестнадцатеричной системе счисления. Код бинарной функции: fn($v) => intval($v, 2)
@str - применить функцию PHP strval(..)
@json - применить функцию PHP json_encode(..)
@rot13 - применить функцию PHP str_rot13(..)
pwd: @rot13 arnaqreguny pelcgbtencul # :)
# parsed to PHP code:
['pwd' => 'neanderthal cryptography']
@object - сделать массив объектом класса stdClass
obj: @object @bang(=|) |
a=1|b=2|c=3
# parsed to PHP code:
['obj' => (object)[
'a' => '1',
'b' => '2',
'c' => '3',
]]
@left(string), @right(string) - дописать string
слева или справа
@sar(DelimSrchDelimRepl) - SearchAndReplace применить функцию PHP preg_replace(..), при том что Delim - разделитель один произвольный символ:
sar: @sar(|=+| is ) a=============1, b====2
# parsed to PHP code:
['sar' => 'a is 1, b is 2']
Из строки в массив или наоборот:
@csv(delimiter) - разбивает строку с помощью функции PHP explode(..)
@space - разбить строку по пробельным символам с помощью Regexp. В скобках можно указать максимальное количество элементов массива
@split - разбить строку с помощью функции PHP preg_split(..). В скобках необходимо указать Regexp
@scan - применить функцию PHP sscanf(..). В скобках - формат
@match - строку в массив. Применить функцию PHP preg_match(..). В скобках - Regexp. $match[0] автоматически удаляется
@url - применить функцию PHP parse_url(..)
@bang - трансформирует строку в формате bang в массив. В скобках можно указать один или два разделителя
@range - применить функцию PHP range(..)
@join(delimiter) - из массива в строку. Используется функция PHP implode(..)
Специальные операторы:
@@ - двойной амперсанд предназначен для JSON-нотации. Он работает в связке с другими операторами и несет действие, такое же как и плюс в ключе YAML-нотации. Примеры: @@inc(.yaml)
, @@path(top.level-1.level-2.level-3)
@inc - вставить значение, представленное во внешнем файле или другом маркере текущего файла. Маркеры работают только с форматом Yaml. Поддерживается 5 форматов, которые распознаются по расширению файла: .php (1), .txt (2), .yml или .yaml (3), .json (4), любые другие (5) расширения файлов, трактуют файл, как bang-fomat. Номинально файл указывается в значении, а маркер в параметре оператора. Если скобок нет - включается весь файл, а не его часть. Адресация файлов может быть явной, когда ware не используется для адресации или относительной к файлам плана app. Примеры включений:
# файл не указан, а только маркер, значит имеется ввиду файл Coresky w2/__data.yaml
# адресация явная, так как код Coresky не принадлежит ни одному плану
- @inc(phpman) # ниже то-же самое
- @inc(phpman) $DIR_S/w2/__data.yaml
# если маркер начинается с точки, то файл "свой", т.е. текущий. Аналогично в Jet
# адресация явная, так как файл "свой", планы не имеют значения
- @inc(.inner)
# включить весь файл, адресация явная, планы не имеют значения, использована $SELF
+ @inc $SELF/../.env
# включить весь файл, адресация относительная, ware - текущий, fomat: bang
+ @inc ../.env
# включить весь файл, ware - задан явно: venus, адресация относительно плана app
+ @inc venus::composer.json
Для формата bang, после имени файла, можно через пробел указать нестандартный разделитель via1 через пробел:
env: @inc .env =
~
via1 delimiter changed to equals sign. Bang file format sample:
LOG_DIR=var/log
SESSION_TIME=3600
# strings will skipped when equals sign absent
LOCALE=en
@path(..) - альтернатива якорям-ссылкам. Копирует значение из уже построенной части массива, адрес указывается ключами объединенными точкой, например:
one:
two: [1, 3]
three: @path(one.two.1) # this value will eq. to 3
@php - вставить PHP код, который можно написать в значении или параметре оператора, в скобках. Если этот оператор используется в JSON-нотации и в коде PHP есть запятые или другие символы, определяющие границы JSON-нотации, напишите код в скобках это исключит проблемы парсинга. Также код можно написать в $TAIL:
# yaml:
- string
- @php SomeClass::method([1, $var]) # no problem
- {a: @php(SomeClass::method([1, $var])), b: c} # no problem
# parsed to PHP cache:
return array(
0 => 'string',
1 => SomeClass::method([1, $var]),
2 => array('a' => SomeClass::method([1, $var]), 'b' => 'c'),
)
@preflight - в компилированный Yaml, можно добавить PHP-preflight код. Если есть скобки, код будет выполняться в изолированной области видимости, которая реализуется с помощью Closure. Если скобок нет - изоляции нет. Нужно всегда использовать плюс:
# yaml:
+ @preflight($key, &$val) |
return SomeClass::method($key, $val);
- @php OtherClass::method($__return)
# parsed to PHP cache:
$__return = call_user_func(function() use ($key, &$val) {
return SomeClass::method($key, $val);
});
return array(
0 => OtherClass::method($__return),
)
@eval - inline-custom-оператор. Код PHP оператора может быть в значении или параметре. Во втором случае, можно обработать значение этим кодом
@sql - выполнить SQL:
+ @sql(@select name, id from $_memory)
array(
'ajax' => 3,
. . .
'init' => 12,
)
@ini_get - получение данных конфигурации PHP с помощью ini_get(..)
@deny - отменить каскадное выполнение
@each - если контекст ожидает скаляр, а на входе массив, можно использовать @each
. Массив будет перебран с помощью PHP функции array_walk_recursive(..)
для функции, которая будет выполняться после @each
:
a: @eval("__$v")
b: @each @csv( ) one two
# b: @csv( ) one two <<<< error when @each absent
c: [three, four] # OK
d: five
['a' =>
['b' => [0 => '__one', 1 => '__two'],
'c' => [0 => '__three', 1 => '__four'],
],
'd' => 'five', # not in cascade
]
Конфигурация Redis
Если план cache должен использовать Redis или другой драйвер, отличный от dc_file, то это нужно настроить в файле bootsrap.php, так как этот план будет использоваться для сохранения главного кэш-файла. Поместите в самый конец файла примерно такой код:
SKY::$plans['cache'] = ['path' => 'L/cache', 'driver' => 'redis', 'dsn' => 'localhost'];
SKY::$plans['gate'] = ['path' => 'L/gate', 'use' => 'cache'];
SKY::$plans['jet'] = ['path' => 'L/jet', 'use' => 'cache'];
Автоматическая рекомпиляция кэша
В режиме DEV, Coresky отслеживает время модификации файлов источников и если было изменение, делается рекомпиляция. Это касается компилированных файлов в планах Jet, Gate. Для статических файлов *.css
и *.js
изменяется индекс ключа в query string, который всегда передается для адресации таких файлов. Это принуждает браузер обновить кешируемые файлы. В режиме DEV, также отслеживается модификация файла config.yaml приложения. Кэш-файл sky_plan.php в плане cache
, перекомпилируется автоматически при изменении config.yaml приложения. Однако аналогичные файлы продуктов не отслеживаются. Если вы изменили такой файл, необходимо удалить кэш руками, чтобы он заново создался:
> sky drop
> sky warm
На production, этот алгоритм не работает, время модификации файлов источников не отслеживается.
Призрачные SQL запросы
Если рассмотреть типичные, часто используемые алгоритмы работы с базами данных, то можно выделить один, который хорошо формализуется, а функциональная надстройка для него, позволит писать короткий и эффективный код приложений. В первую очередь, это касается конфигураций, которые хранятся в БД. Во вторых, представьте группу данных, которая может изменяться в различных местах веб-приложений и должна быть сохранена в БД. Чтобы исключить множественные UPDATE запросы, такие изменения можно сохранять в RAM и записать в БД один раз в конце обработки. В третьих, часто удобно работать с данными в БД как с переменными PHP, а чтение и сохранение таких данных в БД, может происходить автоматически.
Bang данные хранятся, в том числе, в ячейках БД типа TEXT:
var1 value1
var2 value2
...
varN valueN
При упаковке, символы переноса строк в значениях, заменяются на \r, \n, \t, \\ (только четыре символа). Представление данных удобно для чтения (изменения) программистом. Bang, как и упакованные другим способом данные, имеет следующие преимущества:
- чтобы добавить или удалить переменную, не нужны дополнительные действия с таблицей, где хранятся такие данные (ALTER TABLE и т.п.), т.е. возможно flash-использование;
- сохранение данных в одной ячейке, сохраняет сразу всю группу данных;
- возможно исключение запроса обновления данных в БД, если данные не изменились, хотя алгоритмически присутствовала запись в переменную памяти SKY;
Весь функционал Ghost SQL находится в файле sky.php, смотрите: SKY::flush(..)
, SKY::ghost(..)
, SKY::__callStatic(..)
. Функционал Ghost SQL работает не только с памятью SKY, но и любыми другими колонками в таблицах. Функционал Ghost, в ядре CORESKY используется около 8 раз, в том числе для хранения системной конфигурации в БД.
Использование Ghost SQL
В каждом случае использования функционала Ghost, назначается буква латинского алфавита, по которой будет идентифицироваться конкретный случай использования. Использование функционала Ghost в ядре CORESKY:
d - переменные для DEV-режима работы, хранится в var/mem/dev_vars.txt
s - системная конфигурация. Место хранения: memory.8
n - конфигурация для работы в консоле, реализация в классе Schedule. Место хранения: memory.9
a - конфигурация админ раздела. Место хранения: memory.10. Определяется в продукте (ware) RAS (Root-Admin Section) или альтернативных продуктах.
v - дополнительные свойства сессий посетителей. Место хранения: visitors.vmemo
u - дополнительные свойства авторизированных пользователей. Место хранения: users.umemo
i - используется в утилите SkyProject, см. class Install. Место хранения: memory.11
i,j - используется в утилите SkyLang, см. class Language. Код не используется совместно с SkyProject, поэтому возможно совмещение "i"
Замечание: планируется добавить возможность помещать данные Ghost в NO-SQL базы данных, например Redis, вместо реляционных.
Примеры использования:
# использование однобуквенного префикса:
echo $sky->s_online; # посетителей на сайте
$user->v_useragent = 'CORESKY'; # записать в сессию посетителя новый useragent
# то-же самое другим способом:
SKY::v('useragent', 'CORESKY');
Автоматическая запись в базу данных, происходит в SKY::shutdown()
, если во время использования SKY::ghost(..)
, был передан шаблон SQL или Closure для обновления данных и, во время работы скрипта, был установлен внутренний флаг. Для функционала Ghost, используемого в ядре CORESKY, все необходимые действия выполнены. И для чтения-записи в БД, достаточно чтения-записи в(из) переменную PHP.
Для функционала Ghost SKY-приложений, можно использовать любые буквы латинского алфавита кроме d s n a v u, занятые ядром. Код DEV-продуктов, обычно блокирует код приложений, поэтому коллизий не будет и в таких продуктах, можно использовать все буквы SKY-приложений. Так как нагрузка DEV-продуктов минимальна, местом хранения следует выбирать файлы, расположенные в директориях этих продуктов. Код PROD-продуктов используется совместно с кодом приложения, поэтому нужно корректно интегрировать функционал Ghost в код приложений. В этом случае, во время установки продуктов, использующих Ghost, будет производиться проверка на отсутствие коллизий по имени буквы и месту хранения или выбор (настройка) буквы и места хранения. Такие продукты должны содержать класс, соответствующий имени продукта и статический метод ghost(..)
в нём. Например, в продукте Ras имеется код, который используется в Root::_config()
:
<?php
class Ras
{
static function ghost($form = false) {
if ($form)
return [];
return ['a' => 10];
}
. . .
}
Здесь "a" - занимаемая буква Ghost, 10 - ID ряда в таблице memory
. Возможно, также передать форму в синтаксисе класса Form для настройки конфигурации. Она будет задействована в инструментах разработчика на странице Main / Config. На этой же странице, можно просмотреть всё текущее содержимое памяти.
Методы Ghost в классе SKY
Для чтения, записи и удаления переменных Ghost, используется магический метод SKY::__callStatic(..)
. В коде, в качестве имени метода используется буква - идентификатор Ghost. В примерах ниже, используется "s" - системная конфигурация:
SKY::s(string, scalar) - сохранить одну пару ключ-значение (bang)
SKY::s(array) - сохранить много пар ключ-значение (bang)
SKY::s(string) - вернуть одно значение (bang)
SKY::s(string, null) - удалить из БД одну пару (bang)
SKY::s(null, array) - провести запись в другие колонки (кроме памяти SKY), тип записи 2
SKY::s(null, string) - удалить одну колонку, тип записи 2
SKY::s() - вернуть true/false, - существует ли Ghost с данной буквой (в данном случае "s")
SKY::ghost($char, $original, $tpl = '', $flag = 0) - активация функционала призрачных SQL. Параметры метода:
$char - один символ (буква) для нового использования Ghost
$original - упакованная bang-строка, которая была считана из БД запросом SELECT. Также вариант использования: пустая строка.
$tpl - шаблон SQL или Closure для обновления данных в БД или файле. Если передать пустую строку, такое обновление не будет выполнено. Для функционала Ghost, в котором используется только лишь bang, необходимо передавать шаблон для sqlf(..), но когда используется второй тип записи, - шаблон для sql(..). Если был передан Closure, то callback функция будет вызвана, когда нужно обновить данные:
# Init DEV variables from file
$vars = Plan::mem_gq('dev_vars.txt');
SKY::ghost('d', $vars, fn($s) => Plan::mem_p(['main', 'dev_vars.txt'], $s));
SKY::flush(char, bool $return) - этот метод вызывается из SKY::shutdown()
для всех случаев использования призрачных SQL и может выполнять реальное обновление данных в БД. Иногда этот метод полезен и в коде приложений. Первый параметр - буква (идентификатор) частного случая Ghost. Второй параметр - булева переменная. Если true - запрос обновления не будет выполнен, но будет возвращен этим методом.
Shutdown в коде приложений
Даже когда происходят фатальные ошибки приложений, выполнение скрипта продолжается в SKY::shutdown()
, поэтому запись в БД, для функционала Ghost, будет произведена. Если в коде приложений, необходимо использование функции PHP register_shutdown_function(..)
, необходима уверенность, что выполнение Shutdown-кода приложения, будет происходить перед SKY::shutdown()
. Поэтому вместо использования функции PHP, это необходимо кодировать следующим образом: $sky->shutdown[] = [$this, 'shutdown'];
. Необходимо помнить, что фатальная ошибка, произошедшая во время выполнения функции shutdown()
, полностью остановит выполнение скрипта и обновление данных для Ghost SQL может не произойти. Нужно либо не использовать shutdown()
в коде приложений, либо тщательно проверять код пользовательской shutdown функции.