apps/artisancommerce/custom-theme/src/CustomThemePackage.php line 14

Open in your IDE?
  1. <?php
  2. namespace UVDesk\CommunityPackages\ArtisanCommerce\CustomTheme;
  3. use Symfony\Component\Config\Definition\Builder\TreeBuilder;
  4. use Symfony\Component\Config\Definition\ConfigurationInterface;
  5. use Symfony\Component\DependencyInjection\ContainerBuilder;
  6. use Symfony\Component\HttpKernel\Bundle\Bundle;
  7. use Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\PackageInterface;
  8. use Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\ConfigurablePackageInterface;
  9. use UVDesk\CommunityPackages\ArtisanCommerce\CustomTheme\DependencyInjection\Compiler\TwigPathPass;
  10. use Psr\Log\LoggerInterface;
  11. class CustomThemePackage extends Bundle implements PackageInterface, ConfigurablePackageInterface
  12. {
  13. private $metadata;
  14. private $configurationFilepath;
  15. private $configurationParameters = [];
  16. private $logger;
  17. private $debugMode = true;
  18. public function __construct(LoggerInterface $logger = null)
  19. {
  20. $this->logger = $logger;
  21. if ($this->debugMode && $this->logger) {
  22. $this->logger->info('[CustomThemePackage] Package instantiated', [
  23. 'class' => self::class,
  24. 'timestamp' => date('Y-m-d H:i:s')
  25. ]);
  26. }
  27. }
  28. /**
  29. * Symfony Bundle lifecycle: Register compiler passes
  30. */
  31. public function build(ContainerBuilder $container): void
  32. {
  33. parent::build($container);
  34. // Register the Twig path compiler pass
  35. $container->addCompilerPass(new TwigPathPass());
  36. }
  37. /**
  38. * UVDesk installation hook - called during uvdesk:configure-extension
  39. * This is where we auto-register the bundle in config/bundles.php
  40. */
  41. public function install(): void
  42. {
  43. $this->registerBundle();
  44. $this->createConfigurationFile();
  45. }
  46. /**
  47. * Auto-register this bundle in config/bundles.php
  48. */
  49. private function registerBundle(): void
  50. {
  51. // Find project root by traversing up from package root
  52. $projectRoot = $this->findProjectRoot();
  53. if (!$projectRoot) {
  54. if ($this->logger) {
  55. $this->logger->error('[CustomThemePackage] Could not determine project root');
  56. }
  57. return;
  58. }
  59. $bundlesFile = $projectRoot . '/config/bundles.php';
  60. if (!file_exists($bundlesFile)) {
  61. if ($this->logger) {
  62. $this->logger->warning('[CustomThemePackage] bundles.php not found', [
  63. 'expected_path' => $bundlesFile
  64. ]);
  65. }
  66. return;
  67. }
  68. // Load current bundles
  69. $bundles = include $bundlesFile;
  70. $bundleClass = self::class;
  71. // Check if already registered
  72. if (isset($bundles[$bundleClass])) {
  73. if ($this->logger) {
  74. $this->logger->info('[CustomThemePackage] Bundle already registered');
  75. }
  76. return;
  77. }
  78. // Add this bundle to the list
  79. $bundles[$bundleClass] = ['all' => true];
  80. // Generate new bundles.php content
  81. $content = "<?php\n\nreturn [\n";
  82. foreach ($bundles as $class => $envs) {
  83. $envsStr = var_export($envs, true);
  84. $content .= " {$class}::class => {$envsStr},\n";
  85. }
  86. $content .= "];\n";
  87. // Write back to bundles.php
  88. if (file_put_contents($bundlesFile, $content) !== false) {
  89. if ($this->logger) {
  90. $this->logger->info('[CustomThemePackage] Successfully auto-registered bundle', [
  91. 'bundle_class' => $bundleClass,
  92. 'bundles_file' => $bundlesFile
  93. ]);
  94. }
  95. } else {
  96. if ($this->logger) {
  97. $this->logger->error('[CustomThemePackage] Failed to write bundles.php', [
  98. 'bundles_file' => $bundlesFile
  99. ]);
  100. }
  101. }
  102. }
  103. /**
  104. * Create the configuration file required by ConfigurablePackageInterface
  105. */
  106. //private function createConfigurationFile(): void
  107. //{
  108. // if (!empty($this->configurationFilepath)) {
  109. // $configDir = dirname($this->configurationFilepath);
  110. //
  111. // if (!file_exists($configDir)) {
  112. // mkdir($configDir, 0755, true);
  113. // }
  114. //
  115. // if (!file_exists($this->configurationFilepath)) {
  116. // // Create empty configuration file
  117. // $content = "# Custom Theme Package Configuration\ncustom_theme: []\n";
  118. // file_put_contents($this->configurationFilepath, $content);
  119. //
  120. // if ($this->logger) {
  121. // $this->logger->info('[CustomThemePackage] Created configuration file', [
  122. // 'config_file' => $this->configurationFilepath
  123. // ]);
  124. // }
  125. // }
  126. // }
  127. //}
  128. /**
  129. * Create the configuration file with full default values
  130. * Called during install() - ensures config is ready immediately after installation
  131. */
  132. private function createConfigurationFile(): void
  133. {
  134. if (!empty($this->configurationFilepath)) {
  135. $configDir = dirname($this->configurationFilepath);
  136. if (!file_exists($configDir)) {
  137. mkdir($configDir, 0755, true);
  138. }
  139. if (!file_exists($this->configurationFilepath)) {
  140. // Create configuration file with full defaults
  141. $content = <<<YAML
  142. # =============================================================================
  143. # Custom Theme Package Configuration
  144. # =============================================================================
  145. # This file is automatically generated during module installation.
  146. # You can edit these values to customize the module's behavior.
  147. # After making changes, run: php bin/console cache:clear
  148. # =============================================================================
  149. custom_theme:
  150. # Login Tracking Settings
  151. # Track user login sessions, monitor session duration, and view detailed history
  152. login_tracking:
  153. enabled: true # Enable/disable login tracking
  154. session_timeout: 3600 # Session timeout in seconds (default: 1 hour)
  155. max_display_sessions: 100 # Maximum sessions to display in dashboard
  156. track_ip: true # Track IP addresses for sessions
  157. # Theme Customization Settings
  158. # Customize the look and feel of your helpdesk
  159. theme:
  160. enabled: true # Enable custom theme
  161. color_scheme: default # Color scheme: default, dark, light
  162. custom_css: false # Enable custom CSS injection
  163. # Display Preferences
  164. # Configure date/time formats and timezone
  165. display:
  166. date_format: 'd.m.Y' # PHP date() format for dates
  167. time_format: 'H:i:s' # PHP date() format for times
  168. timezone: 'Europe/Vienna' # Default timezone (PHP timezone string)
  169. YAML;
  170. file_put_contents($this->configurationFilepath, $content);
  171. if ($this->logger) {
  172. $this->logger->info('[CustomThemePackage] Created configuration file with defaults', [
  173. 'config_file' => $this->configurationFilepath
  174. ]);
  175. }
  176. }
  177. }
  178. }
  179. /**
  180. * Find project root by traversing up from package location
  181. */
  182. private function findProjectRoot(): ?string
  183. {
  184. $current = __DIR__;
  185. // Traverse up looking for config/bundles.php
  186. for ($i = 0; $i < 10; $i++) {
  187. $current = dirname($current);
  188. if (file_exists($current . '/config/bundles.php')) {
  189. return $current;
  190. }
  191. }
  192. return null;
  193. }
  194. // ========================================
  195. // ConfigurablePackageInterface Methods
  196. // ========================================
  197. //public function getConfiguration(): ConfigurationInterface
  198. //{
  199. // // Return empty configuration schema (required by interface)
  200. // return new class implements ConfigurationInterface {
  201. // public function getConfigTreeBuilder()
  202. // {
  203. // $treeBuilder = new TreeBuilder('custom_theme');
  204. // $rootNode = $treeBuilder->getRootNode();
  205. //
  206. // // Empty configuration - no parameters needed
  207. // return $treeBuilder;
  208. // }
  209. // };
  210. //}
  211. public function getConfiguration(): ConfigurationInterface
  212. {
  213. return new class implements ConfigurationInterface {
  214. public function getConfigTreeBuilder()
  215. {
  216. $treeBuilder = new TreeBuilder('custom_theme');
  217. $rootNode = $treeBuilder->getRootNode();
  218. $rootNode
  219. ->children()
  220. // Login Tracking Settings
  221. ->arrayNode('login_tracking')
  222. ->addDefaultsIfNotSet()
  223. ->children()
  224. ->booleanNode('enabled')
  225. ->defaultTrue()
  226. ->info('Enable login tracking')
  227. ->end()
  228. ->integerNode('session_timeout')
  229. ->defaultValue(3600)
  230. ->min(300)
  231. ->max(86400)
  232. ->info('Session timeout in seconds')
  233. ->end()
  234. ->integerNode('max_display_sessions')
  235. ->defaultValue(100)
  236. ->min(10)
  237. ->max(1000)
  238. ->info('Maximum sessions to display in dashboard')
  239. ->end()
  240. ->booleanNode('track_ip')
  241. ->defaultTrue()
  242. ->info('Track IP addresses')
  243. ->end()
  244. ->end()
  245. ->end()
  246. // Theme Settings
  247. ->arrayNode('theme')
  248. ->addDefaultsIfNotSet()
  249. ->children()
  250. ->booleanNode('enabled')
  251. ->defaultTrue()
  252. ->info('Enable custom theme')
  253. ->end()
  254. ->scalarNode('color_scheme')
  255. ->defaultValue('default')
  256. ->info('Color scheme (default, dark, light)')
  257. ->end()
  258. ->scalarNode('icon_border_radius')
  259. ->defaultValue('50%')
  260. ->info('Dashboard icon border radius (e.g. 50% or 12px)')
  261. ->end()
  262. ->booleanNode('custom_css')
  263. ->defaultFalse()
  264. ->info('Enable custom CSS')
  265. ->end()
  266. ->end()
  267. ->end()
  268. // Display Preferences
  269. ->arrayNode('display')
  270. ->addDefaultsIfNotSet()
  271. ->children()
  272. ->scalarNode('date_format')
  273. ->defaultValue('d.m.Y')
  274. ->info('Date format (PHP date() format)')
  275. ->end()
  276. ->scalarNode('time_format')
  277. ->defaultValue('H:i:s')
  278. ->info('Time format (PHP date() format)')
  279. ->end()
  280. ->scalarNode('timezone')
  281. ->defaultValue('Europe/Vienna')
  282. ->info('Default timezone')
  283. ->end()
  284. ->end()
  285. ->end()
  286. ->end()
  287. ->end();
  288. return $treeBuilder;
  289. }
  290. };
  291. }
  292. public function setConfigurationFilepath(string $configurationFilepath): ConfigurablePackageInterface
  293. {
  294. if (empty($this->configurationFilepath)) {
  295. $this->configurationFilepath = $configurationFilepath;
  296. }
  297. return $this;
  298. }
  299. public function getConfigurationFilepath(): string
  300. {
  301. return $this->configurationFilepath ?? '';
  302. }
  303. public function setConfigurationParameters(array $configurationParameters): ConfigurablePackageInterface
  304. {
  305. if (empty($this->configurationParameters)) {
  306. $this->configurationParameters = $configurationParameters;
  307. }
  308. return $this;
  309. }
  310. public function getConfigurationParameters(): array
  311. {
  312. return $this->configurationParameters;
  313. }
  314. // ========================================
  315. // PackageInterface Methods
  316. // ========================================
  317. final public function setMetadata(\Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\PackageMetadata $metadata): PackageInterface
  318. {
  319. $this->metadata = $metadata;
  320. return $this;
  321. }
  322. final public function getMetadata(): \Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\PackageMetadata
  323. {
  324. return $this->metadata;
  325. }
  326. // ========================================
  327. // Symfony Bundle Methods
  328. // ========================================
  329. public function getContainerExtension()
  330. {
  331. if (null === $this->extension) {
  332. $this->extension = new \UVDesk\CommunityPackages\ArtisanCommerce\CustomTheme\DependencyInjection\CustomThemeExtension();
  333. }
  334. return $this->extension;
  335. }
  336. public function isMetadataSet(): bool
  337. {
  338. try {
  339. return $this->metadata !== null;
  340. } catch (\Exception $e) {
  341. return false;
  342. }
  343. }
  344. public function getDebugInfo(): array
  345. {
  346. $info = [
  347. 'class' => self::class,
  348. 'is_metadata_set' => $this->isMetadataSet(),
  349. 'metadata' => null,
  350. 'package_file' => __FILE__,
  351. 'timestamp' => date('Y-m-d H:i:s'),
  352. 'configuration_filepath' => $this->configurationFilepath ?? 'not set'
  353. ];
  354. if ($this->isMetadataSet()) {
  355. $metadata = $this->getMetadata();
  356. $info['metadata'] = [
  357. 'name' => $metadata->getName(),
  358. 'description' => $metadata->getDescription(),
  359. 'type' => $metadata->getType(),
  360. 'vendor' => $metadata->getVendor(),
  361. 'package' => $metadata->getPackage(),
  362. 'root' => $metadata->getRoot(),
  363. 'namespaces' => $metadata->getDefinedNamespaces(),
  364. 'package_references' => $metadata->getPackageReferences()
  365. ];
  366. }
  367. return $info;
  368. }
  369. }