Source of file BaseMaker.php

Size: 11,060 Bytes - Last Modified: 2023-11-16T22:56:03+01:00

/home/websites/teicee/packagist/site/phpdoc/conf/../vendor/teicee/make-bundle/src/Maker/BaseMaker.php

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
<?php
namespace TIC\MakeBundle\Maker;

use Symfony\Bundle\MakerBundle\Maker\AbstractMaker;
use Symfony\Bundle\MakerBundle\DependencyBuilder;
use Symfony\Bundle\MakerBundle\ConsoleStyle;
use Symfony\Bundle\MakerBundle\Generator;
use Symfony\Bundle\MakerBundle\FileManager;
use Symfony\Bundle\MakerBundle\Str;
use Symfony\Bundle\MakerBundle\Util\ClassNameDetails;
use Symfony\Bundle\MakerBundle\Doctrine\EntityDetails;
use Symfony\Bundle\MakerBundle\InputConfiguration;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Command\Command;

use TIC\CoreBundle\Util\StringHelper;
use TIC\MakeBundle\Helper\GeneratorTwigHelper;
use TIC\MakeBundle\Renderer\FormTypeRenderer;

/**
 *
 */
abstract class BaseMaker extends AbstractMaker
{

	protected $makerName;
	protected static $description;
	protected static $skelPath = __DIR__.'/../Resources/skeleton/';
	protected $dependencies = [];
	protected $twig = true;
	protected $test = false;
	protected $over = false;
	protected $ask  = true;
	protected $io;
	protected $generator;
	protected $fileManager;

	public function __construct()
	{
		$this->makerName = self::getMakerName();
	}

	/**
	 * Injection par call pour laisser le construct facilement surchargeable
	 */
	public function setFileManager(FileManager $fileManager)
	{
		$this->fileManager = $fileManager;
	}

	/**
	 *
	 */
	protected static function getMakerName(): string
	{
		if (preg_match("/\\\\Maker\\\\Make(.*)\$/", static::class, $m)) return $m[1];
	}


	/**
	 * Return the command name for your maker (e.g. make:controller).
	 */
	public static function getCommandName(): string
	{
#		return 'make:tic:' . strtolower(self::getMakerName());
		return 'tic:make:' . strtolower(self::getMakerName());
	}

	/**
	 *
	 */
	public static function getCommandDescription(): string
	{
		return sprintf("Génération basée sur les TIC Bundles pour %s.", self::getMakerName());
	}

	/**
	 * Configure the command: set description, input arguments, options, etc.
	 *
	 * By default, all arguments will be asked interactively. If you want
	 * to avoid that, use the $inputConfig->setArgumentAsNonInteractive() method.
	 */
	public function configureCommand(Command $command, InputConfiguration $inputConfig)
	{
		$command
			->addOption('test',         't', InputOption::VALUE_NONE, "Mode test: affichage sans génération de fichier")
			->addOption('no-template', null, InputOption::VALUE_NONE, "Désactiver la génération de template twig")
			->addOption('overwrite',   null, InputOption::VALUE_NONE, "ATTENTION: suppression des fichiers déjà existants !")
			->addOption('yes',         null, InputOption::VALUE_NONE, "Désactiver les demandes de confirmation")
		;
		$helpFile = __DIR__ . sprintf('/../Resources/help/Make%s.txt', $this->makerName);
		if (file_exists($helpFile)) $command->setHelp(file_get_contents($helpFile));
		
		$this->ticConfigure($command);
	}

	/**
	 * Configure any library dependencies that your maker requires.
	 */
	public function configureDependencies(DependencyBuilder $dependencies)
	{
		foreach ($this->dependencies as $dependency) $dependencies->addClassDependency(
			$dependency['class'], $dependency['value']
		);
	}

	/**
	 * Called after normal code generation: allows you to do anything.
	 */
	public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
	{
		$this->generator = $generator;
		$this->io   = $io;
		$this->ask  = ! $input->getOption('yes');
		$this->test = $input->getOption('test');
		$this->over = $input->getOption('overwrite');
		$this->twig = ! $input->getOption('no-template');
		
		$rc = $this->ticGenerate($input, $io);
		if (! $rc) return;
		
		$generator->writeChanges();
		$this->writeSuccessMessage($io);
		$io->text("Next: Open your new controller class and add some pages!");
	}


