<?php
namespace UVDesk\CommunityPackages\ArtisanCommerce\CustomTheme;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\PackageInterface;
use Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\ConfigurablePackageInterface;
use UVDesk\CommunityPackages\ArtisanCommerce\CustomTheme\DependencyInjection\Compiler\TwigPathPass;
use Psr\Log\LoggerInterface;
class CustomThemePackage extends Bundle implements PackageInterface, ConfigurablePackageInterface
{
private $metadata;
private $configurationFilepath;
private $configurationParameters = [];
private $logger;
private $debugMode = true;
public function __construct(LoggerInterface $logger = null)
{
$this->logger = $logger;
if ($this->debugMode && $this->logger) {
$this->logger->info('[CustomThemePackage] Package instantiated', [
'class' => self::class,
'timestamp' => date('Y-m-d H:i:s')
]);
}
}
/**
* Symfony Bundle lifecycle: Register compiler passes
*/
public function build(ContainerBuilder $container): void
{
parent::build($container);
// Register the Twig path compiler pass
$container->addCompilerPass(new TwigPathPass());
}
/**
* UVDesk installation hook - called during uvdesk:configure-extension
* This is where we auto-register the bundle in config/bundles.php
*/
public function install(): void
{
$this->registerBundle();
$this->createConfigurationFile();
}
/**
* Auto-register this bundle in config/bundles.php
*/
private function registerBundle(): void
{
// Find project root by traversing up from package root
$projectRoot = $this->findProjectRoot();
if (!$projectRoot) {
if ($this->logger) {
$this->logger->error('[CustomThemePackage] Could not determine project root');
}
return;
}
$bundlesFile = $projectRoot . '/config/bundles.php';
if (!file_exists($bundlesFile)) {
if ($this->logger) {
$this->logger->warning('[CustomThemePackage] bundles.php not found', [
'expected_path' => $bundlesFile
]);
}
return;
}
// Load current bundles
$bundles = include $bundlesFile;
$bundleClass = self::class;
// Check if already registered
if (isset($bundles[$bundleClass])) {
if ($this->logger) {
$this->logger->info('[CustomThemePackage] Bundle already registered');
}
return;
}
// Add this bundle to the list
$bundles[$bundleClass] = ['all' => true];
// Generate new bundles.php content
$content = "<?php\n\nreturn [\n";
foreach ($bundles as $class => $envs) {
$envsStr = var_export($envs, true);
$content .= " {$class}::class => {$envsStr},\n";
}
$content .= "];\n";
// Write back to bundles.php
if (file_put_contents($bundlesFile, $content) !== false) {
if ($this->logger) {
$this->logger->info('[CustomThemePackage] Successfully auto-registered bundle', [
'bundle_class' => $bundleClass,
'bundles_file' => $bundlesFile
]);
}
} else {
if ($this->logger) {
$this->logger->error('[CustomThemePackage] Failed to write bundles.php', [
'bundles_file' => $bundlesFile
]);
}
}
}
/**
* Create the configuration file required by ConfigurablePackageInterface
*/
//private function createConfigurationFile(): void
//{
// if (!empty($this->configurationFilepath)) {
// $configDir = dirname($this->configurationFilepath);
//
// if (!file_exists($configDir)) {
// mkdir($configDir, 0755, true);
// }
//
// if (!file_exists($this->configurationFilepath)) {
// // Create empty configuration file
// $content = "# Custom Theme Package Configuration\ncustom_theme: []\n";
// file_put_contents($this->configurationFilepath, $content);
//
// if ($this->logger) {
// $this->logger->info('[CustomThemePackage] Created configuration file', [
// 'config_file' => $this->configurationFilepath
// ]);
// }
// }
// }
//}
/**
* Create the configuration file with full default values
* Called during install() - ensures config is ready immediately after installation
*/
private function createConfigurationFile(): void
{
if (!empty($this->configurationFilepath)) {
$configDir = dirname($this->configurationFilepath);
if (!file_exists($configDir)) {
mkdir($configDir, 0755, true);
}
if (!file_exists($this->configurationFilepath)) {
// Create configuration file with full defaults
$content = <<<YAML
# =============================================================================
# Custom Theme Package Configuration
# =============================================================================
# This file is automatically generated during module installation.
# You can edit these values to customize the module's behavior.
# After making changes, run: php bin/console cache:clear
# =============================================================================
custom_theme:
# Login Tracking Settings
# Track user login sessions, monitor session duration, and view detailed history
login_tracking:
enabled: true # Enable/disable login tracking
session_timeout: 3600 # Session timeout in seconds (default: 1 hour)
max_display_sessions: 100 # Maximum sessions to display in dashboard
track_ip: true # Track IP addresses for sessions
# Theme Customization Settings
# Customize the look and feel of your helpdesk
theme:
enabled: true # Enable custom theme
color_scheme: default # Color scheme: default, dark, light
custom_css: false # Enable custom CSS injection
# Display Preferences
# Configure date/time formats and timezone
display:
date_format: 'd.m.Y' # PHP date() format for dates
time_format: 'H:i:s' # PHP date() format for times
timezone: 'Europe/Vienna' # Default timezone (PHP timezone string)
YAML;
file_put_contents($this->configurationFilepath, $content);
if ($this->logger) {
$this->logger->info('[CustomThemePackage] Created configuration file with defaults', [
'config_file' => $this->configurationFilepath
]);
}
}
}
}
/**
* Find project root by traversing up from package location
*/
private function findProjectRoot(): ?string
{
$current = __DIR__;
// Traverse up looking for config/bundles.php
for ($i = 0; $i < 10; $i++) {
$current = dirname($current);
if (file_exists($current . '/config/bundles.php')) {
return $current;
}
}
return null;
}
// ========================================
// ConfigurablePackageInterface Methods
// ========================================
//public function getConfiguration(): ConfigurationInterface
//{
// // Return empty configuration schema (required by interface)
// return new class implements ConfigurationInterface {
// public function getConfigTreeBuilder()
// {
// $treeBuilder = new TreeBuilder('custom_theme');
// $rootNode = $treeBuilder->getRootNode();
//
// // Empty configuration - no parameters needed
// return $treeBuilder;
// }
// };
//}
public function getConfiguration(): ConfigurationInterface
{
return new class implements ConfigurationInterface {
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('custom_theme');
$rootNode = $treeBuilder->getRootNode();
$rootNode
->children()
// Login Tracking Settings
->arrayNode('login_tracking')
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')
->defaultTrue()
->info('Enable login tracking')
->end()
->integerNode('session_timeout')
->defaultValue(3600)
->min(300)
->max(86400)
->info('Session timeout in seconds')
->end()
->integerNode('max_display_sessions')
->defaultValue(100)
->min(10)
->max(1000)
->info('Maximum sessions to display in dashboard')
->end()
->booleanNode('track_ip')
->defaultTrue()
->info('Track IP addresses')
->end()
->end()
->end()
// Theme Settings
->arrayNode('theme')
->addDefaultsIfNotSet()
->children()
->booleanNode('enabled')
->defaultTrue()
->info('Enable custom theme')
->end()
->scalarNode('color_scheme')
->defaultValue('default')
->info('Color scheme (default, dark, light)')
->end()
->scalarNode('icon_border_radius')
->defaultValue('50%')
->info('Dashboard icon border radius (e.g. 50% or 12px)')
->end()
->booleanNode('custom_css')
->defaultFalse()
->info('Enable custom CSS')
->end()
->end()
->end()
// Display Preferences
->arrayNode('display')
->addDefaultsIfNotSet()
->children()
->scalarNode('date_format')
->defaultValue('d.m.Y')
->info('Date format (PHP date() format)')
->end()
->scalarNode('time_format')
->defaultValue('H:i:s')
->info('Time format (PHP date() format)')
->end()
->scalarNode('timezone')
->defaultValue('Europe/Vienna')
->info('Default timezone')
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
};
}
public function setConfigurationFilepath(string $configurationFilepath): ConfigurablePackageInterface
{
if (empty($this->configurationFilepath)) {
$this->configurationFilepath = $configurationFilepath;
}
return $this;
}
public function getConfigurationFilepath(): string
{
return $this->configurationFilepath ?? '';
}
public function setConfigurationParameters(array $configurationParameters): ConfigurablePackageInterface
{
if (empty($this->configurationParameters)) {
$this->configurationParameters = $configurationParameters;
}
return $this;
}
public function getConfigurationParameters(): array
{
return $this->configurationParameters;
}
// ========================================
// PackageInterface Methods
// ========================================
final public function setMetadata(\Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\PackageMetadata $metadata): PackageInterface
{
$this->metadata = $metadata;
return $this;
}
final public function getMetadata(): \Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\PackageMetadata
{
return $this->metadata;
}
// ========================================
// Symfony Bundle Methods
// ========================================
public function getContainerExtension()
{
if (null === $this->extension) {
$this->extension = new \UVDesk\CommunityPackages\ArtisanCommerce\CustomTheme\DependencyInjection\CustomThemeExtension();
}
return $this->extension;
}
public function isMetadataSet(): bool
{
try {
return $this->metadata !== null;
} catch (\Exception $e) {
return false;
}
}
public function getDebugInfo(): array
{
$info = [
'class' => self::class,
'is_metadata_set' => $this->isMetadataSet(),
'metadata' => null,
'package_file' => __FILE__,
'timestamp' => date('Y-m-d H:i:s'),
'configuration_filepath' => $this->configurationFilepath ?? 'not set'
];
if ($this->isMetadataSet()) {
$metadata = $this->getMetadata();
$info['metadata'] = [
'name' => $metadata->getName(),
'description' => $metadata->getDescription(),
'type' => $metadata->getType(),
'vendor' => $metadata->getVendor(),
'package' => $metadata->getPackage(),
'root' => $metadata->getRoot(),
'namespaces' => $metadata->getDefinedNamespaces(),
'package_references' => $metadata->getPackageReferences()
];
}
return $info;
}
}