How to configure Twig to find templates? - php

I am using Twig with Slim, and am getting the following error:
Warning: file_get_contents(application/templates/config.html): failed
to open stream: No such file or directory in
/var/www/testing/vendor/twig/twig/lib/Twig/Loader/Filesystem.php on
line 131
The script below is located in /var/www/testing/html/index.php, and I have verified that the template exists at /var/www/testing/application/templates/config.html.
$container['view'] = function ($c) {
$view = new \Slim\Views\Twig('../application/templates', [
//'cache' => 'path/to/cache' // See auto_reload option
'debug' => true,
'strict_variables'=> true
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$c['router'],
$c['request']->getUri()
));
$view->addExtension(new \Twig_Extension_Debug());
return $view;
};
$app->get('/config', function (Request $request, Response $response) {
return $this->view->render($response, 'config.html',[]);
});
Line 131 is shown below and returns config.html.
public function getSource($name)
{
return file_get_contents($this->findTemplate($name));
}
I have used this same script in another similar server (however, maybe different PHP version and php.ini and httpd.conf may be different), and do not have this issue?
Obviously, I have configured something incorrectly. How should I configure Twig to find templates?

Yes, that's a problem (bug?) I've encountered last week, and #geggleto solved it.
This is because of Twig update from v1.26.1 from 1.24.2.
This is how Twig grabbed in 1.24.2 (method Twig_Loader_Filesystem::normalizeName):
protected function normalizeName($name)
{
return preg_replace('#/{2,}#', '/', str_replace('\\', '/', (string) $name));
}
And this is how it grabs file in 1.26.1:
private function normalizePath($path)
{
$parts = explode('/', str_replace('\\', '/', $path));
$isPhar = strpos($path, 'phar://') === 0;
$new = array();
foreach ($parts as $i => $part) {
if ('..' === $part) {
array_pop($new);
} elseif ('.' !== $part && ('' !== $part || 0 === $i || $isPhar && $i < 3)) {
$new[] = $part;
}
}
return implode('/', $new);
}
See that array_pop($new); line? That's the one that ruins use of relative path.
#geggleto suggested to use absolute path instead of relative, and it worked:
\Slim\Views\Twig(__DIR__.'/../application/templates')
To sum up: this happens because of Twig new version.

Related

Laravel Localization Nested JSON Language File

I'm trying to make my project multi-language.
I want to work with JSON files since my project has lots of pages,so a lot of strings to translate.
In order to avoid confusion I want to use nested JSON objects instead of just keys.
For example my en.json file looking like this:
{
"login": {
"login": "Login",
"email": "Email",
"emailPlaceholder": "Registered email address",
"password": "Password",
"passwordPlaceHolder": "Your account password"
},
"dashboard": {}
}
So I want to have a key for each page.
But when I use it on the view files, it reads just as a regular string:
<label for="email">
{{ __('login.email') }}
</label>
Any help would be nice, thank you very much.
Try:
<label for="email">
{{ __('login')['email'] }}
</label>
You can get this approach by changing the default __ helper by:
use Illuminate\Support\Arr;
function __($key = null, $replace = [], $locale = null)
{
// Default behavior
if (is_null($key)) return $key;
if (trans()->has($key)) return trans($key, $replace, $locale);
// Search in .json file
$search = Arr::get(trans()->get('*'), $key);
if ($search !== null) return $search;
// Return .json fallback
$fallback = Arr::get(trans()->get('*', [], config('app.fallback_locale')), $key);
if ($fallback !== null) return $fallback;
// Return key name if not found
else return $key;
}
Creating custom bootstrap helpers
if you dont know how to change the default helper, create a file with any name (ex: bootstrap/helpers.php), then in the file public/index.php add this line just before 'Register The Auto Loader'
/*
|--------------------------------------------------------------------------
| Register Custom Helpers
|------------------------------------------------------------------------
*/
require __DIR__.'/../bootstrap/helpers.php';
(Optional) Variables feature
if you also want to use the Variables feature, just like __(welcome.user, ['user'=>'david']) you must create a new helper on that file:
use Illuminate\Support\Str;
function trans_replacements($line, array $replace)
{
if (empty($replace)) return $line;
$shouldReplace = [];
foreach ($replace as $key => $value) {
$shouldReplace[':'.Str::ucfirst($key)] = Str::ucfirst($value);
$shouldReplace[':'.Str::upper($key)] = Str::upper($value);
$shouldReplace[':'.$key] = $value;
}
return strtr($line, $shouldReplace);
}
and then replace return $search with trans_replacements($search, $replace) and return $fallback with trans_replacements($fallback, $replace)
(Optional) Countable feature
for Countable feature (ex: 'an apple|many apples'), is the same process, just add this helper:
use Illuminate\Support\Facades\App;
function trans_choice($key, $number, array $replace = [], $locale = null)
{
// Get message
$message = __($key, $replace, $locale);
// If the given "number" is actually an array or countable we will simply count the
// number of elements in an instance.
if (is_array($number) || $number instanceof Countable)
$number = count($number);
$replace['count'] = $number;
return trans_replacements(
trans()->getSelector()->choose($message, $number, $locale = App::getLocale()),
$replace
);
}
Bootstrap Helpers File
here is the file, just in case: bendeckdavid/laravel_locale_nested_json
Laravel not supporting this by default is annoying.
However, you can use this function I made:
function ___($path) {
$properties = explode(".", $path);
$base = __($properties[0]);
unset($properties[0]);
foreach($properties as $property) {
// Allows specification of indexes
if(is_numeric($property)) {
$property = intval($property);
}
// If the key has not been found, return the initial parameter like __()
try {
$base = $base[$property];
} catch (\Throwable $th) {
return $path;
}
}
return $base;
}
If you are someone like me stumbling upon here wanting to use a file structure like below without the need to specify keys for each string when using php language files.
-app
-lang
--fr
---Headers.json
A little modification to David G's answer above,
<?php
use Illuminate\Support\Arr;
function ___($path = null, $replace = [], $locale = null)
{
// Default behavior
if (is_null($path)) return $path;
if(!strrpos($path, '.')) {
return $path;
}
$properties = explode(".", $path);
$currentLocale = app()->getLocale();
// If the file/folder doesn't exist
// return the last part of the dot notation
$translated_string = substr($path, strrpos($path, '.') + 1);
if(is_dir(lang_path($currentLocale))) {
if (is_file(lang_path($currentLocale.'\\'.$properties[0].'.json'))) {
$contents = json_decode(file_get_contents(lang_path($currentLocale.'\\'.$properties[0].'.json')), true);
// If no value exists for the key, the key is itself returned
$translated_string = Arr::get($contents, $properties[1], $properties[1]);
}
}
return $translated_string;
}
As of now this doesn't work for files under subdirectories under the locale folder. I am sure, the above code can be optimized, but this should give you an idea.
Also, this function uses triple-underscore {{___()}} instead of the regular double-underscore {{__()}} to avoid conflicts.
Works for,
{{___('Messages.Welcome') }} // lang/(locale)/Messages.json
{{___('Welcome')}} // lang/(locale).json
Assuming your json is stored in $json, you want to parse it into array by using json_decode
$data = json_decode($json, TRUE);
You can access it by:
<label for="email">
{{ $data['login']['emailPlaceholder'] }}
</label>

