MOON
Server: Apache
System: Linux nserver.cafsindia.com 4.18.0-553.104.1.lve.el8.x86_64 #1 SMP Tue Feb 10 20:07:30 UTC 2026 x86_64
User: cafsindia (1002)
PHP: 8.2.30
Disabled: NONE
Upload Files
File: //home/cafsindia/help.cafsindia.com/vendor/uvdesk/extension-framework/Console/BuildExtensions.php
<?php

namespace Webkul\UVDesk\ExtensionFrameworkBundle\Console;

use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\PackageMetadata;
use Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\PackageInterface;
use Webkul\UVDesk\ExtensionFrameworkBundle\Definition\Package\ConfigurablePackageInterface;

class BuildExtensions extends Command
{
    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;

        parent::__construct();
    }

    protected function configure()
    {
        $this->setName('uvdesk_extensions:configure-extensions');
    }

    protected function execute(InputInterface $input, OutputInterface $output):int
    {
        if ('dev' != $this->container->get('kernel')->getEnvironment()) {
            $output->writeln("\n<comment>This command is only allowed to be used in development environment.</comment>");

            return Command::INVALID;
        }

        $metadata = $this->prepareMetadata();
        $lockfile = $this->updateLockfile($metadata);

        $this->updateComposerJson($output, $lockfile);
        $this->autoconfigurePackages($output, $metadata);

        return Command::SUCCESS;
    }

    private function prepareMetadata()
    {
        $metadata = [];
        $path = $this->container->getParameter('uvdesk_extensions.dir');

        if (!file_exists($path) || !is_dir($path)) {
            throw new \Exception("No apps directory found. Looked in $path");
        }

        foreach (array_diff(scandir($path), ['.', '..']) as $vendor) {
            $directory = "$path/$vendor";

            if (file_exists($directory) && is_dir($directory)) {
                foreach (array_diff(scandir($directory), ['.', '..']) as $package) {
                    $root = "$directory/$package";
    
                    if (file_exists($root) && is_dir($root)) {
                        $packageMetadata = new PackageMetadata($root);

                        if ($vendor != $packageMetadata->getVendor() || $package != $packageMetadata->getPackage()) {
                            throw new \Exception("Invalid package extension.json file. The qualified package name should be '$vendor/$package' but the specified name is '" . $packageMetadata->getName() . "'");
                        }

                        $metadata[] = $packageMetadata;
                    }
                }
            }
        }

        // Sort packages alphabetically
        usort($metadata, function($data_a, $data_b) {
			return strcasecmp($data_a->getName(), $data_b->getName());
        });

        return $metadata;
    }

    private function updateLockfile(array $metadata = [])
    {
        $lockfile = [
            '_readme' => [
                "This file locks the dependencies of your project to a known state",
                "This file is @generated automatically. Avoid making changes to this file directly.",
            ],
            'packages' => array_map(function ($packageMetadata) {
                return [
                    'name' => $packageMetadata->getName(),
                    'description' => $packageMetadata->getDescription(),
                    'type' => $packageMetadata->getType(),
                    'autoload' => $packageMetadata->getDefinedNamespaces(),
                    'package' => $packageMetadata->getPackageReferences(),
                ];;
            }, $metadata),
        ];

        $path = $this->container->getParameter('kernel.project_dir') . "/uvdesk.lock";
        file_put_contents($path, json_encode($lockfile, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));

        return $lockfile;
    }

    private function updateComposerJson($output, array $lockfile = [])
    {
        $path = $this->container->getParameter('kernel.project_dir') . "/composer.json";
        $prefix = str_ireplace($this->container->getParameter('kernel.project_dir') . "/", "", $this->container->getParameter('uvdesk_extensions.dir'));
        
        $json = json_decode(file_get_contents($path), true);
        $psr4_current = $psr4_modified = $json['autoload']['psr-4'] ?? [];

        foreach ($lockfile['packages'] as $package) {
            foreach ($package['autoload'] as $namespace => $relativePath) {
                $psr4_modified[$namespace] = "$prefix/" . $package['name'] . "/" . $relativePath;
            }
        }

        if (array_diff($psr4_modified, $psr4_current) != null) {
            $json['autoload']['psr-4'] = $psr4_modified;
            file_put_contents($path, json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));

            $output->writeln("New extensions have been found and added to composer.json. Dumping composer autoloader...\n");

            shell_exec('composer dump-autoload');
        }
    }

    private function getUnloadedReflectionClass(string $class, PackageMetadata $metadata) : \ReflectionClass
    {
        try {
            $reflectionClass = new \ReflectionClass($class);
        } catch (\ReflectionException $e) {
            $classPath = null;
            $iterations = explode('\\', $class);

            foreach ($metadata->getDefinedNamespaces() as $namespace => $path) {
                $depth = 1;
                $namespaceIterations = explode('\\', $namespace);

                foreach ($iterations as $index => $iteration) {
                    if (empty($namespaceIterations[$index]) || $namespaceIterations[$index] != $iteration) {
                        break;
                    }

                    $depth++;
                }

                if (0 === (count($namespaceIterations) - $depth)) {
                    $path .= str_ireplace([$namespace, "\\"], ["", "/"], $class);
                    $classPath = $metadata->getRoot() . "/$path.php";
                    break;
                }
            }
        } finally {
            if (empty($reflectionClass) && !empty($classPath)) {
                include_once $classPath;

                $reflectionClass = new \ReflectionClass($class);
            } else if (empty($reflectionClass)) {
                throw new \Exception("Class $class does not exist");
            }
        }

        return $reflectionClass;
    }

    private function autoconfigurePackages($output, array $metadata = [])
    {
        $pathToConfig = $this->container->getParameter('kernel.project_dir') . "/config/extensions";
        $pathToDoctrineConfig = $this->container->getParameter('kernel.project_dir') . "/config/packages/doctrine.yaml";

        if (!file_exists($pathToConfig) || !is_dir($pathToConfig)) {
            mkdir($pathToConfig, 0755, true);
        }

        if (file_exists($pathToDoctrineConfig)) {
            $expiredNamespaces = [];
            $doctrine = Yaml::parseFile($pathToDoctrineConfig);
            $doctrineMappings = $doctrine['doctrine']['orm']['mappings'];

            // Filter out existing community package configurations
            foreach ($doctrineMappings as $namespace => $mappingDetails) {
                $namespaceIterations = explode('\\', $namespace);

                if (count($namespaceIterations) >= 2) {
                    if ('UVDesk' == $namespaceIterations[0] && 'CommunityPackages' == $namespaceIterations[1]) {
                        $expiredNamespaces[] = $namespace;
                    }
                }
            }

            foreach ($expiredNamespaces as $namespace) {
                unset($doctrineMappings[$namespace]);
            }
        }

        foreach ($metadata as $packageMetadata) {
            $class = current(array_keys($packageMetadata->getPackageReferences()));
            $packageReflectionClass = $this->getUnloadedReflectionClass($class, $packageMetadata);
            
            if (!$packageReflectionClass->implementsInterface(PackageInterface::class)) {
                throw new \Exception("Class $class could not be registered as an package. Please check that it implements the " . PackageInterface::class . " interface.");
            }

            if (!empty($doctrineMappings)) {
                $packageDoctrineMetadata = $this->getPackageDoctrineMetadata($packageMetadata);

                if (!empty($packageDoctrineMetadata)) {
                    $namespace = current(array_keys($packageDoctrineMetadata));
                    $doctrineMappings[$namespace] = $packageDoctrineMetadata[$namespace];
                }
            }

            if ($packageReflectionClass->implementsInterface(ConfigurablePackageInterface::class)) {
                $configurablePackage = $packageReflectionClass->newInstanceWithoutConstructor();
                $configurablePackage->setConfigurationFilepath($pathToConfig . "/" . str_replace(['/', '-'], '_', $packageMetadata->getName()) . ".yaml");

                if (!file_exists($configurablePackage->getConfigurationFilepath()) || is_dir($configurablePackage->getConfigurationFilepath())) {
                    $configurablePackage->install();
                }
            }
        }

        if (!empty($doctrine) && !empty($doctrineMappings)) {
            // Add quotes, we will remove later any extra quotes
            foreach ($doctrineMappings as $namespace => $attributes) {
                $attributes['dir'] = "'" . $attributes['dir'] . "'";
                $attributes['prefix'] = "'" . $attributes['prefix'] . "'";

                $doctrineMappings[$namespace] = $attributes;
            }

            $doctrine['doctrine']['orm']['mappings'] = $doctrineMappings;

            $originalContent = file_get_contents($pathToDoctrineConfig);
            $modifiedContent = YAML::dump($doctrine, 6);

            $explodedOriginalContent = preg_split("/\r\n|\n|\r/", $originalContent);
            $explodedModifiedContent = preg_split("/\r\n|\n|\r/", $modifiedContent);

            $incr = 0;
            $skipFlag = false;
            $processedModifiedContent = [];

            foreach ($explodedModifiedContent as $index => $content) {
                if ($skipFlag || !isset($explodedOriginalContent[$index + $incr])) {
                    $processedModifiedContent[] = $content;

                    continue;
                }

                if ('mappings:' == trim($explodedOriginalContent[$index + $incr]) || 'mappings:' == trim($explodedModifiedContent[$index])) {
                    $skipFlag = true;
                    $processedModifiedContent[] = $content;

                    continue;
                } else if ($content == $explodedOriginalContent[$index + $incr]) {
                    $processedModifiedContent[] = $content;
                } else {
                    if (str_replace(['\'', '"'], '', $content) == str_replace(['\'', '"'], '', $explodedOriginalContent[$index + $incr])) {
                        $processedModifiedContent[] = $explodedOriginalContent[$index + $incr];

                        continue;
                    }

                    for ($i = $index + $incr; $i < count($explodedOriginalContent); $i++) {
                        if (trim($explodedModifiedContent[$index]) == trim($explodedOriginalContent[$i])) {
                            $processedModifiedContent[] = $content;
                            break;
                        } else if (str_replace(['\'', '"'], '', trim($explodedModifiedContent[$index])) == str_replace(['\'', '"'], '', trim($explodedOriginalContent[$i]))) {
                            $processedModifiedContent[] = $explodedOriginalContent[$i];
                            break;
                        }

                        $incr++;
                        $processedModifiedContent[] = $explodedOriginalContent[$i];
                    }
                }
            }

            $content = str_replace("'''", "'", implode(PHP_EOL, $processedModifiedContent));
            file_put_contents($pathToDoctrineConfig, $content);
        }
    }

    private function getPackageDoctrineMetadata($packageMetadata)
    {
        $params = [
            'is_bundle' => false,
            'type' => 'annotation',
        ];

        $baseNamespace = current(array_keys($packageMetadata->getDefinedNamespaces()));
        $packageClassPath = current(array_keys($packageMetadata->getPackageReferences()));
        $relativePathToNamespace = $packageMetadata->getDefinedNamespaces()[$baseNamespace];

        $baseNamespace = rtrim($baseNamespace, '\\');
        $pathToNamespace = rtrim($packageMetadata->getRoot(), '/') . "/" . rtrim(ltrim($relativePathToNamespace, '/'), '/') . "/";
        $pathToEntities = $pathToNamespace . "Entity";

        if (file_exists($pathToEntities) && is_dir($pathToEntities)) {
            // Parse qualified vendor name
            $p1 = strrpos($baseNamespace, '\\');
            $p2 = strrpos(substr($baseNamespace, 0, $p1), '\\');
            $vendor = substr($baseNamespace, $p2 + 1, $p1 - $p2 - 1);

            // Parse qualified package name
            $p1 = strrpos($packageClassPath, '\\');
            $package = substr($packageClassPath, $p1 + 1);

            $params['dir'] = str_replace($this->container->getParameter('kernel.project_dir'), '%kernel.project_dir%', $pathToEntities);
            $params['prefix'] = "$baseNamespace\\Entity";
            $params['alias'] = "$vendor$package";

            return [$baseNamespace => $params];
        }

        return null;
    }
}