├── .gitignore ├── tests ├── Unit │ ├── Filesystem │ │ ├── testfile_new.txt │ │ └── ManagerTest.php │ ├── TestCase.php │ ├── AppTest.php │ ├── Providers │ │ └── AbstractEventServiceProviderTest.php │ ├── Traits │ │ ├── ValidatableTest.php │ │ └── LoadsModulesTest.php │ ├── Config │ │ └── ConfigManagerTest.php │ └── Base │ │ └── DictionaryTest.php └── helpers.php ├── bootstrap.php ├── src ├── Contracts │ ├── ConfigurationContract.php │ └── ServiceProviderContract.php ├── Providers │ ├── FileServiceProvider.php │ ├── AbstractEventServiceProvider.php │ └── BitrixMainProvider.php ├── Facades │ ├── CMain.php │ ├── FileManager.php │ ├── Application.php │ └── CUser.php ├── Dictionaries │ └── DefaultValidationMessages.php ├── Base │ ├── AbstractFacade.php │ ├── AbstractServiceProvider.php │ └── AbstractDictionary.php ├── Traits │ ├── LoadsModules.php │ └── Validatable.php ├── Config │ └── Manager.php └── Filesystem │ └── Manager.php ├── container.php ├── Makefile ├── phpunit.xml ├── composer.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .phpunit.result.cache 3 | 4 | -------------------------------------------------------------------------------- /tests/Unit/Filesystem/testfile_new.txt: -------------------------------------------------------------------------------- 1 | test content -------------------------------------------------------------------------------- /bootstrap.php: -------------------------------------------------------------------------------- 1 | assertTrue(class_exists(AbstractServiceProvider::class)); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Contracts/ServiceProviderContract.php: -------------------------------------------------------------------------------- 1 | make(\PrettyBx\Support\Contracts\ConfigurationContract::class)->get($key); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Facades/FileManager.php: -------------------------------------------------------------------------------- 1 | 'Не указано поле :attribute', 15 | 'numeric' => 'Поле :attribute должно содержать числовое значение', 16 | ]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all 2 | 3 | SHELL=/bin/bash -e 4 | 5 | .DEFAULT_GOAL := help 6 | 7 | help: ## This help 8 | @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) 9 | 10 | phpunit: ## Run phpUnit tests 11 | @docker run --rm --interactive --tty --volume $$PWD:/app --user $$(id -u):$$(id -g) composer test 12 | 13 | dump-autoload: ## Dumps composer autoload files 14 | @docker run --rm --interactive --tty --volume $PWD:/app --user $(id -u):$(id -g) composer dump-autoload 15 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests 14 | 15 | 16 | -------------------------------------------------------------------------------- /tests/helpers.php: -------------------------------------------------------------------------------- 1 | make($class); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Facades/Application.php: -------------------------------------------------------------------------------- 1 | =5.8", 15 | "illuminate/support": ">=5.8", 16 | "illuminate/container": ">=5.8", 17 | "mockery/mockery": ">=1.3", 18 | "phpunit/phpunit": ">=7" 19 | }, 20 | "autoload": { 21 | "files": [ 22 | "container.php" 23 | ], 24 | "psr-4": { 25 | "PrettyBx\\Support\\": "src/" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "PrettyBx\\Support\\Tests\\": "tests/Unit" 31 | }, 32 | "files": [ 33 | "tests/helpers.php" 34 | ] 35 | }, 36 | "scripts": { 37 | "test": "phpunit" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/Unit/Filesystem/ManagerTest.php: -------------------------------------------------------------------------------- 1 | getTempDir() . DIRECTORY_SEPARATOR . 'testfile.txt'; 17 | 18 | $this->assertFalse($manager->exists($filename)); 19 | 20 | $manager->touch($filename); 21 | 22 | $this->assertTrue($manager->exists($filename)); 23 | 24 | $manager->putContents($filename, $data); 25 | 26 | $this->assertEquals($data, $manager->getContents($filename)); 27 | 28 | $newname = __DIR__ . DIRECTORY_SEPARATOR . 'testfile_new.txt'; 29 | 30 | $manager->rename($filename, $newname); 31 | 32 | $this->assertFalse($manager->exists($filename)); 33 | $this->assertTrue($manager->exists($newname)); 34 | 35 | $this->assertEquals($data, $manager->getContents($newname)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tests/Unit/Providers/AbstractEventServiceProviderTest.php: -------------------------------------------------------------------------------- 1 | 'tasks', 16 | 'event' => 'OnTaskUpdate', 17 | 'handler' => "event_handler_function", 18 | 'sort' => 100, 19 | ] 20 | ]; 21 | }; 22 | 23 | $eventManager = $this->getMockBuilder('\Bitrix\Main\EventManager') 24 | ->setMethods(['addEventHandler']) 25 | ->getMock(); 26 | 27 | $eventManager->expects($this->once()) 28 | ->method('addEventHandler'); 29 | 30 | container()->bind('\Bitrix\Main\EventManager', function () use ($eventManager) { 31 | return $eventManager; 32 | }); 33 | 34 | $provider->register(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Base/AbstractServiceProvider.php: -------------------------------------------------------------------------------- 1 | container = container(); 24 | 25 | $this->bindSinletons(); 26 | } 27 | 28 | /** 29 | * @inheritDoc 30 | */ 31 | public function register(): void 32 | { 33 | 34 | } 35 | 36 | /** 37 | * bindSinletons. 38 | * 39 | * @access protected 40 | * @return void 41 | */ 42 | protected function bindSinletons(): void 43 | { 44 | foreach ($this->singletons as $id => $implementation) { 45 | if (is_string($id)) { 46 | $this->container->singleton($id, $implementation); 47 | } else { 48 | $this->container->singleton($implementation); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Providers/AbstractEventServiceProvider.php: -------------------------------------------------------------------------------- 1 | events)) { 24 | $this->bindEvents(); 25 | } 26 | } 27 | 28 | /** 29 | * Binds handlers to events 30 | * 31 | * @access protected 32 | * @return void 33 | */ 34 | protected function bindEvents(): void 35 | { 36 | $manager = container()->make('\Bitrix\Main\EventManager'); 37 | 38 | foreach ($this->events as $event) { 39 | $manager->addEventHandler( 40 | $event['module'], 41 | $event['event'], 42 | $event['handler'], 43 | false, 44 | $event['sort'] 45 | ); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Traits/LoadsModules.php: -------------------------------------------------------------------------------- 1 | loadModule($modules); 20 | 21 | return; 22 | } 23 | 24 | if (is_array($modules)) { 25 | foreach ($modules as $moduleId) { 26 | $this->loadModule($moduleId); 27 | } 28 | 29 | return; 30 | } 31 | 32 | if (property_exists($this, 'modules') && is_array($this->modules)) { 33 | foreach ($this->modules as $module) { 34 | $this->loadModule($module); 35 | } 36 | } 37 | } 38 | 39 | /** 40 | * loadModule. 41 | * 42 | * @access protected 43 | * @param string $moduleId 44 | * @return void 45 | */ 46 | protected function loadModule(string $moduleId): void 47 | { 48 | if (!container()->make('\Bitrix\Main\Loader')->includeModule($moduleId)) { 49 | throw new \RuntimeException('Module ' . $moduleId . ' could not be loaded'); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tests/Unit/Traits/ValidatableTest.php: -------------------------------------------------------------------------------- 1 | validate(['id' => 1], ['id' => 'required|integer']); 20 | 21 | $this->assertTrue(true); 22 | } 23 | 24 | /** 25 | * @test 26 | */ 27 | public function validator_uses_internal_rules_if_provided() 28 | { 29 | $tester = new class() { 30 | use Validatable; 31 | 32 | protected $rules = ['id' => 'required|integer']; 33 | }; 34 | 35 | $tester->validate(['id' => 1]); 36 | 37 | $this->assertTrue(true); 38 | } 39 | 40 | /** 41 | * @test 42 | */ 43 | public function validator_uses_external_rules_if_internal_also_provided() 44 | { 45 | $tester = new class() { 46 | use Validatable; 47 | 48 | protected $rules = ['this_rule_must_be_overwritten' => 'required|bool']; 49 | }; 50 | 51 | $tester->validate(['id' => 2], ['id' => 'required|integer']); 52 | 53 | $this->assertTrue(true); 54 | } 55 | } -------------------------------------------------------------------------------- /src/Base/AbstractDictionary.php: -------------------------------------------------------------------------------- 1 | getBxConfig()->get($key); 21 | 22 | if (! empty($value)) { 23 | return $value; 24 | } 25 | 26 | $keyPath = explode('.', $key); 27 | 28 | $root = $this->getBxConfig()->get(array_shift($keyPath)); 29 | 30 | if (empty($root) || ! is_array($root)) { 31 | return ''; 32 | } 33 | 34 | $current = $root; 35 | foreach ($keyPath as $key => $val) { 36 | if (empty($current[$val])) { 37 | return ''; 38 | } 39 | 40 | $current = $current[$val]; 41 | } 42 | 43 | return $current; 44 | } 45 | 46 | /** 47 | * getBxConfig. 48 | * 49 | * @access protected 50 | * @return Configuration 51 | */ 52 | protected function getBxConfig() 53 | { 54 | if (empty($this->bxConfig)) { 55 | $this->bxConfig = Configuration::getInstance(); 56 | } 57 | 58 | return $this->bxConfig; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Facades/CUser.php: -------------------------------------------------------------------------------- 1 | manager = \Mockery::mock(Manager::class . '[getBxConfig]') 15 | ->makePartial() 16 | ->shouldAllowMockingProtectedMethods(); 17 | 18 | $this->manager->shouldReceive('getBxConfig')->andReturn($this->getBxConfig()); 19 | } 20 | 21 | /** 22 | * @test 23 | */ 24 | public function manager_returns_correct_array() 25 | { 26 | $expected = [ 27 | 'subkeyA' => 'valueA', 28 | 'subkeyB' => 'valueB', 29 | ]; 30 | 31 | $this->assertEquals($expected, $this->manager->get('key')); 32 | } 33 | 34 | /** 35 | * @test 36 | */ 37 | public function manager_returns_correct_array_value() 38 | { 39 | $this->assertEquals('valueA', $this->manager->get('key.subkeyA')); 40 | } 41 | 42 | /** 43 | * @test 44 | */ 45 | public function manager_returns_null_if_no_value_found() 46 | { 47 | $this->assertEquals('', $this->manager->get('key.non-existent-subkey')); 48 | } 49 | 50 | protected function getBxConfig() 51 | { 52 | return new class() { 53 | public function get($key) 54 | { 55 | $config = [ 56 | 'key' => [ 57 | 'subkeyA' => 'valueA', 58 | 'subkeyB' => 'valueB', 59 | ], 60 | ]; 61 | 62 | return $config[$key] ?? null; 63 | } 64 | }; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Providers/BitrixMainProvider.php: -------------------------------------------------------------------------------- 1 | ConfigManager::class, 19 | ]; 20 | 21 | /** 22 | * @inheritDoc 23 | */ 24 | public function register(): void 25 | { 26 | parent::register(); 27 | 28 | $this->initGlobalObjects(); 29 | } 30 | 31 | /** 32 | * Initializes global variables 33 | * 34 | * @access protected 35 | * @return void 36 | */ 37 | protected function initGlobalObjects(): void 38 | { 39 | container()->singleton('CMain', function () { 40 | if (empty($GLOBALS['APPLICATION'])) { 41 | throw new \RuntimeException('Bitrix is not initialized'); 42 | } 43 | 44 | return $GLOBALS['APPLICATION']; 45 | }); 46 | 47 | container()->singleton('CUser', function () { 48 | if (empty($GLOBALS['USER'])) { 49 | throw new \RuntimeException('Bitrix is not initialized'); 50 | } 51 | 52 | return $GLOBALS['USER']; 53 | }); 54 | 55 | container()->singleton('\Bitrix\Main\Application', function () { 56 | return \Bitrix\Main\Application::getInstance(); 57 | }); 58 | 59 | container()->singleton('\Bitrix\Main\EventManager', function () { 60 | return \Bitrix\Main\EventManager::getInstance(); 61 | }); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /tests/Unit/Traits/LoadsModulesTest.php: -------------------------------------------------------------------------------- 1 | getLoader($expectedModule, true); 18 | 19 | $class = $this->getLoadingClass(); 20 | 21 | $class->modules = [$expectedModule]; 22 | 23 | $class->load(); 24 | } 25 | 26 | /** 27 | * @test 28 | */ 29 | public function excepetion_is_thrown_of_module_cant_be_loaded() 30 | { 31 | $expectedModule = 'iblock'; 32 | 33 | $loader = $this->getLoader($expectedModule, false); 34 | 35 | $class = $this->getLoadingClass(); 36 | 37 | $class->modules = [$expectedModule]; 38 | 39 | $this->expectException(\RuntimeException::class); 40 | 41 | $class->load(); 42 | } 43 | 44 | protected function getLoader(string $expectedModule, bool $expectedReturn) 45 | { 46 | $loader = $this->getMockBuilder('\Bitrix\Main\Loader') 47 | ->setMethods(['includeModule']) 48 | ->getMock(); 49 | 50 | $loader->expects($this->once()) 51 | ->method('includeModule') 52 | ->with($this->equalTo($expectedModule)) 53 | ->willReturn($expectedReturn); 54 | 55 | container()->bind('\Bitrix\Main\Loader', function () use ($loader) { 56 | return $loader; 57 | }); 58 | } 59 | 60 | protected function getLoadingClass() 61 | { 62 | return new class() { 63 | use LoadsModules; 64 | 65 | public $modules; 66 | 67 | public function load() 68 | { 69 | $this->loadModules(); 70 | } 71 | }; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /tests/Unit/Base/DictionaryTest.php: -------------------------------------------------------------------------------- 1 | getDictionary(); 19 | 20 | $this->assertEquals($dictionary->getItem('K1'), 'Value 1'); 21 | $this->assertEquals($dictionary->getItem('K2'), 'Value 2'); 22 | } 23 | 24 | protected function getDictionary(): AbstractDictionary 25 | { 26 | return new class () extends AbstractDictionary { 27 | 28 | public static function getItems(): array 29 | { 30 | return [ 31 | 'K1' => 'Value 1', 32 | 'K2' => 'Value 2', 33 | ]; 34 | } 35 | }; 36 | } 37 | 38 | /** 39 | * Проверяем, что словарь выбрасывает исключение при запросе не существующего значения 40 | * 41 | * @return void 42 | */ 43 | public function testDictionaryThrowsException() 44 | { 45 | $dictionary = $this->getDictionary(); 46 | 47 | $this->expectException(InvalidArgumentException::class); 48 | 49 | $dictionary->getItem('non-existent'); 50 | } 51 | 52 | /** 53 | * Проверяем, что словарь отдает корректные ключи 54 | * 55 | * @return void 56 | */ 57 | public function testDictionaryReturnsCodes() 58 | { 59 | $dictionary = $this->getDictionary(); 60 | 61 | $this->assertEquals($dictionary->getCodes(), ['K1', 'K2']); 62 | } 63 | 64 | /** 65 | * Проверяем, что словарь отдает корректные значения 66 | * 67 | * @return void 68 | */ 69 | public function testDictionaryReturnsValues() 70 | { 71 | $dictionary = $this->getDictionary(); 72 | 73 | $this->assertEquals($dictionary->getValues(), ['Value 1', 'Value 2']); 74 | } 75 | } -------------------------------------------------------------------------------- /src/Filesystem/Manager.php: -------------------------------------------------------------------------------- 1 | rules : []); 27 | 28 | $validator = new Validator( 29 | new Translator(new ArrayLoader(), $this->getValidationLocale()), 30 | $data, 31 | $rules, 32 | $this->getValidationMessages($messages) 33 | ); 34 | 35 | if ($validator->fails()) { 36 | $message = $toJson ? $validator->errors()->toJson(256) : implode(', ', $validator->errors()->all()); 37 | throw new InvalidArgumentException($message); 38 | } 39 | } 40 | 41 | /** 42 | * Валидирует отдельный атрибут 43 | * 44 | * @access public 45 | * @param string $attribute 46 | * @param mixed $value 47 | * @param array|null $rules Default: null 48 | * @return void 49 | */ 50 | public function validateAttribute(string $attribute, $value, array $rules = null): void 51 | { 52 | if (empty($rules)) { 53 | if (property_exists($this, 'rules') && !empty($this->rules[$attribute])) { 54 | $rules = [$attribute => $this->rules[$attribute]]; 55 | } else { 56 | $rules = [$attribute => []]; 57 | } 58 | } 59 | 60 | $validator = new Validator( 61 | new Translator(new ArrayLoader(), $this->getValidationLocale()), 62 | [$attribute => $value], 63 | $rules, 64 | $this->getValidationMessages() 65 | ); 66 | 67 | if ($validator->fails()) { 68 | throw new InvalidArgumentException(implode(', ', $validator->errors()->all())); 69 | } 70 | } 71 | 72 | /** 73 | * getValidationLocale. 74 | * 75 | * @access protected 76 | * @return string 77 | */ 78 | protected function getValidationLocale(): string 79 | { 80 | return property_exists($this, 'locale') ? $this->locale : 'en_US'; 81 | } 82 | 83 | /** 84 | * getValidationMessages. 85 | * 86 | * @access protected 87 | * @param array|null $messages 88 | * @return array 89 | */ 90 | protected function getValidationMessages(array $messages = null): array 91 | { 92 | return $messages ?? (property_exists($this, 'messages') ? $this->messages : DefaultMessages::getItems()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pretty Bitrix (Support) 2 | 3 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/artem-prozorov/prettybxsupport/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/artem-prozorov/prettybxsupport/?branch=master) 4 | [![Build Status](https://scrutinizer-ci.com/g/artem-prozorov/prettybxsupport/badges/build.png?b=master)](https://scrutinizer-ci.com/g/artem-prozorov/prettybxsupport/build-status/master) 5 | [![Code Intelligence Status](https://scrutinizer-ci.com/g/artem-prozorov/prettybxsupport/badges/code-intelligence.svg?b=master)](https://scrutinizer-ci.com/code-intelligence) 6 | 7 | Библиотека для упрощения работы с Битрикс 8 | 9 | ## Установка 10 | 11 | ``` 12 | composer require prettybx/support 13 | ``` 14 | 15 | ## Начало работы 16 | 17 | 1. Инициализируйте сервис провайдер в `local/php_interface/init.php`: 18 | ``` 19 | (new \PrettyBx\Support\Providers\BitrixMainProvider())->register(); 20 | ``` 21 | 22 | ## DI container 23 | Для реализации Dependency Injection предлагается использовать Illuminate/Container (DI container из фреймворка Laravel). 24 | Для того, чтобы получить экземпляр контейнера, можно воспользоваться хэлпером `container()` 25 | Пример: 26 | ``` 27 | $bar = container()->make(\Foo\Bar::class); // получим экземпляр класса \Foo\Bar 28 | ``` 29 | 30 | ## Фасады 31 | Для удобства тестирования библиотека подключает к проекту и адаптирует к работе ларавелевские фасады. Чтобы сдлать свой фасад, нужно создать класс, унаследовать его от `PrettyBx\Support\Base\AbstractFacade` и реализовать в нем метод `getFacadeAccessor`, который должен вернуть название класса, спрятанного за фасадом. 32 | Пример: 33 | ``` 34 | class Foo 35 | { 36 | public function bar() 37 | { 38 | return 'Hi!'; 39 | } 40 | } 41 | 42 | class FooFacade extends \PrettyBx\Support\Base\AbstractFacade 43 | { 44 | protected static function getFacadeAccessor() 45 | { 46 | return Foo::class; 47 | } 48 | } 49 | 50 | class Service 51 | { 52 | public function doAction() 53 | { 54 | echo FooFacade::bar(); // Hi! 55 | } 56 | } 57 | ``` 58 | В тестах можно использовать так: 59 | ``` 60 | FooFacade::shouldReceive('bar')->andReturn('Hi!'); 61 | ``` 62 | 63 | ## Глобальные переменные Bitrix 64 | Так как статические методы и глобальные переменные очень плохо поддаются тестированию, для удобства работы с ними предлагается использовать фасады, результаты работы которых можно легко подменять тестовыми двойниками. 65 | 66 | ### $GLOBALS['APPLICATION'] 67 | Получить экземпляр класса \CMain, размещенные в `$GLOBALS['APPLICATION']`, можно с помощью фасада `PrettyBx\Support\Facades\CMain` 68 | Пример: 69 | ``` 70 | // Вместо этого 71 | global $APPLICATION; 72 | 73 | $contants = $APPLICATION->GetFileContent("/foo/bar.baz"); 74 | 75 | // Делаем так: 76 | $contants = \PrettyBx\Support\Facades\CMain::GetFileContent("/foo/bar.baz"); 77 | ``` 78 | 79 | ### $GLOBALS['USER'] 80 | Получить экземпляр класса \CUser можно с помощью фасада `PrettyBx\Support\Facades\CUser`. Пример получения текущего идентификатора пользователя: 81 | ``` 82 | $userId = \PrettyBx\Support\Facades\CUser::getId(); 83 | ``` 84 | 85 | Пример авторизации: 86 | ``` 87 | \PrettyBx\Support\Facades\CUser::login($login, $password); 88 | ``` 89 | 90 | ### \Bitrix\Main\Application 91 | Данный класс является основополагающим классов в D7, но в нем пристутствуют статические методы. Кроме того, он является синглтоном на уровне кода, то есть получить его экземпляр можно только с помощью метода getInstance. Это очень сильно затрудняет тестирование. Чтобы сделать тестирование этого класса возможным, предлагается использовать его фасад `PrettyBx\Support\Facades\Application`. 92 | 93 | ## Удобная загрузка модулей Bitrix 94 | В разрабатываемых классах очень часто нужно загружать модули Bitrix. Библиотека предоставляет разработчику удобный инструмент для загрузки модулей. Предлагается использовать трайт `PrettyBx\Support\Traits\LoadsModules`. 95 | Пример: 96 | ``` 97 | use PrettyBx\Support\Traits\LoadsModules; 98 | 99 | class SomeService 100 | { 101 | use LoadsModules; 102 | 103 | protected $modules = ['iblock', 'catalog']; 104 | 105 | public function __construct() 106 | { 107 | $this->loadModules(); // Загрузит те модули, которые указаны в $this->modules 108 | } 109 | 110 | public function loadOnDemand() 111 | { 112 | $this->loadModule('sale'); // Загрузит модуль, который был передан 113 | } 114 | } 115 | ``` 116 | 117 | В случае, если указанный модуль не может быть загружен, будет выброшено исключение `\RuntimeException` 118 | 119 | ## Работа с конфигурацией 120 | Библиотека предоставляет удобный инструмент для работы с конфигурацией Bitrix, размещенной в файле `bitrix/.settings.php`. Для того, чтобы получить значение элемента конфигурации, можно воспользоваться вспомогательной функцией `config`. 121 | ``` 122 | var_dump(config("connections")); 123 | ``` 124 | 125 | Значение многомерного массива можно получить, разделив ключи массива точками, например: 126 | ``` 127 | var_dump(config("connections.default.host")); // $config['connections]['default']['host'] 128 | ``` 129 | 130 | ## Валидация данных 131 | Для валидации данных используется библиотека Illuminate/Validation 132 | Для того, чтобы использовать ее, предлагается к нужному классу подключить трайт `PrettyBx\Support\Traits\Validatable` 133 | Пример 134 | ``` 135 | use PrettyBx\Support\Traits\Validatable; 136 | 137 | class Service 138 | { 139 | use Validatable; 140 | 141 | public function getValidatedRequestData(): array 142 | { 143 | $rules = [ 144 | 'ID' => 'required|numeric', 145 | 'TYPE' => 'required|string', 146 | ]; 147 | 148 | $this->validate($_POST, $rules); 149 | } 150 | } 151 | ``` 152 | 153 | В случае, если валидация данных провалится, будет выброшено исключение `\InvalidArgumentException` 154 | Список всех доступных правил валидации можно смотреть здесь https://laravel.com/docs/5.8/validation 155 | 156 | ## Работа с событиями 157 | Всю работу с событиями предлагается вынести в один класс - EventServiceProvider. Для того, чтобы зарегистрировать свои обработчики событий, создайте класс, наследующийся от `PrettyBx\Support\Providers\AbstractEventServiceProvider`. Укажите события, которые нужно обработать, в массиве в защищенном свойстве `events`. 158 | Пример: 159 | ``` 160 | use PrettyBx\Support\Providers\AbstractEventServiceProvider; 161 | 162 | class EventServiceProvider extends AbstractEventServiceProvider 163 | { 164 | protected array $events = [ 165 | [ 166 | 'module' => 'iblock', 167 | 'event' => 'OnAfterIBlockElementAdd', 168 | 'handler' => [\App\EventListeners\IblockEventListener::class, 'afterAdd'], 169 | 'sort' => 100, 170 | ], 171 | [ 172 | 'module' => 'iblock', 173 | 'event' => 'OnAfterIBlockElementUpdate', 174 | 'handler' => [\App\EventListeners\IblockEventListener::class, 'afterUpdate'], 175 | 'sort' => 100, 176 | ], 177 | [ 178 | 'module' => 'iblock', 179 | 'event' => 'OnBeforeIBlockElementDelete', 180 | 'handler' => 'function_name_here', 181 | 'sort' => 100, 182 | ], 183 | ]; 184 | } 185 | ``` 186 | После этого зарегистрируйте этот класс в `php_interface/init.php`: 187 | ``` 188 | (new EventServiceProvider())->register(); 189 | ``` 190 | При регистрации EventServiceProvider подпишет указанные обработчики на указанные события. 191 | 192 | ## Работа с файловой системой 193 | Для удобства работы с файлами есть класс `PrettyBx\Support\Filesystem\Manager`, который представляет из себя набор команд для выполнения файловых операций. Рекомендуется зарегистрировать этот класс как синглтон с помощью сервис провайдера: 194 | ``` 195 | (new \PrettyBx\Support\Providers\FileServiceProvider())->register(); 196 | ``` 197 | 198 | Теперь файловые операции, такие как переименование, проверка на существование, получение содержимого, удаление и тд, можно осуществлять следующим образом: 199 | ``` 200 | use PrettyBx\Support\Filesystem\Manager; 201 | 202 | $manager = container()->make(Manager::class); 203 | 204 | $file = '/foo/bar'; 205 | 206 | $contents = $manager->getContents($file); 207 | ``` 208 | или через фасад: 209 | ``` 210 | use PrettyBx\Support\Facades\FileManager; 211 | 212 | $file = '/foo/bar'; 213 | $contents = FileManager::getContants($file); 214 | ``` 215 | 216 | Расширение функционала для работы с файлами 217 | Класс `PrettyBx\Support\Filesystem\Manager` реализует трайт `Illuminate\Support\Traits\Macroable`, что позволяет на лету добавлять в него свои методы. Рекомендуется делать это в сервис провайдерах. Пример добавления метода append: 218 | 1. В сервис провайдере добавляем такую команду: 219 | ``` 220 | Manager::macro('append', function ($filename, $data) { 221 | $resource = fopen($filename, 'a'); 222 | 223 | fwrite($resource, (string) $data); 224 | 225 | fclose($resource); 226 | }); 227 | ``` 228 | 2. Пользуемся 229 | ``` 230 | \PrettyBx\Support\Facades\FileManager::append($this->getFullPath(), $data); 231 | ``` 232 | 233 | ## Другие библиотеки в рамках проекта "Pretty Bitrix" 234 | - Удобные фикстуры для юнит тестов: https://github.com/artem-prozorov/prettybxfixtures 235 | --------------------------------------------------------------------------------