Fatal error: Call to undefined method Action::execute() /home/public_html/system/engine/event.php on line 62

Hi tried refreshing the modification cache cache in opencart and since then i am getting a blank page in front end with this error message.
public function trigger($event, array $args = array()) {
foreach ($this->data as $value) {
if (preg_match('/^' . str_replace(array('\*', '\?'), array('.*', '.'), preg_quote($value['trigger'], '/')) . '/', $event)) {
$result = $value['action']->execute($this->registry, $args);
if (!is_null($result) && !($result instanceof Exception)) {
return $result;
}
}
}
}
Thanks,
It seems your have an OC version 3.0.2.x or above.
In your $this->data of the Event Class, you have an event registered that is missing an action parameter.
$this->data[] = array(
'trigger' => $trigger,
'action' => $action, // <-- this must be an Action Object with a method execute()
'priority' => $priority
);
All events are registered via the register() method which explicitly requests that an Action object is being passed as a parameter.
Since the error is pointing to "Call to undefined method Action::execute()", I can assume, you have an issue with the action class.
Most likely you need to check the Modifications of the system/engine/action.php file in your system/storage/modifications.
It could be that the method execute() is either missing or somehow corrupt.
Debug
try to var_dump the $value to see what is there:
public function trigger($event, array $args = array()) {
foreach ($this->data as $value) {
//log out the $value before the error to see if the Action object is actually there and see what trigger causes this.
var_dump($value);
if (preg_match('/^' . str_replace(array('\*', '\?'), array('.*', '.'), preg_quote($value['trigger'], '/')) . '/', $event)) {
$result = $value['action']->execute($this->registry, $args);
if (!is_null($result) && !($result instanceof Exception)) {
return $result;
}
}
}
}
Hope this helps

I refreshed the cache in my opencart website and now the website is not loading? [duplicate]