	/**
	 *
	 */
	abstract protected function ticConfigure(Command $command);

	/**
	 *
	 */
	abstract protected function ticGenerate(InputInterface $input);


	/**
	 * Pré-traitement du nom de classe passé en argument aux commandes.
	 * - accepte les caractères '/' et '.' en séparateur de chemin (au lieu de '\')
	 * - force une majuscule sur tous éléments du chemin du nom de classe
	 */
	protected function fixClassName(string $name, ?bool $skip_path = false): string
	{
		$name = StringHelper::asciify($name);
		$name = preg_replace_callback('/_(.)/', function($m){ return strtoupper($m[1]); }, $name);
		
		if (strpos("\\", $name) === FALSE) $name = preg_replace('/[\/\.]+/', "\\", $name);
		
		$parts = explode("\\", $name);
		return ($skip_path) ? ucfirst(array_pop($parts)) : implode("\\", array_map('ucfirst', $parts));
	}

	/**
	 *
	 */
	protected function getRootNamespace(ClassNameDetails $classNameDetails, ?string $classFolder = null): string
	{
		$ns = str_replace($classNameDetails->getRelativeName(), '', $classNameDetails->getFullName());
		$ns = ($classFolder === null) ? preg_replace("/\\\\[^\\\\]*\\\\?\$/", "", $ns) : str_replace("\\".$classFolder."\\", "", $ns);
		return $ns;
	}

	/**
	 *
	 */
	protected function getSnakeCaseName(ClassNameDetails $classNameDetails): string
	{
		$parts = explode("\\", $classNameDetails->getRelativeNameWithoutSuffix());
		$last = array_pop($parts);
		if (empty($parts)) $parts[] = 'app';
		return strtolower(implode('', $parts) . '_' . $last);
	}

	/**
	 *
	 */
	protected function getVariablesFromName(string $inputName, ?string $type = "Controller"): array
	{
		$classPrefix = ucfirst($type) . "\\";
		$classSuffix = ($classPrefix === "Entity\\") ? "" : ucfirst($type);
		$classDetails = $this->generator->createClassNameDetails($inputName, $classPrefix, $classSuffix);
		$nameSpace = $this->getRootNamespace($classDetails);
		$snakeCase = $this->getSnakeCaseName($classDetails);
		
		$variables = array(
			'base_name'  => $classDetails->getRelativeNameWithoutSuffix(),
			'item_name'  => preg_replace("/${classSuffix}\$/", '', $classDetails->getShortName()),
			'trans_base' => str_replace('_', '.', $snakeCase) . '.',
		);
		if ($classPrefix == "Controller\\") $variables+= array(
			'route_name' => $snakeCase . '_',
			'route_path' => Str::asRoutePath($variables['base_name']),
			'views_path' => Str::asFilePath($variables['base_name']),
			'views_root' => preg_replace('/^(\/*)([^\/]+\/)?(.+)$/', '${2}layout.html.twig', Str::asFilePath($variables['base_name'])),
			'ctrl_class' => $classDetails->getFullName(),
			'form_class' => $nameSpace . "\\Form\\"       . $variables['base_name'] . "Type",
		);
		if ($classPrefix == "Type\\") $variables+= array(
			'form_class' => $nameSpace . "\\Form\\"       . $variables['base_name'] . "Type",
		);
		return $variables+= array(
			'item_class' => $nameSpace . "\\Entity\\"     . $variables['item_name'],
			'repo_class' => $nameSpace . "\\Repository\\" . $variables['item_name'] . "Repository",
			'root_directory' => $this->generator->getRootDirectory(),
		);
	}

// -----------------------------------------------------------------------------

