Смена пространства имён

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2021-07-27 11:17:46 +10:00
parent 7bf8ca6108
commit 5cfdeb03fd
31 changed files with 632 additions and 725 deletions

View File

@ -1,5 +1,5 @@
{
"name": "hood/vk",
"name": "mirzaev/vk",
"type": "framework",
"description": "Фреймворк VK API",
"keywords": [
@ -7,8 +7,8 @@
"api",
"hood"
],
"homepage": "https://git.hood.su/vk",
"license": "AGPL-3.0-or-later",
"homepage": "https://git.hood.su/mirzaev/vk",
"license": "free for you",
"authors": [
{
"name": "Arsen Mirzaev Tatyano-Muradovich",
@ -23,8 +23,8 @@
}
],
"support": {
"docs": "https://git.hood.su/hood/vk/manual",
"issues": "https://git.hood.su/hood/vk/issues"
"docs": "https://git.hood.su/mirzaev/vk/manual",
"issues": "https://git.hood.su/mirzaev/vk/issues"
},
"require": {
"php": "~8.0",
@ -39,12 +39,12 @@
},
"autoload": {
"psr-4": {
"hood\\vk\\": "hood/vk/system"
"mirzaev\\vk\\": "mirzaev/vk/system"
}
},
"autoload-dev": {
"psr-4": {
"hood\\vk\\tests\\": "hood/vk/tests"
"mirzaev\\vk\\tests\\": "mirzaev/vk/tests"
}
}
}

12
composer.lock generated
View File

