X-Git-Url: https://git.rapsys.eu/packbundle/blobdiff_plain/6bc3a323095049fba5ac8bb2b1a2cef1e82b8df5..6065a3af58ca2a4d96134be6f7d533e0189cf590:/Parser/TokenParser.php

diff --git a/Parser/TokenParser.php b/Parser/TokenParser.php
index 9f2bf14..02acca3 100644
--- a/Parser/TokenParser.php
+++ b/Parser/TokenParser.php
@@ -1,11 +1,21 @@
-<?php
+<?php declare(strict_types=1);
 
-namespace Rapsys\PackBundle\Twig;
+/*
+ * This file is part of the Rapsys PackBundle package.
+ *
+ * (c) Raphaël Gertz <symfony@rapsys.eu>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Rapsys\PackBundle\Parser;
 
 use Symfony\Component\Asset\PackageInterface;
 use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
 use Symfony\Component\Filesystem\Filesystem;
 use Symfony\Component\HttpKernel\Config\FileLocator;
+
 use Twig\Error\Error;
 use Twig\Node\Expression\AssignNameExpression;
 use Twig\Node\Node;
@@ -15,50 +25,39 @@ use Twig\Source;
 use Twig\Token;
 use Twig\TokenParser\AbstractTokenParser;
 
-class PackTokenParser extends AbstractTokenParser {
-	///The tag name
-	protected $tag;
+class TokenParser extends AbstractTokenParser {
+	/**
+	 * The stream context instance
+	 */
+	protected mixed $ctx;
 
 	/**
 	 * Constructor
 	 *
-	 * @param FileLocator      locator The FileLocator instance
-	 * @param PackageInterface package The Assets Package instance
-	 * @param array            config  The config path
-	 * @param string           tag     The tag name
-	 * @param string           output  The default output string
-	 * @param array            filters The default filters array
+	 * @param FileLocator $locator The FileLocator instance
+	 * @param PackageInterface $package The Assets Package instance
+	 * @param array $config The config path
+	 * @param string $tag The tag name
+	 * @param string $output The default output string
+	 * @param array $filters The default filters array
 	 */
