drupal 8 error to render template twig with controller - php

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

Related

Problems with class extending UserDefinedForm in Silverstripe 4

I've been stuck on this for a while now and I can't see where I'm going wrong.
I've made a class that extends the UserDefinedForm so I can have a page that also has a UserDefinedForm on it. The form loads on the page, but it isn't as easy as just saying $Form on the template file, instead I have to make and call the following function:
public function getUserForm() {
$page = UserDefinedForm::get()->byID($this->ID);
$controller = UserDefinedFormController::create($page);
return $controller->Form();
}
So when I call that function on the template it displays the form, however, none of my field rules are applied and when submitting the form it takes me to a blank page with "/finished" appended to the URL: "https://example.com/finished".
Can someone please help me out here, would be much appreciated.
I will put my code down below.
Class extending the UserDefinedForm:
<?php
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\FileHandleField;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Assets\Image;
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
use SilverStripe\Forms\DropdownField;
use SilverStripe\UserForms\Model\UserDefinedForm;
use SilverStripe\UserForms\Control\UserDefinedFormController;
use SilverStripe\UserForms\Model\EditableCustomRule;
class Package extends UserDefinedForm {
private static $db = [
'Date' => 'Text',
'Location' => 'Text',
'Availability' => 'Enum(array("Available","Hidden","Sold Out"))',
'Extras' => 'HTMLText',
'NeedTo' => 'HTMLText',
'Price' => 'Text'
];
private static $has_one =[
'Photo' => Image::class,
];
private static $has_many =[
'FileAttachments' => 'PackageFile'
];
private static $many_many = [
'SacredTexts' => 'ImportantText'
];
public function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Main', Injector::inst()->create(FileHandleField::class, 'Photo'));
$fields->addFieldToTab('Root.Main', new TextField('Date', 'Date'));
$fields->addFieldToTab('Root.Main', new TextField('Location', 'Location'));
$fields->addFieldToTab('Root.Main', new TextField('Price', 'Price'));
$fields->addFieldToTab('Root.Main', new HTMLEditorField('Extras', 'Extras'));
$fields->addFieldToTab('Root.Main', new HTMLEditorField('NeedTo', 'What you need to know'));
$fields->addFieldToTab('Root.Main', new DropdownField('Availability', 'Availability', singleton('Package')->dbObject('Availability')->enumValues()));
$fields->addFieldToTab('Root.Main', new GridField('SacredTexts', 'Important Texts', $this->SacredTexts(), GridFieldConfig_RecordEditor::create()),'Date');
$fields->addFieldToTab('Root.Main', new GridField('FileAttachments', 'File Attachments', $this->FileAttachments(), GridFieldConfig_RecordEditor::create()),'Content');
return $fields;
}
/* Look up SS4 docs on SS Sitetree URL parse function and what needs to be namespaced */
function onBeforeWrite () {
parent::onBeforeWrite ();
if($this->Name){
$this->Slug = str_replace(' ','-', strtolower($this->Name));;
}
}
public function ShortContent( $word_limit = 20 ) {
$NoHTML = htmlspecialchars_decode(strip_tags($this->NewsText),ENT_QUOTES);
$words = explode( ' ', $NoHTML );
return implode( ' ', array_slice( $words, 0, $word_limit ) );
}
public function ParentEvent(){
return $this->Parent()->URLSegment;
}
public function getUserForm() {
$page = UserDefinedForm::get()->byID($this->ID);
$controller = UserDefinedFormController::create($page);
return $controller->Form();
}
public function hasUserForm() {
if (count($this->getUserForm()->Fields()) > 1) {
return $this->getUserForm();
}
}
}
I figured it out.
Turns out the class controller I was extending to override wasn't working, instead it was referring to the UserDefinedFormController. I fixed it by copying the following function from the UserDefinedForm class:
public function getControllerName()
{
return UserDefinedFormController::class;
}
and copying it into my extended class from UserDefinedForm and renaming the return statement to the name of the class, for example:
public function getControllerName()
{
return PackageController::class;
}

Twig template engine shows odd information

I am first day user of Twig, and I have some strange behaviour of engine.
I push some information to my view:
class MainController extends Controller {
public function actionIndex()
{
$template = self::$twig->loadTemplate('index.php');
$title = 'CRUD интерфейс';
$projects = MainList::showAll();
$workers = CompanyWorker::showAll();
$roles = Role::showAll();
$namesOfProjects = Project::showAll();
echo $template->render(array(
'title' => $title,
'projects' => $projects,
'workers' => $workers,
'roles' => $roles,
'namesOfProjects' => $namesOfProjects
));
}
}
In the end I have a good result but in the end of HTML file twig shows me my controller object. Why it's happened?
It's my Twig initialisation:
abstract class Controller {
public $loader;
static $twig;
function __construct()
{
$this->loader = new Twig_Loader_Filesystem('views');
//$twig = new Twig_Environment($loader, array('cache' => 'cache'));
self::$twig = new Twig_Environment($this->loader);
}
I'm were blind 8[. I really missed 'print_r' func.

Twig function return a template

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),]);
}
}

Default scope in Yii 1.1

AR model Player:
public function scopes()
{
return array(
'proleague' => array(
'condition' => 'mode = "proleague"',
),
'main' => array(
'condition' => 'mode = "main"',
),
);
}
Using model Player:
Player::model()->
proleague()->
with('startposition')->
findAllByAttributes(... here some condition ...);
^^^ That's all ok. Scope-condition will be executed. But...
In my project I have many places where any scope for Player model doesn't specified and in this cases I need use this scope-condition as default:
'main' => array(
'condition' => 'mode = "main"',
)
If I add defaultScope() method to Player model like this
public function defaultScope()
{
return array(
'condition' => 'mode = "main"',
);
}
the next code
Player::model()->
proleague()->
with('startposition')->
findAllByAttributes(... here some condition ...);
won't run correct. I won't get mode = "proleague" condition, becouse I'll use defaultScope() with mode = "main".
Any suggestions? How can I resolve the problem?
You should just use the resetScope(true) method. It "removes" the defaultScope filter.
$model = Player::model()->resetScope(true)->proleague();
create a new Class for this.
<?php
## e.g. protected/models/
class MyCoreAR extends CActiveRecord
{
/**
* Switch off the default scope
*/
private $_defaultScopeDisabled = false; // Flag - whether defaultScope is disabled or not
public function setDefaultScopeDisabled($bool)
{
$this->_defaultScopeDisabled = $bool;
}
public function getDefaultScopeDisabled()
{
return $this->_defaultScopeDisabled;
}
public function noScope()
{
$obj = clone $this;
$obj->setDefaultScopeDisabled(true);
return $obj;
}
// see http://www.yiiframework.com/wiki/462/yii-for-beginners-2/#hh16
public function resetScope($bool = true)
{
$this->setDefaultScopeDisabled(true);
return parent::resetScope($bool);
}
public function defaultScope()
{
if(!$this->getDefaultScopeDisabled()) {
return array(
'condition' => 'mode = "main"',
);
} else {
return array();
}
}
}
In your code:
// no default scope
$model = Player::model()->noScope()->proleague();
// with default scope
$model = Player::model()->proleague();

How can I set own Tag class in Volt (Phalcon)

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() }}

Categories