@ -166,16 +166,16 @@
},
{
"name": "guzzlehttp/psr7",
"version": "1.8.1",
"version": "1.8.2",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "35ea11d335fd638b5882ff1725228b3d35496ab1"
"reference": "dc960a912984efb74d0a90222870c72c87f10c91"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/35ea11d335fd638b5882ff1725228b3d35496ab1",
"reference": "35ea11d335fd638b5882ff1725228b3d35496ab1",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91",
"reference": "dc960a912984efb74d0a90222870c72c87f10c91",
"shasum": ""
},
"require": {
@ -235,9 +235,9 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/1.8.1"
"source": "https://github.com/guzzle/psr7/tree/1.8.2"
},
"time": "2021-03-21T16:25:00+00:00"
"time": "2021-04-26T09:17:50+00:00"
},
{
"name": "hood/accounts",

View File

@ -1,52 +0,0 @@
<?php
declare(strict_types=1);
namespace Hood\VK\API;
class CallBack extends CallBackAbstract
{
/**
* Адрес для создания колбек-сервера
*
* @var string
*/
private $url;
/**
* Пользовательский ключ колбек-сессии
*
* @var string
*/
private $secret_key;
/**
* Ключ подтверждения колбек сессии
*
* @var string
*/
private $confirmation_token;
/**
* @var int
*/
private $group_id;
public function __construct(object $group, array $params = []){
$this->secret_key = $_ENV['CALLBACK_SECRET_KEY'];
$this->url = $_ENV['SERVER_DOMAIN'];
$this->group_id = $group->id;
$this->group_id->request('groups.addCallbackServer', [
'group_id' => $this->group_id,
'url' => $this->url,
'title' => $this->group_id . 'CallBackServer',
'secret_key' => $this->secret_key
]);
// $this->confirmation_token = request('groups.getCallbackConfirmationCode', [$this->group_id]);
echo $this->confirmation_token;
}
public function sendOk(){
echo 'ok';
}
}

View File

@ -1,222 +0,0 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use hood\vk\core;
use hood\vk\robots\robot;
use hood\vk\tests\settings;
use hood\accounts\vk as account;
/**
* @testdox API
*/
final class apiTest extends TestCase
{
use settings;
/**
* @var core $core Ядро фреймворка
*/
private static core $core;
/**
* @var account $account Аккаунт
*/
protected static account $account;
/**
* @var robot $robot Робот
*/
private static robot $robot;
/**
* @testdox Инициализация аккаунта
* @beforeClass
*/
public function testAccountInit(): void
{
// Проверка входных данных
if (empty(self::$project_id)) {
self::markTestSkipped('Не инициализирован идентификатор проекта');
}
// Инициализация аккаунта
self::$account = new account(empty(self::$id) ? rand(0, 10) : self::$id, self::$path_accounts);
// Запись режима SSL-протокола
self::$account->ssl = self::$ssl ?? true;
if (empty(self::$key)) {
// Если не указан ключ
// Проверка входных данных
if (empty(self::$login)) {
self::markTestSkipped('Не инициализирован входной аккаунта');
} else if (empty(self::$password)) {
self::markTestSkipped('Не инициализирован пароль аккаунта');
}
// Деаутентификация (на всякий случай)
self::$account->deauth();
// Аутентификация и генерация ключа
self::$key = self::$account->auth(self::$login, self::$password)->key(self::$project_id);
}
$this->assertNotNull(self::$key, 'Ошибка при инициализации ключа аккаунта');
}
/**
* @testdox Деинициализация аккаунта
* @afterClass
*/
public static function testAccountDeinit(): void
{
// Инициализация аккаунта
self::$account = new account(empty(self::$id) ? rand(0, 10) : self::$id, self::$path_accounts);
// Деаутентификация
self::$account->deauth();
}
/**
* @testdox Инициализация робота
* @before
*/
public function testRobotGroupInit(): void
{
// Инициализация ядра
self::$core = core::init();
// Сохранение количества роботов
$count = self::$core->robots;
// Инициализация робота
self::$robot = self::$core->group(empty(self::$group_id) ? rand(0, 10) : self::$group_id);
// Проверка
$this->assertEquals(self::$core->robots, $count + 1, 'Ошибка при инициализации робота');
}
/**
* @testdox Деинициализация робота
* @after
*/
public function testRobotGroupDeinit(): void
{
// Очистка реестра
self::$core->delete();
// Проверка
$this->assertEmpty(self::$core->get(self::$robot->id), 'Ошибка при деинициализации робота');
}
/**
* @testdox Инициализация (безопасная)
*/
public function testSafeInit(): void
{
// Инициализация
$settings = self::$robot->key(self::$group_key)->api->init();
// Проверка
$this->assertNotNull($settings['access_token']);
$this->assertNotNull($settings['v']);
}
/**
* @testdox Реинициализация
*/
public function testReinit(): void
{
// Реинициализация
self::$robot->key(self::$group_key)->api->reinit();
}
/**
* @testdox Чтение робота
*/
public function testReadRobot(): void
{
// Чтение робота
$this->assertNotNull(self::$robot->key(self::$group_key)->api->robot);
}
/**
* @testdox Запись настроек
*/
public function testWriteSettings(): void
{
// Проверка выброса исключения
$this->expectExceptionMessage('Запрещено перезаписывать настройки');
// Запись настроек
self::$robot->key(self::$group_key)->api['settings'] = ['settings'];
// Проверка
$this->assertTrue(!empty(self::$robot->api(['settings'])));
}
/**
* @testdox Чтение элемента настроек
*/
public function testReadSettingsElement(): void
{
// Проверка выброса исключения
$this->expectExceptionMessage('Не найдено: settings[\'element\']');
// Чтение элемента настроек
self::$robot->key(self::$group_key)->api['element'];
}
/**
* @testdox Запись элемента настроек
*/
public function testWriteSettingsElement(): void
{
// Запись элемента настроек
self::$robot->key(self::$group_key)->api['element'] = 'element';
// Проверка
$this->assertNotNull(self::$robot->api['element']);
}
/**
* @testdox Выбор получателя по идентификатору
*/
public function testchooseDestinationById(): void
{
// Выбор получателя по идентификатору
self::$robot->key(self::$group_key)->api->chooseDestination(12345);
// Проверка
$this->assertNotNull(self::$robot->api['peer_id']);
}
/**
* @testdox Выбор получателей по идентификаторам
*/
public function testchooseDestinationByIds(): void
{
// Выбор получателей по идентификаторам
self::$robot->key(self::$group_key)->api->chooseDestination([12345, 12345]);
// Проверка
$this->assertNotNull(self::$robot->api['user_ids']);
}
/**
* @testdox Выбор получателя по домену
*/
public function testchooseDestinationByDomain(): void
{
// Выбор получателя по домену
self::$robot->key(self::$group_key)->api->chooseDestination('domain');
// Проверка
$this->assertNotNull(self::$robot->api['domain']);
}
}

View File

@ -1,199 +0,0 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use hood\vk\core;
use hood\vk\robots\robot;
use hood\vk\tests\settings;
use hood\vk\api\data;
use hood\accounts\vk as account;
/**
* @testdox Вложения
*/
final class dataTest extends TestCase
{
use settings;
/**
* @var core $core Ядро фреймворка
*/
private static core $core;
/**
* @var account $account Аккаунт
*/
protected static account $account;
/**
* @var robot $robot Робот
*/
private static robot $robot;
/**
* @var data $data Вложения
*/
private static data $data;
/**
* @testdox Инициализация аккаунта
* @beforeClass
*/
public function testAccountInit(): void
{
// Проверка входных данных
if (empty(self::$project_id)) {
self::markTestSkipped('Не инициализирован идентификатор проекта');
}
// Инициализация аккаунта
self::$account = new account(empty(self::$id) ? rand(0, 10) : self::$id, self::$path_accounts);
// Запись режима SSL-протокола
self::$account->ssl = self::$ssl ?? true;
if (empty(self::$key)) {
// Если не указан ключ
// Проверка входных данных
if (empty(self::$login)) {
self::markTestSkipped('Не инициализирован входной аккаунта');
} else if (empty(self::$password)) {
self::markTestSkipped('Не инициализирован пароль аккаунта');
}
// Деаутентификация (на всякий случай)
self::$account->deauth();
// Аутентификация и генерация ключа
self::$key = self::$account->auth(self::$login, self::$password)->key(self::$project_id);
}
$this->assertNotNull(self::$key, 'Ошибка при инициализации ключа аккаунта');
}
/**
* @testdox Деинициализация аккаунта
* @afterClass
*/
public static function testAccountDeinit(): void
{
// Инициализация аккаунта
self::$account = new account(empty(self::$id) ? rand(0, 10) : self::$id, self::$path_accounts);
// Деаутентификация
self::$account->deauth();
}
/**
* @testdox Инициализация робота
* @before
*/
public function testRobotGroupInit(): void
{
// Инициализация ядра
self::$core = core::init();
// Сохранение количества роботов
$count = self::$core->robots;
// Инициализация робота
self::$robot = self::$core->group(empty(self::$group_id) ? rand(0, 10) : self::$group_id);
// Проверка
$this->assertEquals(self::$core->robots, $count + 1, 'Ошибка при инициализации робота');
}
/**
* @testdox Деинициализация робота
* @after
*/
public function testRobotGroupDeinit(): void
{
// Очистка реестра
self::$core->delete();
// Проверка
$this->assertEmpty(self::$core->get(self::$robot->id), 'Ошибка при деинициализации робота');
}
/**
* @testdox Инициализация вложений
* @before
*/
public function testDataInit(): void
{
if (isset(self::$robot)) {
// Инициализация вложений
self::$data = new data(self::$robot);
}
}
/**
* @testdox Чтение вложений
*/
public function testReadAttachments(): void
{
// Проверка
$this->assertIsArray(self::$data->data);
}
/**
* @testdox Запись вложения
*/
public function testWriteAttachment(): void
{
// Запись вложения
self::$data->addData('Вложение');
// Проверка
$this->assertNotEmpty(self::$data->data);
}
/**
* @testdox Запись вложения (повторная)
*/
public function testWriteAttachmentWhenItIsAlreadyWrited(): void
{
//Запись вложения
self::$data->addData('Вложение');
// Повторная запись вложения
self::$data->addData('Вложение');
// Проверка
$this->assertSame(['Вложение', 'Вложение'], self::$data->data);
}
/**
* @testdox Запись более 10 вложений
*/
public function testWriteAttachmentWhenLimitIsExceed()
{
// Проверка выброса исключения
$this->expectExceptionMessage('Превышен лимит вложений (10)');
//Запись вложений
self::$data->addData('1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11');
}
/**
* @testdox Очистка вложений
*/
public function testClearAttachments(): void
{
//Запись вложения
self::$data->addData('Вложение');
// Очистка вложений
self::$data->clear();
// Проверка
$this->assertEmpty(self::$data->data);
}
}

View File

@ -1,78 +0,0 @@
<?php
declare(strict_types=1);
namespace hood\vk\tests;
trait settings
{
/**
* @var string $path_account папка для куки
*/
protected static string $path_accounts = null;
/**
* @var int $id Идентификатор аккаунта
*/
protected static int $id = null;
/**
* @var int $id Идентификатор вспомогательного аккаунта
*/
protected static int $target_id = null;
/**
* @var string $password Входной аккаунта (если не указан ключ)
*/
protected static string $login = null;
/**
* @var string $password Пароль аккаунта (если не указан ключ)
*/
protected static string $password = null;
/**
* @var string $key Ключ аккаунта
*/
protected static string $key = null;
/**
* @var int $group_id Идентификатор группы
*/
protected static int $group_id = null;
/**
* @var string $key Ключ группы
*/
protected static string $group_key = null;
/**
* @var float $version Версия API
*/
protected static float $version = null;
/**
* @var int $project_id Идентификатор проекта
*/
protected static int $project_id = null;
/**
* @var string $project_key Ключ проекта
*/
protected static string $project_key = null;
/**
* @var string $project_service_key Сервисный ключ проекта
*/
protected static string $project_service_key = null;
/**
* @var bool $ssl SSL-протокол
*/
protected static bool $ssl = false;
/**
* @var string $path_photo Путь к Фото
*/
protected static string $path_photo = null;
}

View File

@ -0,0 +1,52 @@
<?php
// declare(strict_types=1);
// namespace Hood\VK\API;
// class CallBack extends CallBackAbstract
// {
// /**
// * Адрес для создания колбек-сервера
// *
// * @var string
// */
// private $url;
// /**
// * Пользовательский ключ колбек-сессии
// *
// * @var string
// */
// private $secret_key;
// /**
// * Ключ подтверждения колбек сессии
// *
// * @var string
// */
// private $confirmation_token;
// /**
// * @var int
// */
// private $group_id;
// public function __construct(object $group, array $params = []){
// $this->secret_key = $_ENV['CALLBACK_SECRET_KEY'];
// $this->url = $_ENV['SERVER_DOMAIN'];
// $this->group_id = $group->id;
// $this->group_id->request('groups.addCallbackServer', [
// 'group_id' => $this->group_id,
// 'url' => $this->url,
// 'title' => $this->group_id . 'CallBackServer',
// 'secret_key' => $this->secret_key
// ]);
// // $this->confirmation_token = request('groups.getCallbackConfirmationCode', [$this->group_id]);
// echo $this->confirmation_token;
// }
// public function sendOk(){
// echo 'ok';
// }
// }

View File

@ -2,11 +2,11 @@
declare(strict_types=1);
namespace hood\vk\api;
namespace mirzaev\vk\api;
use Exception;
use hood\vk\core,
hood\vk\robots\robot;
use mirzaev\vk\core,
mirzaev\vk\robots\robot;
/**
* LongPoll
@ -23,7 +23,7 @@ use hood\vk\core,
* @see https://vk.com/dev/groups.getLongPollServer
* @see https://vk.com/dev/groups.setLongPollSettings
*
* @package hood\vk\api
* @package mirzaev\vk\api
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*
* @todo Добавить обработку ошибок ($request['errors];)
@ -66,13 +66,10 @@ final class longpoll
*/
public function __construct(private robot $robot)
{
// Инициализация робота
match (true) {
!isset($robot->id) => throw new Exception('Необходимо указать идентификатор ВКонтакте'),
!isset($robot->key) => throw new Exception('Необходимо указать ключ для доступа к LongPoll'),
!isset($robot->version) => throw new Exception('Необходимо указать версию используемого API ВКонтакте'),
default => null
};
// Инициализация
if (empty($robot->id)) throw new Exception('Необходимо указать идентификатор ВКонтакте');
if (empty($robot->key)) throw new Exception('Необходимо указать ключ для доступа к LongPoll');
if (empty($robot->api['v'])) throw new Exception('Необходимо указать версию используемого API ВКонтакте');
// Остановка процессов-дубликатов
if (!file_exists(core::init()->path_temp)) {
@ -185,6 +182,8 @@ final class longpoll
*
* @param int $wait Время ожидания новых событий (в секундах)
*
* @todo Проверка на ошибки запроса, включая на наличие доступа к лонгполл у ключа
*
* @return array
*/
public function get(int $wait = 25): array
@ -201,16 +200,25 @@ final class longpoll
// Запрос на получение доступа и данных LongPoll-сервера
$response = json_decode($this->robot->browser->request(method: 'POST', uri: 'groups.getLongPollServer', options: [
'form_params' => $this->robot->api['settings']
])->getBody()->getContents())->response;
])->getBody()->getContents());
if (isset($response->error)) {
// Что-то сделать
var_export($response->error); die;
}
// Инициализация
$response = $response->response;
// Ключ доступа
$this->key = $response->key;
$this->key = $response->key;
// Сервер хранящий события
$this->server = $response->server;
$this->server = $response->server;
// Идентификатор последнего события
$this->ts = $response->ts;
$this->ts = $response->ts;
}
// Запрос на получение событий