-	public function __construct(FileLocator $locator, PackageInterface $package, $config, $tag, $output, $filters) {
-		//Save locator
-		$this->locator = $locator;
-
-		//Save assets package
-		$this->package = $package;
-
-		//Set name
-		$this->name = $config['name'];
-
-		//Set scheme
-		$this->scheme = $config['scheme'];
-
-		//Set timeout
-		$this->timeout = $config['timeout'];
-
-		//Set agent
-		$this->agent = $config['agent'];
-
-		//Set redirect
-		$this->redirect = $config['redirect'];
-
-		//Set tag
-		$this->tag = $tag;
-
-		//Set output
-		$this->output = $output;
-
-		//Set filters
-		$this->filters = $filters;
+	//TODO: change config to name and get other values from RAPSYSPACK_REDIRECT, RAPSYSPACK_SCHEME, RAPSYSPACK_TIMEOUT, RAPSYSPACK_AGENT env variables ?
+	public function __construct(protected FileLocator $locator, protected PackageInterface $package, protected array $config, protected string $tag, protected string $output, protected array $filters) {
+		//Set ctx
+		$this->ctx = stream_context_create(
+			[
+				'http' => [
+					#'header' => ['Referer: https://www.openstreetmap.org/'],
+					//TODO: set as bundle env config
+					'max_redirects' => $config['redirect']?:5,
+					//TODO: set as bundle env config
+					'timeout' => $config['timeout']?:(int)ini_get('default_socket_timeout'),
+					#'user_agent' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36',
+					//TODO: set as bundle env config
+					'user_agent' => $config['agent']?:(string)ini_get('user_agent')?:'rapsys_pack/2.0.0',
+				]
+			]
+		);
 	}
 
 	/**
@@ -66,35 +65,26 @@ class PackTokenParser extends AbstractTokenParser {
 	 *
 	 * @return string This tag name
 	 */
-	public function getTag() {
+	public function getTag(): string {
 		return $this->tag;
 	}
 
 	/**
 	 * Parse the token
 	 *
-	 * @param Token token The \Twig\Token instance
+	 * @xxx Skip filter when debug mode is enabled is not possible
+	 * @xxx This code is only run once when twig cache is enabled
+	 * @xxx Twig cache value is not avaible in container parameters, maybe in twig env ?
 	 *
+	 * @param Token $token The \Twig\Token instance
 	 * @return Node The PackNode
-	 *
-	 * @todo see if we can't add a debug mode behaviour
-	 *
-	 * If twig.debug or env=dev (or rapsys_pack.config.debug?) is set, it should be possible to loop on each input
-	 * and process the captured body without applying requested filter.
-	 *
-	 * @todo list:
-	 * - detect debug mode
-	 * - retrieve fixe link from input s%@(Name)Bundle/Resources/public(/somewhere/file.ext)%/bundles/\L\1\E\2%
-	 * - for each inputs:
-	 *   - generate a set asset_url=x
-	 *   - generate a body
 	 */
-	public function parse(Token $token) {
+	public function parse(Token $token): Node {
 		$parser = $this->parser;
 		$stream = $this->parser->getStream();
 
 		$inputs = [];
-		$name = $this->name;
+		$name = $this->config['name'];
 		$output = $this->output;
 		$filters = $this->filters;
 
@@ -140,8 +130,6 @@ class PackTokenParser extends AbstractTokenParser {
 		//Process end block
 		$stream->expect(Token::BLOCK_END_TYPE);
 
-		//TODO: debug mode should be inserted here before the output variable is rewritten
-
 		//Replace star with sha1
 		if (($pos = strpos($output, '*')) !== false) {
 			//XXX: assetic use substr(sha1(serialize($inputs).serialize($filters).serialize($options)), 0, 7)
@@ -153,7 +141,8 @@ class PackTokenParser extends AbstractTokenParser {
 			//Deal with generic url
 			if (strpos($inputs[$k], '//') === 0) {
 				//Fix url
-				$inputs[$k] = $this->scheme.substr($inputs[$k], 2);
+				//TODO: set as bundle env config
+				$inputs[$k] = $this->config['scheme'].substr($inputs[$k], 2);
 			//Deal with non url path
 			} elseif (strpos($inputs[$k], '://') === false) {
 				//Check if we have a bundle path
@@ -184,23 +173,12 @@ class PackTokenParser extends AbstractTokenParser {
 			}
 		}
 
-		//Init context
-		$ctx = stream_context_create(
-			[
-				'http' => [
-					'timeout' => $this->timeout,
-					'user_agent' => $this->agent,
-					'redirect' => $this->redirect,
-				]
-			]
-		);
-
 		//Check inputs
 		if (!empty($inputs)) {
 			//Retrieve files content
 			foreach($inputs as $input) {
 				//Try to retrieve content
-				if (($data = file_get_contents($input, false, $ctx)) === false) {
+				if (($data = file_get_contents($input, false, $this->ctx)) === false) {
 					throw new Error(sprintf('Unable to retrieve input path "%s"', $input), $token->getLine(), $stream->getSourceContext());
 				}
 				//Append content
@@ -261,7 +239,7 @@ class PackTokenParser extends AbstractTokenParser {
 			try {
 				//Create dir
 				//XXX: set as 0775, symfony umask (0022) will reduce rights (0755)
-			    $filesystem->mkdir($dir, 0775);
+				$filesystem->mkdir($dir, 0775);
 			} catch (IOExceptionInterface $e) {
 				//Throw error
 				throw new Error(sprintf('Output directory "%s" do not exists and unable to create it', $dir), $token->getLine(), $stream->getSourceContext(), $e);
@@ -297,28 +275,25 @@ class PackTokenParser extends AbstractTokenParser {
 	/**
 	 * Test for tag end
 	 *
-	 * @param Token token The \Twig\Token instance
-	 *
-	 * @return bool
+	 * @param Token $token The \Twig\Token instance
+	 * @return bool The token end test result
 	 */
-	public function testEndTag(Token $token) {
+	public function testEndTag(Token $token): bool {
 		return $token->test(['end'.$this->getTag()]);
 	}
 
 	/**
 	 * Get path from bundled file
 	 *
-	 * @param string     file   The bundled file path
-	 * @param int        lineno The template line where the error occurred
-	 * @param Source     source The source context where the error occurred
-	 * @param \Exception prev   The previous exception
+	 * @see https://symfony.com/doc/current/bundles.html#overridding-the-bundle-directory-structure
 	 *
+	 * @param string $file The bundled file path
+	 * @param int $lineno The template line where the error occurred
+	 * @param Source $source The source context where the error occurred
+	 * @param Exception $prev The previous exception
 	 * @return string The resolved file path
-	 *
-	 * @todo Try retrive public dir from the member function BundleNameBundle::getPublicDir() return value ?
-	 * @xxx see https://symfony.com/doc/current/bundles.html#overridding-the-bundle-directory-structure
 	 */
-	public function getLocated($file, int $lineno = 0, Source $source = null, \Exception $prev = null) {
+	public function getLocated(string $file, int $lineno = 0, ?Source $source = null, ?\Exception $prev = null): string {
 		/*TODO: add a @jquery magic feature ?
 		if ($file == '@jquery') {
 			#header('Content-Type: text/plain');
@@ -329,7 +304,7 @@ class PackTokenParser extends AbstractTokenParser {
 
 		//Check that we have a / separator between bundle name and path
 		if (($pos = strpos($file, '/')) === false) {
-			throw new Error(sprintf('Invalid path "%s"', $file), $token->getLine(), $stream->getSourceContext());
+			throw new Error(sprintf('Invalid path "%s"', $file), $lineno, $source);
 		}
 
 		//Set bundle
@@ -382,7 +357,7 @@ class PackTokenParser extends AbstractTokenParser {
 				//Catch bundle does not exist or is not enabled exception again
 			} catch(\InvalidArgumentException $e) {
 				//Bail out as bundle or path is invalid and we have no way to know what was meant
-				throw new Error(sprintf('Invalid bundle name "%s" in path "%s". Maybe you meant "%s"', substr($file, 1, $pos - 1), $file, $bundle.'/'.$path), $token->getLine(), $stream->getSourceContext(), $e);
+				throw new Error(sprintf('Invalid bundle name "%s" in path "%s". Maybe you meant "%s"', substr($file, 1, $pos - 1), $file, $bundle.'/'.$path), $lineno, $source, $e);
 			}
 		}