CakePHP - render whole page as HTML to attach to email - cakephp

I have successfully created a report accessed at /controller/report
I now want to create a separate controller method to create this report as an HTML file and email it to designated useds. I have done this but have hit one snag. When the HTML file is rendered, it is only the view element from the /report method - the layout (including the CSS) is not rendered.
Here's the basic structure:
public function email_report() {
$render = $this->requestAction('/controller/report');
//$render is then used by fwrite to create a .HTML file, which is then attached to an email
}
public function report() {
//yada yada
//render in report layout rather than default
$this->render('report', 'reports');
}
So the problem is that $render only contains the view stuff, not the stuff from my "reports" layout. What do I need to do to get the layout in my HTML file as well?
I could put all of the HTML in the view but I would like to create other reports using the same layout in future and would like to avoid repetition.

use the following instead. Note the extra array argument passed to the function
bare indicates whether or not to include layout. setting it to 0 i.e false forces it to include layout. Including return sets requested to 1. requested indicates whether request is from requestAction or not.
Visit http://book.cakephp.org/2.0/en/controllers/request-response.html and http://book.cakephp.org/2.0/en/controllers.html for reference
$this->requestAction('/controller/report', array('return', 'bare' =>
0));

Related

Where to put a function to create a pdf

I have an application which deals with projects evolving according to a process defined by a series of status transitions. I have a button to set a project to the next status. The button calls a function in the ProjectsController. This function calls another function in the Project model, where I search for the correct transition, depending on the current status, the user_group and some other parameter, and set the new status. After everything successfully accomplished, I return to the original page with 'return $this->redirect($this->referer());' from the controller.
Some of the transitions have side effects. One is to create a PDF, save it on the server and add a new entry to the 'documents' table referenced to the current project.
Problem: where should I put the function to create the PDF? I would like to put it to the Model. But I need some View Files to first render a html page and then convert it to the PDF. I could put it to the Controller. But then I have a controller function which should not be called directly an doesn't render a view.
The functions all work, but where to put them? Is there another possibility? Would it be possible to use a component?
Implement it as PdfView that will render any (pdf) view for you as Pdf. There is already a plugin that does this, search for CakePdf on Github.
A component is clearly the wrong place. A Pdf is output, so it's a kind of view. Model gets you the data, controller sets it, view renders it.

Concrete5: Take the central part of my single page and have it displayed on the homepage

Within my Concrete5 there's a package that contains many single pages, which actually make the core functionality (community connections).
There's one particular page that contains search functionality. Is there any way to take the central part of that page and somehow display it on the homepage, in a div element or similar?
You can do this with jquery .load()
On the single page, wrap the content you want to import in a div with a unique id.
On the home page, add a div to import the content into
// Get the URL of the page
var url = "relative/path/to/page;
// Load the new page into the temp container
// Replace #wrapper with the selector of the element you want to import
$("#import-content").load(url + " #wrapper");
You should be able to do this by creating a new public function in the single_page's controller that returns whatever you want it to (data that you can then render in HTML, or you could have the controller method itself render an "element" with some data, or just create an HTML string in the controller method itself if you want to totally violate the MVC pattern).
Then you should be able to retrieve that data or markup from your other page like so:
$myController = Loader::controller('/path/to/singlepage'); //<--NOTE this is a C5 URL path (e.g. "slug"), not a server file path!
$myMarkup = $myController->myCustomFunctionIWroteToReturnSomeStuff();
echo $myMarkup;

CakePHP: How to use the same controller function to render 2 pages

I wish to have a page called "index" with a corresponding url "domain/controller/index" and another
page called "admin_index" with a corresponding url "domain/admin/controller/index".
The trick is that i want both pages to use the same view to render and the same function for the logic while on of the page's parameters are a flag indicating to the view from which url the view is rendered.
I need it because currently in my "index" page I have table with data.
The page also has a smart filter for that page which requires a respectful amount of logic in the controller side.
My problem is that currently there is an "Edit" button in each line which I don't want to share to all the users.
Currently I'm using the admin prefix to handle this kind of pages by protecting them by limiting the access from the web-server (Apache in my case).
Any ideas of how to implement this without duplicating the controller function?
Try this (I've tested it on my CakePHP 2.0.x app, but there's nothing in this code that should be 2.0 specific):
//controller
public function index($admin = false) {
$this->set(compact('admin'));
}
public function admin_index() {
$this->index(true); //calls the index function to do all that stuff
$this->render('index'); //tells it to render the 'index' view
}
When you hit the /index page, all should be as normal. When you hit the admin_index, it runs the logic from the index function, then specifies to use the index view.

