Yii2 render database content - yii2

There is a textarea where user can edit some templates and can use variables like:
{{model.user.name}}
Application need to replace this variables with data and display HTML output.
We can write a small function that will replace variables from template with data but we need to use a template engine like Twig or Smarty.
https://github.com/yiisoft/yii2-twig
https://github.com/yiisoft/yii2-smarty
Now we can use ViewRenderer from Smarty or Twig.
$render = new ViewRenderer();
$content = $render->render($this->view,'template.twig',[
'model' => $model,
]);
But I see this error:
Unable to find template "template.twig" (looked into: .).
How can I use Smarty or Twig to render a template with the content from database in Yii2 ?

I found Mustache ( https://github.com/bobthecow/mustache.php ) and I'm using like this:
$m = new \Mustache_Engine();
echo $m->render("Hello {{model.client.firma}}",['model' => $model]);

You don't create a renderer manually, you configure your application components, like this:
[
'components' => [
'view' => [
'class' => 'yii\web\View',
'renderers' => [
'twig' => [
'class' => 'yii\twig\ViewRenderer',
'cachePath' => '#runtime/Twig/cache',
// Array of twig options:
'options' => [
'auto_reload' => true,
],
'globals' => ['html' => '\yii\helpers\Html'],
'uses' => ['yii\bootstrap'],
],
// ...
],
],
],
]
You are telling Yii that there is a renderer to handle templates with the .twig extension.
Then, all you need to do is add the .twigextension when calling render in your controller actions:
public function actionIndex()
{
return $this->render('index.twig');
Then put your twig templates in the view folders where the views normally go.
Read the documentation for the twig extension: Twig Extension for Yii 2
If you want to only use twig templates, you can avoid specifying the extension (.twig) if you set the default extension:
'components' => [
'view' => [
'defaultExtension' => 'twig',

You should create a twig component which will wrap around Twig_Environment. You can add yii\twig\Extension extension if you need. Then you should use it like this:
$renderedTemplate = Yii::$app->twig->render($template, $context);
If you really need to render a template from a string variable you may implement your own Twig_LoaderInterface. There is a Twig_Loader_String, but it's deprecated and you should not use it.

Related

Can I display pictures outside backend web folder in yii2?

I have a little problem. I can’t view images outside the backend web folder.
Aliases in common\config\main:
'aliases' => [
'#upload' => dirname(dirname(__DIR__)).'/upload',
],
View Dataprovider:
[
'format' => 'raw',
'label' => 'Immagine',
'value' => function ($data) {
return Html::img(Yii::getAlias('#upload') . $data->codice_prodotto . '/' . $data->immagine, ['width' => '70px', 'class' => 'img-thumbnail']);
},
],
Can I resolve? Thanks.
If your file is not accessible for http server, so you can't directly download it.
You can:
Move uploads directory to directory accessible for the http-server
Create action that will read the file from private directory and stream it to the browser (you can use yii\web\Response::sendFile() function for that)
Streaming file to the browser
Please read this official docs article to understand this deeply: https://www.yiiframework.com/doc/api/2.0/yii-web-response#sendFile()-detail
Action code example for your case: *
public function actionFile($filename)
{
$storagePath = Yii::getAlias('#upload');
// check filename for allowed chars (do not allow ../ to avoid security issue: downloading arbitrary files)
if (!preg_match('/^[a-z0-9]+\.[a-z0-9]+$/i', $filename) || !is_file("$storagePath/$filename")) {
throw new \yii\web\NotFoundHttpException('The file does not exists.');
}
return Yii::$app->response->sendFile("$storagePath/$filename", $filename);
}
And view Dataprovider configuration: *
[
'format' => 'raw',
'label' => 'Immagine',
'value' => function ($data) {
return Html::img(Url::to(['/path/to-streaming-action/file', 'filename' => $data->codice_prodotto . '/' . $data->immagine]), ['width' => '70px', 'class' => 'img-thumbnail']);
},
],
* Notice that this code is not ready to copy-paste, please read it carefully and try to understand the principle before implement it in your code.

Yii2: Override 3rd party mail views

How do we override mail view files of a 3rd party module/component?
Let's assume a module is using the following code to send an email:
Yii::$app->mailer->compose([
'html' => '#myvendor/mymodule/mail/email-html',
'text' => '#myvendor/mymodule/mail/email-text',
])
->setTo([$email => $name])
->setSubject('Hi');
->send();
How would we override these individual email views #myvendor/mymodule/mail/email-html and #myvendor/mymodule/mail/email-text?
You can override these two aliases in your config:
'aliases' => [
'#myvendor/mymodule/mail/email-html' => '#app/views/mail/email-html',
'#myvendor/mymodule/mail/email-text' => '#app/views/mail/email-text',
],
Configure and rewrite the $viewPath property in the mail file in the module.
example:
public $viewPath = '#myvendor/mymodule/mail';
First, create new html and text files. Create both files.
Create both files.
mail/newHTML
mail/trxt/NewTEXT
$mailer = Yii::$app->mailer;
$mailer->viewPath = $this->viewPath;
$mailer->getView()->theme = Yii::$app->view->theme;
return $mailer->compose(['html' => $view, 'text' => 'text/' . $view], $params)
->setTo($to)
->setFrom($this->sender)
->setSubject($subject)
->send();
If you want to change the path for only one:
Use before code:
Yii :: $ app-> mailer-> viewPath = '# myvendor / newPath';
Yii::$app->mailer->compose([ #code...
  If the VIEW file: Only need to change the name for HTML and TEXT file, (both)
Update:
It can be override or through a component and ...
//new file: path\widgets\Mailer.php
namespace path\widgets;
use yourpath\Mailer as DefaultMailer; //path:mymodule/mail
class Mailer extends DefaultMailer{
public $viewPath = '#myvendor/mymodule/mail';
public function changeviewPath($_path){
$this->viewPath; = $_path;
}
}
// for use. Changes
use path\widgets\Maile; // New path
// Use before the usual code
$mailer->changeviewPath('newpath\mail');
To change the address of the files in the component. Depending on your email module, it varies
example:
'modules' => [
'myMudul' => [
'class' => 'PathModule\Module',
'mailer' => [
#code ..
],
],
...

Yii2 internationalizating slug and controller

I'm making a yii2 site in 2 languages (for now) using yii's native i18n module, but how can I add multilanguage support for the action URLs?
For instance one of my actions is category/slug and in English, it will show as
http://example.com/category/chair
but in spanish it has to be shown as
http://example.com/categoria/silla
and so on for other languages shown in the future
right now im manually adding my routes like:
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'rules' => [
'<alias:\w+>' => 'site/<alias>',
'marca/<slug>' => 'site/brand',
'categoria/<slug>' => 'site/category',
'brand/<slug>' => 'site/brand',
'category/<slug>' => 'site/category',
],
],
Do i need to manually route every action to its correct controller or is it possible to add a more automated form using yii::t() function?
you will need to write your own UrlRule class, implementing yii\web\UrlRuleInterface and configure your UrlManager.
read more here.
basically it is about "translating" a given request like '/categoria/silla' to your internal url ['site/category', 'slug' => $slug, 'lang' => $lang] in your UrlRule's 'parseRequest' method. 'createUrl' is the other way round.

Pass dynamic params in the ajax call of yii2-grid EditableColum widget

the \kartik\grid\EditableColumn widget has a parameter called ajaxSettings where you may override the parameters passed with the ajax request to the server. What i want to do is to dynamically pass the selected rows ids together with the value coming from the popover to the server. I manage to do that passing static parameter coming from a php array in compile time like so
Editable::widget(['name' => 'publishDate', 'ajaxSettings' => ['ids' => [1,2,3]]])
but It seems that i cannot use a jquery selector there to grab the ids of the selected columns like so
Editable::widget([
'name' => 'publishDate',
'ajaxSettings' => [
'ids' => '$("#books-grid").yiiGridView("getSelectedRows")'
]
])
Maybe you want to try creating a variable outside the Editable::widget([ like this:
var arrayIds = $("#books-grid").yiiGridView("getSelectedRows");
And then assign it to the widget:
Editable::widget([
'name' => 'publishDate',
'ajaxSettings' => [
'ids' => arrayIds
]
])
Hope this helps,
Leo.

How to customize vendor view files?

In yii2 how do I customize vendor view files without modifying the original view files?
I'm using dektrium yii2-user and would like to make a few changes to the login page.
You can assign your view path for dektrium yii2-user in this way (assume #app your app alias) :
'components' => [
'view' => [
'theme' => [
'pathMap' => [
'#dektrium/user/views' => '#app/views/your_dir_views' // mapping for override the views dektrium with your views
],
],
.....
],