	protected function ticGenerateTemplates(string $skelDir, array $templates, array $variables = []): array
	{
		if (isset($variables['views_root'])) $this->initTwigLayout($variables['views_root'], $variables);
		
		$res = array();
		foreach ($templates as $template) $res[] = $this->ticGenerateTemplate(
			$variables['views_path'] . '/' . $template . '.html.twig',
			self::$skelPath . $skelDir . '/twig_' . $template . '.tpl.php',
			$variables
		);
		return $res;
	}

	/**
	 * Génération du template twig parent (si le fichier n'existe pas déjà).
	 */
	protected function initTwigLayout(string $tpl_path, array $variables = []): void
	{
		$src_path = static::$skelPath . 'base/twig_layout.tpl.php';
#		$tpl_name = dirname($tpl_path);
#		if ($tpl_name !== '.') $variables['webpack_entry'] = 'app_' . $tpl_name;
		try { $this->generator->generateTemplate($tpl_path, $src_path, $variables); }
		catch (\Symfony\Bundle\MakerBundle\Exception\RuntimeCommandException $e) { }
	}

	protected function ticGenerateTemplate(string $targetPath, string $templateName, array $variables = []): ?string
	{
		$templatePath = $this->fileManager->getPathForTemplate($targetPath);
		if (! $this->checkTargetPath( $templatePath )) return null;
		
		$variables['ticHelper'] = new GeneratorTwigHelper();
		$this->generator->generateTemplate($targetPath, $templateName, $variables);
		return $templatePath;
	}

	protected function ticGenerateClass(string $className, string $templateName, array $variables = []): ?string
	{
		if (! $this->checkTargetPath( $this->fileManager->getRelativePathForFutureClass($className) )) return null;
		
		return $this->generator->generateClass($className, $templateName, $variables);
	}

	protected function ticGenerateController(string $controllerClassName, string $controllerTemplatePath,  array $parameters = []): ?string
	{
		if (! $this->checkTargetPath( $this->fileManager->getRelativePathForFutureClass($controllerClassName) )) return null;
		
		return $this->generator->generateController($controllerClassName, $controllerTemplatePath, $parameters);
	}

	protected function ticGenerateFormType(FormTypeRenderer $renderer, ClassNameDetails $formDetails, EntityDetails $doctrineDetails, ClassNameDetails $entityDetails, array $constraintClasses = [], array $extraUseClasses = []): ?string
	{
		if (! $this->checkTargetPath( $this->fileManager->getRelativePathForFutureClass($formDetails->getFullName()) )) return null;
		
		return $renderer->generate($formDetails, $doctrineDetails, $entityDetails);
	}

	protected function checkTargetPath(string $targetPath): bool
	{
		$fullPath = $this->fileManager->absolutizePath($targetPath);
		
		if (! file_exists($fullPath)) return true;
		$this->io->caution("Le fichier à générer existe déjà : " . $fullPath);
		
		if (! $this->over) return false;
		if (! $this->confirm("Confirmer la suppression du fichier actuel")) return false;
		
		return unlink($fullPath);
	}

	protected function confirm(string $question): bool
	{
		if (! $this->ask) return true;
		return $this->io->confirm($question, true);
	}


	/**
	 *
	 */
	protected static function hash2list(array $hash): array
	{
		$lines = array();
		foreach ($hash as $k => $v) $lines[] = array($k, $v);
		return $lines;
	}

	/**
	 *
	 */
	protected static function indentFile(string $file, ?bool $with_space = false): bool
	{
		if (! file_exists($file)) return false;
		$old = ($with_space) ? "\t" : "    ";
		$new = ($with_space) ? "    " : "\t";
		$len = strlen($old);
		$data = file_get_contents($file);
		$data = preg_replace_callback("/\n(($old)+)/", function($m) use($new,$len) { return "\n" . str_repeat($new, ceil(strlen($m[1]) / $len)); }, $data);
		$data = str_replace(";\n\n$new$new", ";\n$new$new", $data);
		file_put_contents($file, $data);
		return true;
	}

	/**
	 * Récapitulatif des fichiers générés
	 */
	protected function summary(array $results): bool
	{
		$this->io->section("Liste des fichiers générés :");
		$this->io->table([ 'Name', 'Path' ], $results);
		return true;
	}

}