CakePHP dynamic element

I am trying to create a message-board type element in a CakePHP app. This element will be displayed on all pages and views that use a particular layout. I want it to display all the messages in the model, then show the add form when a link is clicked, then return to the updated message list when submitted. All this without affecting the current view/page.
I have my message model/controller/index set up, with a message board element that requests the index action. This works fine. However I am perplexed about how to return back to the original page/action from which the link was clicked. I can't use $this->referer() because that will link back to the add() action; what I want rather is to link to the page/view before that.
Any general pointers on how to achieve something like this?
I would approach this using Ajax, and use an ajax layout.
$this->layout('ajax')
Then you would be able to setup a full stack for processing this, and pass various things in as parameters into the controller actions.
By using Ajax you will not need to worry about passing in the referrer controller / action pair. You can also use the return from this to update the list by calling out to the MessagesController. The added bonus of this is that you can just switch the layout in your actual controllers, thus not having to write any extra code at all.
In your controller, you can check for Ajax
if($this->params['requested']){
$this->layout('ajax');
return $data;
}else{
$this->set('data',$data);
}

GWT, access RichTextArea by non-GWT (or "regular") javascript

I am writing a pretty simple CMS on GAE, and I want my users to be able to upload images.
I have written the part that does the actual uploading and showing the images, and here's what I'd like to do:
Show the usual form for new posts (with a widget that contains a rich text area and a format bar for it) and the list of images the user has ever uploaded (done). Then i want an image to appear in the text area when the user clicks that image.
I generate the list of images on the server, and i can't find a way to call any methods on the Rich Text Area from non-GWT javascript. And I don't really want to generate the list of images by means of AJAX, because it seems quite cumbersome and, hopefully, with the advent of HTML5 it is going to be much simpler.
Well, the question is, how can i access a RichTextArea in a widget from a normal javascript on a page, or is there another way of inserting an image into it (i.e. another is there a way to generate a list of images so that they would be in a kind of widget, but without the use of AJAX).
Thank you.
To answer your general question of getting access to your GWT code from hand written Javascript, you can use the general built in method or Ray Cromwell's gwt-exporter project. This way, you can expose the specific methods of the RichTextArea instance you're trying to access from external Javascript.
As for your other question, generating a list of Images should only require getting the urls for the images and creating a bunch of Image objects with the given URLs. Then display this list in a PopupPanel or some other widget.
Here is how i finally solved the problem (thanks to Arthur's reply above):
public class NewSection implements EntryPoint {
private static RichTextAreaWithFormatBar rta;
private Button pseudoSubmit;
#Override
public void onModuleLoad() {
invokeExternal("hello");
rta = new RichTextAreaWithFormatBar();
pseudoSubmit = new Button(">>>");
<...>
}
<some other code here>
public static void addImage(String a) {
rta.textarea().setHTML(
rta.textarea().getHTML() + "<br /><img src=\"/cms/i/"+ a +"\" alt=\"\"><br />");
}
native void invokeExternal(String int1) /*-{
$wnd.externalJsFunction(function(int1) {
#ur.g05.smc.client.NewSection::addImage(Ljava/lang/String;)(int1);
});
}-*/;
}
And here is the "hand-written" javascript in my templates:
(first the FreeMaker code for creating the image list in that same template):
<#list images as i>
<td><img src="/cms/i/${i.keyString()}.t" alt='' onclick='addImage("${i.keyString()}.p");'/><br /><p>${i.fullWidth()}·${i.fullHeight()}</p><p>${i.previewWidth()}·${i.previewHeight()}</p><p>${i.thumbWidth()}·${i.thumbHeight()}</p></td>
</#list>
And the script itself:
<script language="javascript">
var callBackFunction;
function externalJsFunction(func) {
callBackFunction = func;
}
function addImage(imgid) {
callBackFunction(imgid);
}
</script>
What in fact happens is:
First we create a list of images, adding an "onClick" listener to each of them with the url of each corresponding image as the argument. Image urls are formed from their Keys in the datastore, plus ".t" for thumbnails, ".p" for previews and nothing for full-size images.
Each image than calls the "addImage" function. But the addImage function has to know about the textarea, which it doesn't. To that end we create the "callBackFunction" variable, and the "externalJsFunction", that sets the value of that "callBackFunction" variable. And it sets it to whatever it gets as the argument.
Now, we can call that externalJsFunction from our Widget code and pass the function that adds an image to the textarea. However, i couldn't make it work while the richtextarea was not static.
That's basically it.
And thanks for replies and votes :)

Resources