How to load/execute a view template from a string in CakePHP - cakephp

I've developed a CakePHP plugin that allows the site administrator to define custom reports as a list of SQL queries that are executed and the results displayed by a .ctp template.
Now I need to allow the administrator to edit the template, stored in the DB together with the report.
Therefore I need to render a template that is inside a string and not in a .ctp file and I could not find anything in the core that helps.
I considered initially the approach to write the templates in .ctp files and load them from there, but I suspect this solution is rigged with flaws re: the location of the files and related permissions.
A better solution seems to override the View class and add a method to do this.
Can anyone suggest a better approach ?
P.S. Security is not a concern here, since the administrator is basically a developer without access to the code.

In CakePHP 2.0:
The View::render() method imports the template file using
include
The include statement includes and evaluates the specified file.
The evaluated template is immediately executed in whatever scope it was included. To duplicate this functionality, you would need to use
eval()
Caution: The eval() language construct is very dangerous because it
allows execution of arbitrary PHP code. Its use thus is discouraged.
If you have carefully verified that there is no other option than to
use this construct, pay special attention not to pass any user
provided data into it without properly validating it beforehand.
(This warning is speaking to you, specifically)
...if you wish to continue... Here is a basic example of how you might achieve this:
$name = 'world';
$template = 'Hello <?php echo $name ?>... <br />';
echo $template;
// Output: Hello ...
eval(' ?>' . $template . '<?php ');
// Output: Hello world...
Which is (almost) exactly the same as:
$name = 'world';
$template = 'Hello <?php echo $name ?>... <br />';
file_put_contents('path/to/template.php', $template);
include 'path/to/template.php';
Except people won't yell at you for using eval()
In your CakePHP application:
app/View/EvaluatorView.php
class EvaluatorView extends View
{
public function renderRaw($template, $data = [])
{
if (empty($data)) {
$data = $this->viewVars;
}
extract($data, EXTR_SKIP);
ob_start();
eval(' ?>' . $template . '<?php ');
$output = ob_get_clean();
return $output;
}
}
app/Controller/ReportsController.php
class ReportsController extends AppController
{
public function report()
{
$this->set('name', 'John Galt');
$this->set('template', 'Who is <?php echo $name; ?>?');
$this->viewClass = 'Evaluator';
}
}
app/View/Reports/report.ctp
// Content ...
$this->renderRaw($template);
Alternatively, you may want to check out existing templating engines like: Mustache, Twig, and Smarty.

Hmmm.. Maybe create a variable that will store the generated code and just 'echo' this variable in ctp file.
I had similar problem (cakephp 3)
Controller method:
public function preview($id = null) {
$this->loadModel('Templates');
$tempate = $this
->Templates
->findById($id)
->first();
if(is_null($template)) {
$this->Flash->error(__('Template not found'));
return $this->redirect($this->referer());
}
$html = $template->html_content;
$this->set(compact('html'));
}
And preview.ctp is just:
<?= $html

Related

Undefined variable in view

I am having an issue setting variables in the controller and showing it at the view.
my codes are as follow:
In my view (pages/anything.ctp):
<?php echo $anything; ?>
In my controller (pagesController.php):
public function anything() {
$a = "asdasdas";
$this->set('anything', $a);
}
I am new to Cake, and I've done quite a number of search in google and stack. Still no luck.
I'd be grateful if anybody could help, or if anyone already asked this question before please provide a link that would be best.
First read the following article Controller actions in CakePHP CookBook
When you use controller methods with requestAction(), you will often want to return data that isn’t a string. If you have controller methods that are used for normal web requests + requestAction, you should check the request type before returning:
class RecipesController extends AppController {
public function popular() {
$popular = $this->Recipe->popular();
if (!empty($this->request->params['requested'])) {
return $popular;
}
$this->set('popular', $popular);
}
}
The above controller action is an example of how a method can be used with requestAction() and normal requests. Returning array data to a non-requestAction request will cause errors and should be avoided. See the section on requestAction() for more tips on using requestAction()
Try this:
public function anything() {
$a = "asdasdas";
$this->set(compact('a'));
}
<?php echo $a; ?>

how to write code inside javascript

