PHP Classes

File: src/Plugin/Code/CodeGenerator.php

Recommend this page to a friend!
  Packages of Thierry Feuzeu   Jaxon   src/Plugin/Code/CodeGenerator.php   Download  
File: src/Plugin/Code/CodeGenerator.php
Role: Class source
Content type: text/plain
Description: Class source
Class: Jaxon
Call PHP classes from JavaScript using AJAX
Author: By
Last change:
Date: 4 months ago
Size: 8,984 bytes
 

Contents

Class file image Download
<?php

/**
 * CodeGenerator.php - Jaxon code generator
 *
 * Generate HTML, CSS and Javascript code for Jaxon.
 *
 * @package jaxon-core
 * @author Thierry Feuzeu <thierry.feuzeu@gmail.com>
 * @copyright 2016 Thierry Feuzeu <thierry.feuzeu@gmail.com>
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
 * @link https://github.com/jaxon-php/jaxon-core
 */

namespace Jaxon\Plugin\Code;

use
Jaxon\Di\Container;
use
Jaxon\Plugin\AbstractPlugin;
use
Jaxon\Plugin\CodeGeneratorInterface;
use
Jaxon\Utils\Http\UriException;
use
Jaxon\Utils\Template\TemplateEngine;

use function
array_map;
use function
array_merge;
use function
count;
use function
implode;
use function
is_subclass_of;
use function
ksort;
use function
md5;
use function
trim;

