Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
120 / 120
100.00% covered (success)
100.00%
1 / 1
CRAP
100.00% covered (success)
100.00%
1 / 1
Configuration
100.00% covered (success)
100.00%
120 / 120
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
1 / 1
 addCmsOptions
n/a
0 / 0
n/a
0 / 0
0
 addApiOptions
n/a
0 / 0
n/a
0 / 0
0
 getConfigTreeBuilder
100.00% covered (success)
100.00%
120 / 120
100.00% covered (success)
100.00%
1 / 1
6
1<?php
2namespace Apie\Common\Config;
3
4use Apie\Common\ValueObjects\EntityNamespace;
5use Apie\DoctrineEntityDatalayer\IndexStrategy\DirectIndexStrategy;
6use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
7use Symfony\Component\Config\Definition\Builder\TreeBuilder;
8use Symfony\Component\Config\Definition\ConfigurationInterface;
9
10/**
11 * Configuration
12 */
13abstract class Configuration implements ConfigurationInterface
14{
15    private const ENABLE_CONFIGS = [
16        'enable_basic_auth' => 'Apie\Common\BasicAuth\AddBasicAuthContextBuilder',
17        'enable_ai_instructor' => 'Apie\AiInstructor\AiInstructor',
18        'enable_common_plugin' => 'Apie\ApieCommonPlugin\ApieCommonPlugin',
19        'enable_cms' => 'Apie\Cms\RouteDefinitions\CmsRouteDefinitionProvider',
20        'enable_cms_dropdown' => 'Apie\CmsApiDropdownOption\RouteDefinitions\DropdownOptionsForExistingObjectRouteDefinition',
21        'enable_doctrine_entity_converter' => 'Apie\DoctrineEntityConverter\OrmBuilder',
22        'enable_doctrine_entity_datalayer' => 'Apie\DoctrineEntityDatalayer\DoctrineEntityDatalayer',
23        'enable_export' => 'Apie\Export\EntityExport',
24        'enable_faker' => 'Apie\Faker\ApieObjectFaker',
25        'enable_ftp' => 'Apie\FtpServer\FtpServerCommand',
26        'enable_graphql' => 'Apie\Graphql\Factories\GraphqlSchemaFactory',
27        'enable_maker' => 'Apie\Maker\Utils',
28        'enable_mcp_server' => 'Apie\McpServer\RunMcpServerCommand',
29        'enable_rest_api' => 'Apie\RestApi\OpenApi\OpenApiGenerator',
30        'enable_console' => 'Apie\Console\ConsoleCommandFactory',
31        'enable_twig_template_layout_renderer' => 'Apie\TwigTemplateLayoutRenderer\TwigRenderer',
32        'enable_typescript_client_builder' => 'Apie\TypescriptClientBuilder\RouteDefinitions\CodeRouteDefinitionProvider',
33        'enable_webdav' => 'Apie\Webdav\Controller\WebdavController',
34    ];
35
36    abstract protected function addCmsOptions(ArrayNodeDefinition $arrayNode): void;
37
38    abstract protected function addApiOptions(ArrayNodeDefinition $arrayNode): void;
39
40    public function getConfigTreeBuilder(): TreeBuilder
41    {
42        $treeBuilder = new TreeBuilder('apie');
43
44        $children = $treeBuilder->getRootNode()->children();
45        $children->booleanNode('enable_core')->defaultValue(true)->end();
46        $children->scalarNode('encryption_key')->end();
47        $cmsConfig = $children->arrayNode('cms');
48        $cmsConfig->children()
49          ->scalarNode('base_url')->defaultValue('/cms')->end()
50          ->arrayNode('asset_folders')->scalarPrototype()->end()
51        ->end();
52        $this->addCmsOptions($cmsConfig);
53        $apiConfig = $children->arrayNode('rest_api');
54        $apiConfig->children()
55          ->scalarNode('base_url')->defaultValue('/api')->end()
56        ->end();
57        $this->addApiOptions($apiConfig);
58
59        $ftpConfig = $children->arrayNode('ftp_server');
60        $ftpConfig->children()
61          ->scalarNode('public_ip')->defaultValue('127.0.0.1')->end()
62          ->scalarNode('passive_min_port')->defaultValue('49152')->end()
63          ->scalarNode('passive_max_port')->defaultValue('65534')->end()
64        ->end();
65
66        $ftpConfig = $children->arrayNode('graphql');
67        $ftpConfig->children()
68          ->scalarNode('base_url')->defaultValue('graphql')->end()
69        ->end();
70
71        $aiConfig = $children->arrayNode('ai')
72          ->addDefaultsIfNotSet();
73        $aiConfig->children()
74            ->scalarNode('base_url')->defaultValue('https://api.openai.com/v1')->end()
75            ->scalarNode('api_key')->defaultValue('no-value')->end()
76        ->end();
77        $children->arrayNode('datalayers')
78                ->children()
79                    ->scalarNode('default_datalayer')->isRequired()->end()
80                    ->arrayNode('context_mapping')
81                        ->useAttributeAsKey('name')
82                        ->arrayPrototype()
83                            ->isRequired()
84                            ->children()
85                                ->scalarNode('default_datalayer')->isRequired()->end()
86                                ->arrayNode('entity_mapping')
87                                    ->useAttributeAsKey('class')
88                                    ->scalarPrototype()
89                                    ->end()
90                                ->end()
91                            ->end()
92                        ->end()
93                    ->end()
94                ->end()
95            ->end()
96            ->arrayNode('doctrine')
97                ->children()
98                    ->arrayNode('indexing')
99                        ->children()
100                            ->enumNode('type')->values(['direct', 'late', 'background', 'custom'])->defaultValue('direct')->end()
101                            ->scalarNode('service')->defaultValue(DirectIndexStrategy::class)->end()
102                        ->end()
103                    ->end()
104                    ->scalarNode('build_once')->defaultValue(false)->end()
105                    ->scalarNode('run_migrations')->defaultValue(true)->end()
106                    ->arrayNode('connection_params')
107                      ->defaultValue(['driver' => 'pdo_sqlite'])
108                      ->useAttributeAsKey('class')
109                      ->scalarPrototype()
110                      ->end()
111                    ->end()
112                ->end()
113            ->end()
114            ->arrayNode('storage')
115              ->arrayPrototype()
116                ->children()
117                  ->scalarNode('class')->isRequired()->end()
118                  ->arrayNode('options')->defaultValue([])
119                    ->scalarPrototype()
120                    ->end()
121                  ->end()
122                ->end()
123              ->end()
124            ->end()
125            ->arrayNode('maker')
126                ->children()
127                  ->scalarNode('target_path')->defaultValue(false)->end()
128                  ->scalarNode('target_namespace')->defaultValue('App\Apie')->end()
129                ->end()
130            ->end()
131            ->arrayNode('bounded_contexts')
132                ->useAttributeAsKey('name')
133                ->arrayPrototype()
134                ->beforeNormalization()
135                    ->always(
136                        function (array $v) {
137                            if (empty($v['policy_folder']) && !empty($v['entities_folder'])) {
138                                $v['policy_folder'] = rtrim($v['entities_folder'], '/\\') . '/../Policies';
139                            }
140
141                            if (empty($v['policy_namespace']) && !empty($v['entities_namespace'])) {
142                                $entityNamespace = EntityNamespace::fromNative($v['entities_namespace']);
143                                $v['policy_namespace'] = $entityNamespace->getParentNamespace()->getChildNamespace('Policies')->toNative();
144                            }
145
146                            return $v;
147                        }
148                    )->end()
149                    ->children()
150                        ->scalarNode('entities_folder')->isRequired()->end()
151                        ->scalarNode('entities_namespace')->isRequired()->end()
152                        ->scalarNode('actions_folder')->isRequired()->end()
153                        ->scalarNode('actions_namespace')->isRequired()->end()
154                        ->scalarNode('policy_folder')->defaultNull()->end()
155                        ->scalarNode('policy_namespace')->defaultNull()->end()
156                    ->end()
157                ->end()
158            ->end()
159            ->arrayNode('scan_bounded_contexts')
160                ->children()
161                    ->scalarNode('search_path')->end()
162                    ->scalarNode('search_namespace')->end()
163                ->end()
164            ->end();
165        $childNode = $treeBuilder->getRootNode()->children();
166        foreach (self::ENABLE_CONFIGS as $configKey => $classNameToExist) {
167            $childNode->booleanNode($configKey)->defaultValue(class_exists($classNameToExist));
168        }
169        $childNode->scalarNode('remote_mcp_path')->defaultValue(null)->end();
170        return $treeBuilder;
171    }
172}