View File

@ -2,14 +2,14 @@
declare(strict_types=1);
namespace hood\vk\api\methods;
namespace mirzaev\vk\api\methods;
use Exception;
use hood\accounts\vk;
use hood\vk\robots\robot;
use hood\vk\api\data;
use hood\vk\robots\group;
use mirzaev\accounts\vk;
use mirzaev\vk\robots\robot;
use mirzaev\vk\api\data;
use mirzaev\vk\robots\group;
/**
* Сообщение
@ -19,7 +19,7 @@ use hood\vk\robots\group;
* @see https://vk.com/dev/messages.send
* @see https://vk.com/dev/messages.getById
*
* @package hood\vk\api
* @package mirzaev\vk\api
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*
* @todo Доработать строгий режим отправки: проверку сообщения в беседе (не имеет ID сообщений)

View File

@ -2,26 +2,26 @@
declare(strict_types=1);
namespace hood\vk\api\methods;
namespace mirzaev\vk\api\methods;
use hood\vk\robots\robot;
use mirzaev\vk\robots\robot;
/**
* Абстракция метода API
*
*
* @method protected static put(string $url, ...$params) Создать
* @method protected static post(string $url, ...$params) Изменить
* @method protected static get(string $url, ...$params) Получить
* @method protected static delete(string $url, ...$params) Удалить
*
* @package hood\vk\api\methods
*
* @package mirzaev\vk\api\methods
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*/
abstract class method
{
/**
* Создать
*
*
* @return array Ответ сервера
*/
public static function put(): array
@ -31,7 +31,7 @@ abstract class method
/**
* Изменить
*
*
* @return array Ответ сервера
*/
public static function post(): array
@ -41,7 +41,7 @@ abstract class method
/**
* Получить
*
*
* @return array Ответ сервера
*/
public static function get(): array
@ -51,7 +51,7 @@ abstract class method
/**
* Удалить
*
*
* @return array Ответ сервера
*/
public static function delete(): array

View File

@ -2,12 +2,12 @@
declare(strict_types=1);
namespace hood\vk\api\methods;
namespace mirzaev\vk\api\methods;
use hood\vk\robots\robot,
hood\vk\robots\group;
use mirzaev\vk\robots\robot,
mirzaev\vk\robots\group;
use hood\accounts\vk as account;
use mirzaev\accounts\vk as account;
use Exception;
@ -19,7 +19,7 @@ use Exception;
* @see https://vk.com/dev/photos.getUploadServer
* @see https://vk.com/dev/messages.getById
*
* @package hood\vk\api\methods
* @package mirzaev\vk\api\methods
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*
* @todo Добавить обработку ошибок ($request['errors];)
@ -194,7 +194,7 @@ final class photos extends method
/**
* Получить адрес сервера сообщений
*
*
* @return object
*/
public function getMessageServer(): object
@ -245,7 +245,7 @@ final class photos extends method
return $request;
}
/**
/**
* Получить id фото для сообщения
*
* $robot робот
@ -291,6 +291,6 @@ final class photos extends method
$request;
// Ссылка на фото
return 'photo' . $request->response[0]->owner_id . '_' . $request->response[0]->id;
}
}

View File

@ -2,9 +2,9 @@
declare(strict_types=1);
namespace hood\vk\api;
namespace mirzaev\vk\api;
use hood\vk\robots\robot;
use mirzaev\vk\robots\robot;
use Throwable;
use Exception;
@ -20,11 +20,18 @@ use ArrayAccess;
* @todo
* 1. Создать __isset(), __unset()
*
* @package hood\vk\api
* @package mirzaev\vk\api
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*/
class settings implements ArrayAccess
{
/**
* Версия API ВКонтакте по умолчанию
*
* Должна иметь тип string потому, что PHP при стандартных настройках удаляет нули у float
*/
protected const VK_API_VERSION_DEFAULT = '5.130';
/**
* Конструктор
*/
@ -43,18 +50,21 @@ class settings implements ArrayAccess
/**
* Инициализация (безопасная)
*
* @var float|null $version Версия API
* @var float $version Версия API (переопределять не рекомендуется)
*/
public function init(float|null $version = null): self
public function init(string $version = self::VK_API_VERSION_DEFAULT): self
{
if (isset($blocked)) {
// Инициализация
static $blocked = false;
if ($blocked) {
// Блокировка найдена
throw new Exception('Повторная инициализация запрещена', 500);
}
// Блокировка
static $blocked = true;
$blocked = true;
// Инициализация
try {
@ -69,9 +79,9 @@ class settings implements ArrayAccess
/**
* Реинициализация
*
* @var float|null $version Версия API
* @var float $version Версия API (переопределять не рекомендуется)
*/
public function reinit(float|null $version = null): self
public function reinit(string $version = null): self
{
// Буфер
$version = $version ?? $this->settings['v'] ?? null;
@ -92,9 +102,9 @@ class settings implements ArrayAccess
/**
* Инициализация
*
* @var float $version Версия API
* @var float $version Версия API (переопределять не рекомендуется)
*/
protected function _init(float $version = 5.124): self
protected function _init(string $version = self::VK_API_VERSION_DEFAULT): self
{
// Ключ
$this->settings['access_token'] = $this->robot->key;
@ -106,26 +116,30 @@ class settings implements ArrayAccess
}
/**
* Записать получателя
* Определить и записать получателя
*
* Определяет получателей по входным параметрам
*
* @see hood\vk\api\methods\messages Сообщения
* @see mirzaev\vk\api\methods\messages Сообщения
*/
public function writeDestination(string|array|int $destination): void
public function destination(string|array|int $target): self
{
if (is_int($destination)) {
if (is_int($target)) {
// Идентификатор
$this->settings['peer_id'] = $destination;
} else if (is_array($destination)) {
$this->settings['peer_id'] = $target;
return $this;
} else if (is_array($target)) {
// Идентификаторы
$this->settings['user_ids'] = $destination;
} else if (is_string($destination)) {
$this->settings['user_ids'] = $target;
return $this;
} else if (is_string($target)) {
// Домен
$this->settings['domain'] = $destination;
$this->settings['domain'] = $target;
return $this;
}
throw new Exception('Не удалось определить получателя', 500);
@ -142,8 +156,7 @@ class settings implements ArrayAccess
match ($name) {
'settings' => isset($this->settings) ? throw new Exception('Запрещено перезаписывать настройки', 500) : $this->settings = $value,
'robot' => isset($this->robot) ? throw new Exception('Запрещено перезаписывать Робота', 500) : $this->robot = $value,
'data' => $this->offsetSet('data', $value),
'attachments' => $this->offsetSet('attachments', $value),
'data', 'attachments' => $this->offsetSet('attachments', $value),
default => $this->offsetSet($name, $value)
};
}
@ -158,12 +171,21 @@ class settings implements ArrayAccess
return match ($name) {
'settings' => $this->settings ?? throw new Exception('Настройки не инициализированы', 500),
'robot' => $this->robot ?? throw new Exception('Робот не инициализирован', 500),
'data' => $this->offsetGet('data'),
'attachments' => $this->offsetGet('attachments'),
'data', 'attachments' => $this->offsetGet('attachments'),
default => $this->offsetGet($name)
};
}
// public function __unset(string $name): void
// {
// match ($name) {
// 'settings' => throw new Exception('Запрещено удалять настройки', 500),
// 'robot' => throw new Exception('Запрещено удалять робота', 500),
// 'data', 'attachments' => $this->offsetUnset('attachments'),
// default => $this->offsetUnset($name)
// };
// }
/**
* Записать по смещению
*/
@ -187,8 +209,14 @@ class settings implements ArrayAccess
return $this->settings['attachments'] = $value;
}
// Конкатенация
return $this->settings['attachments'][] = $value;
if (empty($this->settings['attachments']) || count($this->settings['attachments']) < 10) {
// Записано менее чем 10 вложений (от 0 до 9)
// Запись (конкатенация)
return $this->settings['attachments'][] = $value;
}
throw new Exception('Превышено ограничение на 10 вложений', 500);
} else {
// Запись по ключу или смещению
@ -219,7 +247,7 @@ class settings implements ArrayAccess
return $this->settings[$offset];
}
is_int($offset) ? throw new Exception("Смещение $offset не найдено", 404) : throw new Exception("Ключ $offset не найден", 404);
throw new Exception(is_int($offset) ? "Смещение $offset не найдено" : "Ключ $offset не найден", 404);
}
throw new Exception('Настройки не инициализированы', 500);

View File

@ -2,11 +2,11 @@
declare(strict_types=1);
namespace hood\vk;
namespace mirzaev\vk;
use hood\vk\robots\robot;
use hood\vk\traits\singleton;
use hood\vk\loggers\jasmo;
use mirzaev\vk\robots\robot;
use mirzaev\vk\traits\singleton;
use mirzaev\vk\loggers\jasmo;
use Exception;
@ -23,7 +23,7 @@ use Exception;
* @method public function set($id, $value) Запись в реестр
* @method public function get($id = null) Чтение из реестра
*
* @package hood\vk
* @package mirzaev\vk
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*/
final class core
@ -75,16 +75,14 @@ final class core
private string $path_temp;
/**
* Журналист
* Запись в журнал
*
* @param string $file Файл для журналирования
*
* @return self
*
* @todo Добавить установку иного журналиста по спецификации PSR-3
* @todo Более гибкое журналирование
*/
public function log(string $file = null): self
public function journal(string $file = null): self
{
// Инициализация журналиста (требует переработки)
jasmo::init()::post($file)::postErrorHandler()::postShutdownHandler();
@ -98,9 +96,7 @@ final class core
* @param int $id
* @param robot $robot
*
* @see hood\vk\traits\registry Модификация метода
*
* @return void
* @see mirzaev\vk\traits\registry Модификация метода
*/
public function write(int $id, robot $robot): void
{
@ -131,7 +127,7 @@ final class core
* @param int|null $id Идентификатор
* @param int|null $session Сессия
*
* @see hood\vk\traits\registry Модификация метода
* @see mirzaev\vk\traits\registry Модификация метода
*
* @return mixed Весь реестр, робота или сессию робота
*/
@ -171,9 +167,7 @@ final class core
* @param int|null $id Идентификатор
* @param int|null $session Сессия
*
* @see hood\vk\traits\registry Модификация метода
*
* @return void
* @see mirzaev\vk\traits\registry Модификация метода
*/
public function delete(int|null $id = null, int|null $session = null): void
{
@ -222,8 +216,6 @@ final class core
*
* @param mixed $name Название
* @param mixed $value Значение
*
* @return void
*/
public function __set(mixed $name, mixed $value): void
{
@ -239,17 +231,15 @@ final class core
* Прочитать свойство
*
* @param mixed $name Название
*
* @return mixed
*/
public function __get(mixed $name): mixed
{
return match ($name) {
'robots' => $this->robots,
'timezone' => !isset($this->timezone) ? $this->timezone = 'Europe/Moscow' : $this->timezone,
'path_root' => !isset($this->path_root) ? $this->path_root = dirname(__DIR__) : $this->path_root,
'path_logs' => !isset($this->path_logs) ? $this->path_logs = $this->path_root . '/logs' : $this->path_logs,
'path_temp' => !isset($this->path_temp) ? $this->path_root . '/temp' : $this->path_temp,
'timezone' => $this->timezone ?? $this->timezone = 'Europe/Moscow',
'path_root' => $this->path_root ?? $this->path_root = dirname(__DIR__),
'path_logs' => $this->path_logs ?? $this->path_logs = $this->__get('path_root') . '/logs',
'path_temp' => $this->path_temp ?? $this->path_temp = $this->__get('path_root') . '/temp',
default => null
};
}
@ -262,12 +252,10 @@ final class core
*
* @param string $method Метод
* @param array $params Параметры
*
* @return robot
*/
public function __call(string $method, array $params): robot
{
if (class_exists($robot = '\\hood\\vk\\robots\\' . $method)) {
if (class_exists($robot = '\\mirzaev\\vk\\robots\\' . $method)) {
// Если найден класс реализующий запрошенного робота
return new $robot(...$params);
} else {

View File

@ -2,25 +2,25 @@
declare(strict_types=1);
namespace hood\vk\loggers;
namespace mirzaev\vk\loggers;
use DateTime;
use Monolog\logger;
use Monolog\Handler\StreamHandler;
use Jasny\ErrorHandler;
use hood\vk\core,
hood\vk\traits\singleton;
use mirzaev\vk\core,
mirzaev\vk\traits\singleton;
/**
* Журналист Jasmo
*
* Основан на "monolog/monolog" и "jasny/error-handler"
*
* Основан на "monolog/monolog" и "jasny/error-handler"
* Jasmo = Jasny + Monolog
*
*
* @see Monolog\logger
* @see Jasny\ErrorHandler
*
* @package hood\vk\loggers
*
* @package mirzaev\vk\loggers
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*/
final class jasmo extends logger
@ -37,7 +37,7 @@ final class jasmo extends logger
// /**
// * Экземпляр класса обработчика ошибок
// *
// * @var ErrorHandler
// * @var ErrorHandler
// */
// public ErrorHandler $handler;
@ -45,15 +45,15 @@ final class jasmo extends logger
{
$file = $file ?? date_format(new DateTime(core::init()->timezone), 'Y.m.d');
/**
/**
* Создание логгера по спецификации PSR-3 (Monolog)
*
*
* @param string Название канала логирования
*/
self::$logger = new logger(__CLASS__);
/**
* Создание обработчиков (порядок обязателен)
/**
* Создание обработчиков (порядок обязателен)
*/
self::$logger->pushHandler(new StreamHandler(core::init()->path['logs'] . "/${file}-INFO.log", logger::INFO, false)); // Инфомация о процессе работы
self::$logger->pushHandler(new StreamHandler(core::init()->path['logs'] . "/${file}-NOTICE.log", logger::NOTICE, false)); // Уведомления
@ -89,7 +89,7 @@ final class jasmo extends logger
public static function postErrorHandler(): ?jasmo
{
/**
/**
* Подключение логгера в обработчик ошибок (Jasny)
*/
$handler = new ErrorHandler(self::$logger);

View File

@ -2,12 +2,12 @@
declare(strict_types=1);
namespace hood\vk\loggers;
namespace mirzaev\vk\loggers;
/**
* Абстрактный класс журналиста
*
* @package hood\vk\loggers
*
* @package mirzaev\vk\loggers
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*/
abstract class logger
@ -22,4 +22,4 @@ abstract class logger
abstract static public function post($file = null): ?logger;
abstract static public function get(): ?logger;
abstract static public function delete(): ?logger;
}
}

View File

@ -2,10 +2,10 @@
declare(strict_types=1);
namespace hood\vk\robots;
namespace mirzaev\vk\robots;
use hood\vk\robots\robot;
use hood\vk\api\longpoll;
use mirzaev\vk\robots\robot;
use mirzaev\vk\api\longpoll;
use Throwable;
use Exception;
@ -19,7 +19,7 @@ use Exception;
* @method public function __get($name) Чтение свойства
* @method public function __isset($name) Проверка на инициализированность свойства
*
* @package hood\vk\robots
* @package mirzaev\vk\robots
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*/
final class group extends robot
@ -35,7 +35,7 @@ final class group extends robot
* @param string $name Название
* @param mixed $value Значение
*
* @see hood\vk\robots\robot Наследуемый метод
* @see mirzaev\vk\robots\robot Наследуемый метод
*
* @return void
*/
@ -58,7 +58,7 @@ final class group extends robot
*
* @param string $name Название
*
* @see hood\vk\robots\robot Наследуемый метод
* @see mirzaev\vk\robots\robot Наследуемый метод
*
* @return mixed
*/

View File

@ -2,19 +2,19 @@
declare(strict_types=1);
namespace hood\vk\robots;
namespace mirzaev\vk\robots;
use Exception;
use GuzzleHttp\Client as browser;
use hood\vk\core;
use hood\vk\proxies\proxy;
use hood\vk\captcha\captcha;
use hood\vk\api\settings as api;
use hood\vk\api\methods\method;
use mirzaev\vk\core;
use mirzaev\vk\proxies\proxy;
use mirzaev\vk\captcha\captcha;
use mirzaev\vk\api\settings as api;
use mirzaev\vk\api\methods\method;
use hood\accounts\vk as account;
use mirzaev\accounts\vk as account;
/**
@ -41,7 +41,7 @@ use hood\accounts\vk as account;
* @method public static function __callStatic(string $method, array $params) Вызов статического метода
* @method public function __toString() Конвертация в строку
*
* @package hood\vk\robots
* @package mirzaev\vk\robots
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*/
abstract class robot
@ -241,7 +241,7 @@ abstract class robot
*/
public function __call(string $method, array $params): method
{
if (class_exists($class = '\\hood\\vk\\api\\methods\\' . $method . 's')) {
if (class_exists($class = '\\mirzaev\\vk\\api\\methods\\' . $method . 's')) {
// Если найден класс реализующий запрошенный метод
return new $class($this, ...$params);
}
@ -262,7 +262,7 @@ abstract class robot
*/
public static function __callStatic(string $method, array $params): method
{
if (class_exists($class = '\\hood\\vk\\api\\methods\\' . $method . 's')) {
if (class_exists($class = '\\mirzaev\\vk\\api\\methods\\' . $method . 's')) {
return $class(self, ...$params);
}

View File

@ -2,16 +2,16 @@
declare(strict_types=1);
namespace hood\vk\robots;
namespace mirzaev\vk\robots;
use hood\vk\robots\robot;
use mirzaev\vk\robots\robot;
use hood\accounts\vk as account;
use mirzaev\accounts\vk as account;
/**
* Робот-пользователь
*
* @package hood\vk\robots
* @package mirzaev\vk\robots
* @author Arsen Mirzaev Tatyano-Muradovich <red@hood.su>
*/
final class user extends robot

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace hood\vk\traits;
namespace mirzaev\vk\traits;
/**
* Паттерн registry

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace hood\vk\traits;
namespace mirzaev\vk\traits;
use Exception;
@ -27,7 +27,7 @@ trait singleton
/**
* Инициализация
*
*
* @return self
*/
public static function init(): self

View File

@ -0,0 +1 @@
9104

View File

@ -0,0 +1,273 @@
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use mirzaev\vk\core;
use mirzaev\vk\robots\robot;
use mirzaev\vk\tests\settings;
use mirzaev\accounts\vk as account;
use Exception as RealException;
/**
* @testdox API ВКонтакте
*/
final class apiTest extends TestCase
{
use settings;
/**
* @var core $core Ядро фреймворка
*/
private static core $core;
/**
* @var account $account Аккаунт
*/
protected static account $account;
/**
* @var robot $robot Робот
*/
private static robot $robot;
/**
* @testdox Инициализация аккаунта
* @beforeClass
*/
public function testAccountInit(): void
{
// Проверка входных данных
if (empty(self::$project_id)) {
self::markTestSkipped('Не инициализирован идентификатор проекта');
}
// Инициализация аккаунта
self::$account = new account(empty(self::$id) ? rand(0, 10) : self::$id, self::$path_accounts);
// Запись режима SSL-протокола
self::$account->ssl = self::$ssl ?? true;
if (empty(self::$key)) {
// Если не указан ключ
// Проверка входных данных
if (empty(self::$login)) {
self::markTestSkipped('Не инициализирован входной аккаунта');
} else if (empty(self::$password)) {
self::markTestSkipped('Не инициализирован пароль аккаунта');
}
// Деаутентификация (на всякий случай)
self::$account->deauth();
// Аутентификация и генерация ключа
self::$key = self::$account->auth(self::$login, self::$password)->key(self::$project_id);
}
$this->assertNotNull(self::$key, 'Ошибка при инициализации ключа аккаунта');
}
/**
* @testdox Деинициализация аккаунта
* @afterClass
*/
public static function testAccountDeinit(): void
{
// Инициализация аккаунта
self::$account = new account(self::$id ?? rand(0, 10), self::$path_accounts);
// Деаутентификация
self::$account->deauth();
}
/**
* @testdox Инициализация робота-группы
* @before
*/
public function testRobotGroupInit(): void
{
// Инициализация ядра
self::$core = core::init();
// Сохранение количества роботов
$count = self::$core->robots;
// Инициализация робота
self::$robot = self::$core->group(self::$group_id ?? rand(0, 10));
// Проверка
$this->assertSame(self::$core->robots, $count + 1, 'Ошибка при инициализации робота-группы');
}
/**
* @testdox Деинициализация робота-группы
* @after
*/
public function testRobotGroupDeinit(): void
{
// Очистка реестра
self::$core->delete();
// Проверка выброса исключения (НЕ РАБОТАЕТ, ВЕРОЯТНО БАГ)
// $this->expectExceptionMessage('Робот с идентификатором ' . self::$robot->id . ' не найден');
// $this->expectExceptionCode(404);
try {
// Чтение
self::$core->read(self::$robot->id);
} catch (RealException $e) {
// Проверка
$this->assertSame('Робот с идентификатором ' . self::$robot->id . ' не найден', $e->getMessage(), 'Не удалось удалить робота');
}
}
/**
* @testdox Инициализация
*/
public function testInit(): void
{
// Инициализация
$settings = self::$robot->key(self::$group_key)->api->init(self::$version);
// Проверка
$this->assertNotNull($settings['access_token']);
$this->assertNotNull($settings['v']);
$this->assertSame($settings['v'], self::$version);
// Проверка
$this->expectExceptionMessage('Повторная инициализация запрещена');
// Инициализация (повторная)
$settings = self::$robot->api->init(self::$version);
}
/**
* @testdox Реинициализация
*/
public function testReinit(): void
{
// Реинициализация
self::$robot->key(self::$group_key)->api->reinit();
}
/**
* @testdox Запись и чтение параметра
*/
public function testWriteAndReadParameter(): void
{
// Запись
self::$robot->key(self::$group_key)->api['key'] = 'value';
// Проверка
$this->assertSame('value', self::$robot->api['key'], 'Не удалось записать или прочитать параметр');
}
/**
* @testdox Чтение неинициализированного параметра
*/
public function testReadUndefinedParameter(): void
{
// Проверка выброса исключения
$this->expectExceptionMessage('Ключ key не найден');
// Чтение
self::$robot->key(self::$group_key)->api['key'];
}
/**
* @testdox Выбор получателя по идентификатору
*/
public function testChooseDestinationById(): void
{
// Выбор получателя
self::$robot->key(self::$group_key)->api->destination(self::$target_id);
// Проверка
$this->assertSame(self::$target_id, self::$robot->api['peer_id'], 'Не удалось выбрать получателя по идентификатору');
}
/**
* @testdox Выбор получателей по идентификаторам
*/
public function testChooseDestinationsByIds(): void
{
// Выбор получателей
self::$robot->key(self::$group_key)->api->destination([self::$target_id, self::$target_id]);
// Проверка
$this->assertSame([self::$target_id, self::$target_id], self::$robot->api['user_ids'], 'Не удалось выбрать получателей по идентификаторам');
}
/**
* @testdox Выбор получателя по домену
*/
public function testChooseDestinationByDomain(): void
{
// Выбор получателя
self::$robot->key(self::$group_key)->api->destination(self::$target_domain);
// Проверка
$this->assertSame(self::$target_domain, self::$robot->api['domain'], 'Не удалось выбрать получателя по домену');
}
/**
* @testdox Запись, чтение и удаление вложений
*/
public function testWriteAndReadAttachments(): void
{
// Инициализация
self::$robot->key(self::$group_key);
// Запись
self::$robot->api['attachments'] = 'photo0000_0000';
self::$robot->api['attachments'] = 'video0000_0000';
self::$robot->api['attachments'] = 'audio0000_0000';
// Проверка
$this->assertSame(['photo0000_0000', 'video0000_0000', 'audio0000_0000'], self::$robot->api['attachments'], 'Не удалось записать или прочитать вложения');
// Удаление одного вложения
unset(self::$robot->api['attachments'][0]);
// Реинициализация смещений (для точной проверки)
self::$robot->api['attachments'] = array_values(self::$robot->api['attachments']);
// Проверка
$this->assertSame(['video0000_0000', 'audio0000_0000'], self::$robot->api['attachments'], 'Не удалось удалить или прочитать вложения');
// Удаление всех вложений
unset(self::$robot->api['attachments']);
// Проверка
$this->assertNull(self::$robot->api['attachments'], 'Не удалось удалить вложения');
}
/**
* @testdox Запись вложений с превышением ограничения
*/
public function testWriteWithOverflowAttachments()
{
// Проверка выброса исключения
$this->expectExceptionMessage('Превышено ограничение на 10 вложений');
// Инициализация
self::$robot->key(self::$group_key);
// Запись (11 вложений)
self::$robot->api['attachments'] = 'photo0000_0000';
self::$robot->api['attachments'] = 'video0000_0000';
self::$robot->api['attachments'] = 'audio0000_0000';
self::$robot->api['attachments'] = 'photo0000_0000';
self::$robot->api['attachments'] = 'video0000_0000';
self::$robot->api['attachments'] = 'audio0000_0000';
self::$robot->api['attachments'] = 'photo0000_0000';
self::$robot->api['attachments'] = 'video0000_0000';
self::$robot->api['attachments'] = 'audio0000_0000';
self::$robot->api['attachments'] = 'photo0000_0000';
self::$robot->api['attachments'] = 'video0000_0000';
}
}

View File

@ -4,15 +4,15 @@ declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use hood\vk\core;
use hood\vk\robots\robot;
use hood\vk\tests\settings;
use mirzaev\vk\core;
use mirzaev\vk\robots\robot;
use mirzaev\vk\tests\settings;
use hood\accounts\vk as account;
use hood\accounts\vk;
use mirzaev\accounts\vk as account;
use mirzaev\accounts\vk;
/**
* @testdox Сообщения
* @testdox [МЕТОД] Сообщения
*/
final class messagesTest extends TestCase
{
@ -99,7 +99,7 @@ final class messagesTest extends TestCase
self::$robot = self::$core->group(empty(self::$group_id) ? rand(0, 10) : self::$group_id);
// Проверка
$this->assertEquals(self::$core->robots, $count + 1, 'Ошибка при инициализации робота');
$this->assertSame(self::$core->robots, $count + 1, 'Ошибка при инициализации робота');
}
/**
@ -112,7 +112,7 @@ final class messagesTest extends TestCase
self::$core->delete();
// Проверка
$this->assertEmpty(self::$core->get(self::$robot->id), 'Ошибка при деинициализации робота');
$this->assertEmpty(self::$core->read(self::$robot->id), 'Ошибка при деинициализации робота');
}
/**
@ -145,13 +145,13 @@ final class messagesTest extends TestCase
public function testWriteTextWhenHeIsAlreadyWrited(): void
{
// Запись текста
$message = self::$robot->message()->text('text');
$message = self::$robot->message()->text('hello');
// Повторная запись текста
$message->text('text');
$message->text(' world');
// Проверка
$this->assertEquals('texttext', $message->text);
$this->assertSame('hello world', $message->text, );
}
/**
@ -169,7 +169,7 @@ final class messagesTest extends TestCase
/**
* @testdox Получение информации о сообщении
*/
public function testgetById(): void
public function testGetById(): void
{
// Отправка сообщения
$id = self::$robot->key(self::$group_key)->message('Теста метода getByID')->send(self::$target_id);
@ -203,7 +203,7 @@ final class messagesTest extends TestCase
$message = self::$robot->message()->attachments('Вложение');
// Проверка
$this->assertEquals(['Вложение'], $message->data);
$this->assertSame(['Вложение'], $message->data);
}
/**
@ -272,7 +272,7 @@ final class messagesTest extends TestCase
// Запись пересылаемых сообщений
$message = self::$robot->message('Тест пересылки сообщений')->forward($id);
// Отпрравка пересылки сообщения
$id = $message->send(self::$target_id);

View File

@ -4,11 +4,11 @@ declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use hood\vk\core;
use hood\vk\robots\robot;
use hood\vk\tests\settings;
use mirzaev\vk\core;
use mirzaev\vk\robots\robot;
use mirzaev\vk\tests\settings;
use hood\accounts\vk as account;
use mirzaev\accounts\vk as account;
/**
* @testdox Фото

View File

@ -4,11 +4,11 @@ declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use hood\vk\core;
use hood\vk\robots\robot;
use hood\vk\tests\settings;
use mirzaev\vk\core;
use mirzaev\vk\robots\robot;
use mirzaev\vk\tests\settings;
use hood\accounts\vk as account;
use mirzaev\accounts\vk as account;
/**
* @testdox Робот-группа

View File

@ -4,11 +4,11 @@ declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use hood\vk\core;
use hood\vk\robots\robot;
use hood\vk\tests\settings;
use mirzaev\vk\core;
use mirzaev\vk\robots\robot;
use mirzaev\vk\tests\settings;
use hood\accounts\vk as account;
use mirzaev\accounts\vk as account;
/**
* @testdox Робот-пользователь

View File

@ -0,0 +1,88 @@
<?php
declare(strict_types=1);
namespace mirzaev\vk\tests;
/**
* Настройки окружения для тестирования
*
* @todo Разгруппировать свойства и привести в понимаемый для тех кто только начал знакомиться с проектом вид
*/
trait settings
{
/**
* @var string $path_account Путь до директории с данными аккаунтов
*/
protected static string $path_accounts = __DIR__ . '/accounts';
/**
* @var string $path_images Путь до директории с изображениями
*/
protected static string $path_images = __DIR__ . '/storage/images';
/**
* Идентификатор аккаунта
*/
protected static int $id = 0;
/**
* Идентификатор вспомогательного аккаунта
*/
protected static int $target_id = 0;
/**
* Домен вспомогательного аккаунта
*/
protected static string $target_domain = '';
/**
* Входной аккаунта (если не указан ключ)
*/
protected static string $login = '';
/**
* Пароль аккаунта (если не указан ключ)
*/
protected static string $password = '';
/**
* Ключ аккаунта
*/
protected static string $key = '';
/**
* Идентификатор группы
*/
protected static int $group_id = 0;
/**
* Ключ группы
*/
protected static string $group_key = '';
/**
* Версия API
*/
protected static float $version = 5.124;
/**
* Идентификатор проекта
*/
protected static int $project_id = 0;
/**
* Ключ проекта
*/
protected static string $project_key = '';
/**
* Сервисный ключ проекта
*/
protected static string $project_service_key = '';
/**
* SSL-протокол
*/
protected static bool $ssl = false;
}

20
test.php Normal file
View File

@ -0,0 +1,20 @@
<?php
use hood\vk\core;
use hood\vk\api\settings;
require './vendor/autoload.php';
$core = core::init();
$robot = $core->group(12312)->key(1);
$robot = $core->group(12312)->key(1);
$robot = $core->group()->key(1);
$robot = $core->group()->key(1);
$settings = new settings($robot);
$settings['data']['test']['a'] = 2;
$settings['data'] = 2;
var_export($core->read());