Hi tried refreshing the modification cache cache in opencart and since then i am getting a blank page in front end with this error message.
public function trigger($event, array $args = array()) {
foreach ($this->data as $value) {
if (preg_match('/^' . str_replace(array('\*', '\?'), array('.*', '.'), preg_quote($value['trigger'], '/')) . '/', $event)) {
$result = $value['action']->execute($this->registry, $args);
if (!is_null($result) && !($result instanceof Exception)) {
return $result;
}
}
}
}
Thanks,
It seems your have an OC version 3.0.2.x or above.
In your $this->data of the Event Class, you have an event registered that is missing an action parameter.
$this->data[] = array(
'trigger' => $trigger,
'action' => $action, // <-- this must be an Action Object with a method execute()
'priority' => $priority
);
All events are registered via the register() method which explicitly requests that an Action object is being passed as a parameter.
Since the error is pointing to "Call to undefined method Action::execute()", I can assume, you have an issue with the action class.
Most likely you need to check the Modifications of the system/engine/action.php file in your system/storage/modifications.
It could be that the method execute() is either missing or somehow corrupt.
Debug
try to var_dump the $value to see what is there:
public function trigger($event, array $args = array()) {
foreach ($this->data as $value) {
//log out the $value before the error to see if the Action object is actually there and see what trigger causes this.
var_dump($value);
if (preg_match('/^' . str_replace(array('\*', '\?'), array('.*', '.'), preg_quote($value['trigger'], '/')) . '/', $event)) {
$result = $value['action']->execute($this->registry, $args);
if (!is_null($result) && !($result instanceof Exception)) {
return $result;
}
}
}
}
Hope this helps

Twig PHP Pass existing Array to Twig Filter

I'm trying to implement my custom Translation Filter in twig. All translations are stored in csv's. Per template we have a csv that contains the data.
Now for some reason the function within the filter isn't possible to access the $TranslationText array.
What should I change to make the filter working?
Notice: Undefined variable: TranslationText in /public_html/public/index.php on line 103
Translations are requested by {{ 'Whatever'|t}}
if (file_exists("../application/languages/nl/".$RenderTemplate.".csv") != FALSE) {
$handle = file_get_contents("../application/languages/nl/".$RenderTemplate.".csv");
$handle_row = explode("\n", $handle);
foreach ($handle_row as $key => $val) {
$row_array = explode('|', $val);
foreach ($row_array as $key => $val) {
$row_array[$key] = trim(str_replace('"', '', $val));
}
$TranslationText[] = $row_array;
}
}
require_once '../library/Twig/Autoloader.php';
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem('../application/views/');
//Add Translation Filter
$filter = new Twig_SimpleFilter('t', function ($string) {
foreach($TranslationText AS $key => $value)//line 103
{
if($TranslationText[$key][0] == $string)
{
$Found = TRUE;
$TranslatedText = $TranslationText[$key][1];
}
}
if($Found == TRUE)
{
return $TranslatedText;
}
else
{
return $string;
}
});
$twig = new Twig_Environment($loader, array(
'cache' => '../tmp/cache/', 'auto_reload' => TRUE, 'debug' => TRUE
));
//REMOVE auto_reload and DEBUG if live!
$twig->addFilter($filter);
echo $twig->render($RenderTemplate.".html", $TotalArray);
All I can say is you get the error because of the following:
$filter = new Twig_SimpleFilter('t', function ($string) {
foreach($TranslationText AS $key => $value)//line 103
//... other code lines follow
});
You didn't use $translationText. Consider this code:
$filter = new Twig_SimpleFilter('t', function ($string) use ($TranslationText) {
foreach($TranslationText AS $key => $value)//line 103
//... other code lines follow
});
Please note that if your csv file doesn't exist or cannot be read, you will still get the same error, because you do not declare this variable outside your file_exists condition.
NB: I cannot guarantee that this is the only problem in your code. It's just a solution for your particular problem.
P.S. In general, your code looks messy. Consider using OOP for such things. Also, pay attention to the standards you use: some variables are named using underscores, others are named using CamelCase.

find recursive specific file

I'm trying to find all the files that called "testunit.php".
In addition i want to cut the first 23 chars of the string.
I tried this but this is not working.I get all the files.
$it = new RecursiveDirectoryIterator($parent);
$display = Array ( 'testunit.php');
foreach (new RecursiveIteratorIterator($it) as $file=>$cur) {
{
if ( In_Array ( $cur, $display ) == true )
$file = substr($cur, 23)
fwrite($fh,"<file>$file</file>");
}
Thank you!
see if glob helps you
Try
class TestUnitIterator extends FilterIterator
{
public function accept()
{
return (FALSE !== strpos(
$this->getInnerIterator()->current(),
'testunit.php'
));
}
public function current()
{
return sprintf(
'<file>%s</file>',
substr($this->getInnerIterator()->current(), 23)
);
}
}
Usage (codepad (abridged example)):
$iterator = new TestUnitIterator(
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
'/path/to/iterate/over',
FilesystemIterator::CURRENT_AS_PATHNAME
)
)
);
foreach ($iterator as $file) {
echo $file, PHP_EOL;
}
Disclaimer: I wasn't in the mood to mock the filesystem or setup the required test files, so the above might need a little tweaking to work with the filesystem. I only tested with an ArrayIterator but there shouldn't be much to do if the above produces errors.

Categories