I need to make a DOM substitution, something like this:
$("#target").html('<?php echo $html?>');
where the $html variable could be a complex markup
$html = '<div>
<input type="text" name="test" />
</div>';
Of course I need some kind of escaping, or the javascript engine will break for a syntax problem at the first crlf or quote. In rails there's a simple function escape_javascript that makes it very easy. Is there anything similar in cakephp?
I think using
$("#target").html('<?php echo $this->element("element_path"); ?>');
makes more sense. But it depends on what is in your element_path.ctp file.
On the other hand, it's a bit weird to put replacement HTML in like this. Espacially if it's a lott, I would make an ajax call to load the HTML and have a Controller function return the contents of the element.
$("#target").html('Loading...').load('/myController/loadHtml/');
and the myController
function loadHtml(){
$this->layout = false;
}
and the view for the function app/View/my/load_html.ctp:
<?php echo $this->element("element_path"); ?>
you can do this by using requestAction
in your view file add the below code
$html = $this->requestAction('/tests/func_name');
echo $this->Html->scriptBlock('
$("#target").html('. $this->Js->value($html) .');
');
And in your TestsController.
public function func_name() {
$this->layout = 'layout_name'; // The layout you want here for design.
$this->render('/Elements/element_name'); // you can directly render the content of element by writing like this.
}

cakephp disable direct access to a controller

I am new to use cakephp2,
i use element + requestAction to show a news block on some page of my site, like below:
news.ctp
<?php
$news = $this->requestAction('controller'=>'News','action'=>'load');
foreach($news as $itm){
echo $itm['title];
//...
}
NewsController.php
<?php
//...
public function load(){
//...
return $data;
}
It's worked well ,my problem is
how to disable direct access like: http://domain/News/load
and if it is a good way to make a contents block?
thanks!
In your controller you can try like this to prevent direct access.
public function load(){
if (empty($this->request->params['requested'])) {
$this->redirect($this->referer());
}
return $data;
}
If requestAction is used without caching requestAction can lead to poor performance. It is rarely appropriate to use in a controller or model. check here
For more info you can check the documentation here

Trying to write a simple Joomla plugin

Please help, this is my first plugin I'm writing and I'm completely lost. I'm trying to write and update information in a table in a joomla database using my custom giveBadge() function. The functions receives two different variables, the first variable is the $userID and the second one is the digit 300 which I pass at the bottom of the class using giveBadge(300). At the same comparing the $userID in the Joomla database to ensure that the number 300 is given to the current user logged in the Joomla site.
Thanks in advance.
<?php
defined('JPATH_BASE') or die;
class plgUserBadge extends JPlugin
{
public function onUserLogin () {
$user =& JFactory::getUser();
$userID =& user->userID;
return $userID;
}
public function giveBadge ($userID, &$badgeID) {
// Get a db connection.
$db = JFactory::getDbo();
// Create a new query object.
$query = $db->getQuery(true);
// Fields to update.
$fields = array(
'profile_value=\'Updating custom message for user 1001.\'',
'ordering=2');
// Conditions for which records should be updated.
$conditions = array(
'user_id='.$userID,
'profile_key=\'custom.message\'');
$query->update($db->quoteName('#__user_badges'))->set($fields)->where($conditions);
$db->setQuery($query);
try {
$result = $db->query();
} catch (Exception $e) {
// Catch the error.
}es = array(1001, $db->quote('custom.message'), $db->quote('Inserting a record using insert()'), 1);
}
}
giveBadge(300); //attaches to $badgeID
?>
Here is not going well with your code:
You can drop the assign by reference in all your code (&) - you really don't need it, in 99% of the cases.
Use an IDE (for example Eclipse with PDT). At the top of your code you have & user->userID; Any IDE will spot your error and also other things in your code.
Study existing plugins to understand how they work. Here is also the documentation on plugins.
The method onUserLogin() will automatically be called by Joomla when the specific event is triggered (when your plugin is activated). Check with a die("My plugin was called") to see if your plugin is really called
inside onUserLogin() you do all your business logic. You are not supposed to return something, just return true. Right now your method does absolutely nothing. But you can call $this->giveBadge() to move the logic to another method.

What has happened to javascript helper in cakePHP 2?

I have used this item and get this error :
Missing Helper
Error: JavascriptHelper could not be found.
Error: Create the class JavascriptHelper below in file: app/View/Helper/JavascriptHelper.php
<?php
class JavascriptHelper extends AppHelper {
}
Well indeed, this file does not exists, and I tried to use 'Js' in my helper array.
class myClassController expend AppController {
var $helpers = array('Html', 'Js'); // and not 'Javascript');
In the code, the method $this->Javascript->codeBlock is called to add a javascript method (in the middle of the content instead of the header) but there is no $this->Js->codeBlockcodeBlock either.
$output .= $this->Js->codeBlock("datepick('" . $htmlAttributes['id'] . "','01/01/" . $options['minYear'] . "','31/12/" . $options['maxYear'] . "');");
Could you explain me what happened to the old Javascript helper or how to get the code working?
Is there an other helper which could work with CakePHP-2.0?
Cordially,
Have you read the migration guide? If not do that now:
http://book.cakephp.org/2.0/en/appendices/2-0-migration-guide.html#xmlhelper-ajaxhelper-and-javascripthelper-removed
XmlHelper, AjaxHelper and JavascriptHelper removed The AjaxHelper and
JavascriptHelper have been removed as they were deprecated in version
1.3. The XmlHelper was removed, as it was made obsolete and redundant with the improvements to Xml. The Xml class should be used to replace
previous usage of XmlHelper.
The AjaxHelper, and JavascriptHelper are replaced with the JsHelper
and HtmlHelper.
JsHelper JsBaseEngineHelper is now abstract, you will need to
implement all the methods that previously generated errors.
So
$this->Js->codeBlock('...');
is now
$this->Html->codeBlock('...');
HtmlHelper::scriptBlock($code, $options = array())
//Parameters:
$code (string) – The code to go in the script tag.
$options (array) – An array of html attributes.

Resources