class
CodeGenerator
{
   
/**
     * @var AssetManager
     */
   
private $xAssetManager;

   
/**
     * The classes that generate code
     *
     * @var array<string>
     */
   
protected $aCodeGenerators = [];

   
/**
     * @var string
     */
   
protected $sJsOptions;

   
/**
     * @var array
     */
   
protected $aCss = [];

   
/**
     * @var array
     */
   
protected $aJs = [];

   
/**
     * @var array
     */
   
protected $aCodeJs = [];

   
/**
     * @var array
     */
   
protected $aCodeJsBefore = [];

   
/**
     * @var array
     */
   
protected $aCodeJsAfter = [];

   
/**
     * @var array
     */
   
protected $aCodeJsFiles = [];

   
/**
     * @var string
     */
   
protected $bGenerated = false;

   
/**
     * The constructor
     *
     * @param string $sVersion
     * @param Container $di
     * @param TemplateEngine $xTemplateEngine
     */
   
public function __construct(private string $sVersion, private Container $di,
        private
TemplateEngine $xTemplateEngine)
    {
       
// The Jaxon library config is on top.
       
$this->addCodeGenerator(ConfigScriptGenerator::class, 0);
       
// The ready script comes after.
       
$this->addCodeGenerator(ReadyScriptGenerator::class, 200);
    }

   
/**
     * Add a code generator to the list
     *
     * @param string $sClassName The code generator class
     * @param int $nPriority The desired priority, used to order the plugins
     *
     * @return void
     */
   
public function addCodeGenerator(string $sClassName, int $nPriority): void
   
{
        while(isset(
$this->aCodeGenerators[$nPriority]))
        {
           
$nPriority++;
        }
       
$this->aCodeGenerators[$nPriority] = $sClassName;
    }

   
/**
     * @param string $sClassName
     *
     * @return CodeGeneratorInterface
     */
   
private function getCodeGenerator(string $sClassName): CodeGeneratorInterface
   
{
        return
$this->di->g($sClassName);
    }

   
/**
     * Generate a hash for all the javascript code generated by the library
     *
     * @return string
     */
   
public function getHash(): string
   
{
       
$aHashes = array_map(function($sClassName) {
            return
$this->getCodeGenerator($sClassName)->getHash();
        },
$this->aCodeGenerators);
       
$aHashes[] = $this->sVersion;
        return
md5(implode('', $aHashes));
    }

   
/**
     * Render a template in the 'plugins' subdir
     *
     * @param string $sTemplate The template filename
     * @param array $aVars The template variables
     *
     * @return string
     */
   
private function render(string $sTemplate, array $aVars = []): string
   
{
       
$aVars['sJsOptions'] = $this->sJsOptions;
        return
$this->xTemplateEngine->render("jaxon::plugins/$sTemplate", $aVars);
    }

   
/**
     * Generate the Jaxon CSS and js codes for a given plugin
     *
     * @param CodeGeneratorInterface $xGenerator
     *
     * @return void
     */
   
private function generatePluginCodes(CodeGeneratorInterface $xGenerator): void
   
{
        if(!
is_subclass_of($xGenerator, AbstractPlugin::class) ||
           
$this->xAssetManager->shallIncludeAssets($xGenerator))
        {
           
// HTML tags for CSS
           
if(($sCss = trim($xGenerator->getCss(), " \n")) !== '')
            {
               
$this->aCss[] = $sCss;
            }
           
// HTML tags for js
           
if(($sJs = trim($xGenerator->getJs(), " \n")) !== '')
            {
               
$this->aJs[] = $sJs;
            }
        }

       
// Additional js codes
       
if(($xJsCode = $xGenerator->getJsCode()) !== null)
        {
            if((
$sJs = trim($xJsCode->sJs, " \n")) !== '')
            {
               
$this->aCodeJs[] = $sJs;
            }
            if((
$sJsBefore = trim($xJsCode->sJsBefore, " \n")) !== '')
            {
               
$this->aCodeJsBefore[] = $sJsBefore;
            }
            if((
$sJsAfter = trim($xJsCode->sJsAfter, " \n")) !== '')
            {
               
$this->aCodeJsAfter[] = $sJsAfter;
            }
           
$this->aCodeJsFiles = array_merge($this->aCodeJsFiles, $xJsCode->aFiles);
        }
    }

   
/**
     * Generate the Jaxon CSS ans js codes
     *
     * @return void
     * @throws UriException
     */
   
private function generateCodes(): void
   
{
        if(
$this->bGenerated)
        {
            return;
        }

       
$this->xAssetManager = $this->di->getAssetManager();
       
$this->sJsOptions = $this->xAssetManager->getJsOptions();

       
// Sort the code generators by ascending priority
       
ksort($this->aCodeGenerators);

        foreach(
$this->aCodeGenerators as $sClassName)
        {
           
$this->generatePluginCodes($this->getCodeGenerator($sClassName));
        }

       
// Load the Jaxon lib js files, after the other libs js files.
       
$this->aJs[] = trim($this->render('includes.js', [
           
'aUrls' => $this->xAssetManager->getJsLibFiles(),
        ]));

       
// The codes are already generated.
       
$this->bGenerated = true;
    }

   
/**
     * Get the HTML tags to include Jaxon CSS code and files into the page
     *
     * @return string
     * @throws UriException
     */
   
public function getCss(): string
   
{
       
$this->generateCodes();
        return
implode("\n\n", $this->aCss);
    }

   
/**
     * Get the HTML tags to include Jaxon javascript files into the page
     *
     * @return string
     * @throws UriException
     */
   
public function getJs(): string
   
{
       
$this->generateCodes();
        return
implode("\n\n", $this->aJs);
    }

   
/**
     * Get the Javascript code
     *
     * @return string
     */
   
public function getJsScript(): string
   
{
        foreach(
$this->aCodeGenerators as $sClassName)
        {
           
$xGenerator = $this->getCodeGenerator($sClassName);
           
// Javascript code
           
if(($sJsScript = trim($xGenerator->getScript(), " \n")) !== '')
            {
               
$aJsScript[] = $sJsScript;
            }
        }
        return
implode("\n\n", $aJsScript);
    }

   
/**
     * @param bool $bIncludeJs Also get the JS files
     * @param bool $bIncludeCss Also get the CSS files
     *
     * @return array<string>
     */
   
private function renderCodes(bool $bIncludeJs, bool $bIncludeCss): array
    {
       
$aCodes = [];
        if(
$bIncludeCss)
        {
           
$aCodes[] = $this->getCss();
        }
        if(
$bIncludeJs)
        {
           
$aCodes[] = $this->getJs();
        }

       
$sUrl = !$this->xAssetManager->shallCreateJsFiles() ? '' :
           
$this->xAssetManager->createJsFiles($this);
       
// Wrap the js code into the corresponding HTML tag.
       
$aCodes[] = $sUrl !== '' ?
           
$this->render('include.js', ['sUrl' => $sUrl]) :
           
$this->render('wrapper.js', ['sScript' => $this->getJsScript()]);

       
// Wrap the js codes into HTML tags.
       
if(count($this->aCodeJsBefore) > 0)
        {
           
$sScript = implode("\n\n", $this->aCodeJsBefore);
           
$aCodes[] = $this->render('wrapper.js', ['sScript' => $sScript]);
        }
        if(
count($this->aCodeJs) > 0)
        {
           
$sScript = implode("\n\n", $this->aCodeJs);
           
$aCodes[] = $this->render('wrapper.js', ['sScript' => $sScript]);
        }
        if(
count($this->aCodeJsFiles) > 0)
        {
           
$aCodes[] = $this->render('includes.js', ['aUrls' => $this->aCodeJsFiles]);
        }
        if(
count($this->aCodeJsAfter) > 0)
        {
           
$sScript = implode("\n\n", $this->aCodeJsAfter);
           
$aCodes[] = $this->render('wrapper.js', ['sScript' => $sScript]);
        }
        return
$aCodes;
    }

   
/**
     * Get the javascript code to be sent to the browser
     *
     * @param bool $bIncludeJs Also get the JS files
     * @param bool $bIncludeCss Also get the CSS files
     *
     * @return string
     * @throws UriException
     */
   
public function getScript(bool $bIncludeJs, bool $bIncludeCss): string
   
{
       
$this->generateCodes();
       
$aCodes = $this->renderCodes($bIncludeJs, $bIncludeCss);
        return
implode("\n\n", $aCodes);
    }
}