Is it possible for a twig function to return a twig template?
For example
class ToTimeExtension extends \Twig_Extension {
public function getFunctions() {
return array(
'totime' => new \Twig_Function_Method($this, 'toTime')
);
}
public function toTime ($string) {
$time = strtotime($string);
return {"time.html.twig", $time};
//return a twig template and pass $time variable
}
}
time.html.twig
<h1>{{time}}</h1>
Usage
{{ totime('now') }}
You can access the Twig environment if you set the proper options. Then you can render another template inside the method.
class ToTimeExtension extends \Twig_Extension {
public function getFunctions() {
return array(
'totime' => new \Twig_Function_Method($this, 'toTime', ['needs_environment' => true,])
);
}
public function toTime (Twig_Environment $twig, $string) {
return $twig->render('time.html.twig', [ 'time' => strtotime($string),]);
}
}
Related
I created custom actions for rest api in yii2
my codes are:
namespace app\controllers;
use yii\rest\ActiveController;
use yii\web\Response;
use Yii;
class RsController extends ActiveController{
public $modelClass='app\models\Mymodel';
/*some another actions*/
public function actionOne($id){
return \app\models\Anothermodel::findAll(['my_id'=>$id]);
}
public function actionTwo($id){
return \app\models\Anothermodel::findAll(['my_name'=>'xxxx']);
}
}
I know we can override fields function in model to get special fields but
now I wanted to get different fields for actionOne and actionTwo (of a model)
How can I override fields function in Anothermodel for this purpose?
I found my answer from here
I create a component like this
<?php
namespace app\components;
class Serializer extends \yii\rest\Serializer {
public $defaultFields;
public $defaultExpand;
public function init() {
parent::init();
$this->defaultFields = !is_null($this->defaultFields) ? implode(",", $this->defaultFields) : $this->defaultFields;
$this->defaultExpand = !is_null($this->defaultExpand) ? implode(",", $this->defaultExpand) : $this->defaultExpand;
}
protected function getRequestedFields() {
$fields = is_null($this->request->get($this->fieldsParam)) ? $this->defaultFields : $this->request->get($this->fieldsParam);
$expand = is_null($this->request->get($this->expandParam)) ? $this->defaultExpand : $this->request->get($this->expandParam);
return [
preg_split('/\s*,\s*/', $fields, -1, PREG_SPLIT_NO_EMPTY),
preg_split('/\s*,\s*/', $expand, -1, PREG_SPLIT_NO_EMPTY),
];
}
}
and then in my controllers action set my fields
like this.
public function actionOne($id){
$this->serializer['defaultFields'] = ["field1",
"field2"];
return new \yii\data\ActiveDataProvider([
'query' => \app\models\Anothermodel::find()->where(['my_id'=>$id]),
]);
}
public function actionTwo($id){
$this->serializer['defaultFields'] = ["field1",
"field2","field3"];
return new \yii\data\ActiveDataProvider([
'query' => \app\models\Anothermodel::find()->where(['my_id'=>$id]),
]);
}
I suggest to use events
public function actionPublic()
{
\yii\base\Event::on(Thing::class, Thing::EVENT_AFTER_FIND, function ($event) {
$event->sender->scenario = Thing::SCENARIO_SEARCH_PUBLIC;
});
return new ActiveDataProvider([
'query' => Thing::find(),
]);
}
public function actionPrivate()
{
\yii\base\Event::on(Thing::class, Thing::EVENT_AFTER_FIND, function ($event) {
$event->sender->scenario = Thing::SCENARIO_SEARCH_PRIVATE;
});
return new ActiveDataProvider([
'query' => Thing::find(),
]);
}
and inside of ActiveRecord (Thing in my case) check the scenario in fields() method
public function fields()
{
$fields = parent::fields();
if ($this->scenario === self::SCENARIO_SEARCH_PUBLIC) {
unset($fields['field1'], $fields['field2'], $fields['field3'], $fields['field4']);
}
return $fields;
}
check my answer in gihub
I am trying to render a template with my controller but does not work
it show me this error :
LogicException: The controller must return a response (Hello Bob! given). in Symfony\Component\HttpKernel\HttpKernel->handleRaw() (line 163 of core/vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php).
My function :
public function helloAction($name) {
$twigFilePath = drupal_get_path('module', 'acme') . '/templates/hello.html.twig';
$template = $this->twig->loadTemplate($twigFilePath);
return $template->render(array('name' => $name));
}
In Drupal 8 you either return a Response object or a render array from a controller. So you have two options:
1) Place the rendered template into a Response object:
public function helloAction($name) {
$twigFilePath = drupal_get_path('module', 'acme') . '/templates/hello.html.twig';
$template = $this->twig->loadTemplate($twigFilePath);
$markup = $template->render(array('name' => $name));
return new Response($markup);
}
2) Place the rendered template into a render array:
public function helloAction($name) {
$twigFilePath = drupal_get_path('module', 'acme') . '/templates/hello.html.twig';
$template = $this->twig->loadTemplate($twigFilePath);
$markup = $template->render(array('name' => $name));
return array(
'#markup' => $markup,
);
}
Also you can Use the second option without custom template, doing this:
public function helloAction($name) {
$markup = "<p> Without custom Template</p>";
return array(
'#markup' => $markup,
);
}
class ClientController extends ControllerBase implements ContainerInjectionInterface ,ContainerAwareInterface {
protected $twig ;
public function __construct(\Twig_Environment $twig)
{
$this->twig = $twig ;
}
public function index()
{
$twigFilePath = drupal_get_path('module', 'client') . '/templates/index.html.twig';
$template = $this->twig->loadTemplate($twigFilePath);
$user = ['user' => 'name'] ; // as example
$markup = [
'#markup' => $template->render( ['users' => $users ,'kit_form' => $output] ),
'#attached' => ['library' => ['client/index.custom']] ,
];
return $markup;
}
// this is called first then call constructor
public static function create(ContainerInterface $container)
{
return new static(
$container->get('twig') ,
);
}
}
this full example to render twig by dependency injection from controller
I want to redeclare and add some methods to helper Tag.
class MyTags extends \Phalcon\Tag
{
public static function mytag($params)
{
<...>
}
}
in services.php
$di->set('tag', function() {
return new MyTags();
};
But it works only for PHP engine, not for Volt.
{{ mytag() }}
returned
Undefined function 'mytag'
First of all: don't use tag as your service name because it's already used by Phalcon's Tag object. Secondly you can use static methods from class.
Below is a working example for myTag using config from my app with changed names for your example.
$di->set(
'view',
function () use ($config) {
$view = new View();
$view->setViewsDir($config->application->viewsDir);
$view->registerEngines(
array(
'.volt' => function ($view, $di) use ($config) {
$volt = new VoltEngine($view, $di);
$volt->setOptions(
array(
'compiledPath' => $config->application->cacheDir,
'compiledSeparator' => '_',
'compileAlways' => false
)
);
$compiler = $volt->getCompiler();
// add a function
$compiler->addFunction(
'myTag',
function ($resolvedArgs, $exprArgs) {
return 'MyTags::mytag(' . $resolvedArgs . ')';
}
);
// or filter
$compiler->addFilter(
'myFilter',
function ($resolvedArgs, $exprArgs) {
return 'MyTags::mytag(' . $resolvedArgs . ')';
}
);
return $volt;
}
)
);
return $view;
},
true
);
Then you can use your myTag() function in volt views.
But if you want to use object then don't use static methods:
class MyTags extends \Phalcon\Tag
{
/**
* Look no static keyword here
*/
public function mytag($params)
{
<...>
}
}
in services use object:
$di->set('mahTag', function() {
return new MyTags();
};
and then in in volt:
{{ mahTag.mytag() }}
Having the following class that is extended by other controllers
class Admin_Controller extends Base_Controller
{
static $admin_layout = 'admin.layouts.default';
public function __construct()
{
parent::__construct();
$role_object = User::find(Auth::user()->id)->roles()->get();
$role = $role_object[0]->attributes['name'];
such as:
class Admin_Draws_Controller extends Admin_Controller
{
public $restful = true;
public function __construct()
{
$this->layout = parent::$admin_layout;
parent::__construct();
}
public function get_index()
{
$view = View::make('admin.templates.draws');
$this->layout->content = $view;
}
}
How can I send the $role variable to admin.layouts.default so I can have it when ever the view is loaded?
The point of "global" $role variable is to avoid to have to call it in all of my View::make() like the following:
$view = View::make('admin.templates.articles',
array(
'fields' => $fields,
'data' => $results,
'links' => $links,
'role' => 'role here'. // I don't want to add this where ever I call the View::make
)
);
$this->layout->content = $view;
and just do an echo $role like, in my header.blade.php
I ended up doing the following, which works.
Controller
// Example of variable to set
$this->layout->body_class = 'user-register';
$view = View::make('modules.user.register', array(
'success' => true,
));
$this->layout->content = $view;
My default.layout.php view
<body class="<?php echo isset($body_class) ? $body_class : '' ;?>">
#include('partials.header')
{{ $content }}
#include('partials.footer')
The variable, can be easily used in any other context within the view.
i got such form
class CC extends CFormModel
{
public $static_field;
public $fields;
public function rules()
{
return array(
array('static_field, testF', 'required')
);
}
public function getForm()
{
return new CForm(array(
'showErrorSummary'=>true,
'elements'=>array(
'static_field'=>array(),
'testF'=>array(),
),
'buttons'=>array(
'submit'=>array(
'type'=>'submit',
'label'=>'Next'
)
)
), $this);
}
public function attributeLabels()
{
return array(
'static_field' => 'static_field'
);
}
public function __get($name)
{
if (isset($this->fields[$name]))
return $this->fields[$name];
else
return '';
}
public function __set($name, $value)
{
$this->fields[$name] = $value;
}
}
i want to add dynamical field testF
i try to use __get\__set and array for values, but nothing work. any ideas?
If by dynamic you mean not required, you can add it as a property just as you have done with static_field. All attributes, or fields, are encapsulated member data of your FormModel class. So, if you wanted to add your dynamic_field attribute, you could add it in this manner:
class CC extends CFormModel
{
public $static_field;
public $dynamic_field;
public function rules()
{
return array(
array('static_field','required'),
array('dynamic_field','safe'),
);
}
}
Also, you're not exactly following the dominant usage pattern for this type of class. If I were you, I would suggest creating some CRUD through gii and examining the usage patterns for models and forms.