Is there a way to someone have an after filter for the View::make? What im trying todo is to run the content from View::make that is returned, through an HTML minifier.
I already have App::after that minifies the final html doc. But see, im putting the View::make response into a json object (for ajax requests) and i need the response to be minified.
After filters generally work after the response has been sent to the user.
So to minify the HTML that the user will see need to be processed before it is sent.
But before filters will not work here either. As they are called before the controller method is processed.
So you will have to your process to be used within your controller, a possible solution could be to use a helper function with your minify code, or as a function within your BaseController, which is accessible to all your controllers which called the helper function.
You can do the following within your controller;
$view = View::make('view.path', $data)->render()
This will render and process the view into the HTML the user will see.
You can then pass this to the function you have to minify the HTML and insert it into the JSON response.
Related
I've been working with slim framework and I found a problem. I'm using mpdf library to generate pdf files out of the html content I'm passing to it. I'm also using Twig Templating Engine for (I think) obvious reasons. My problem is that I can't access body rendered by Slim Twig View, at the time the controller is working, because the data is still in the output buffer. I've made a workaround by creating middleware class intercepting a request with specific route and generating the pdf file from it's body but I don't think that's the way it's supposed to be done. I was also trying not to mess with ob_get_contents in the controller because that's like working against the framework.
So here is my question: Is there a better way to do what I did?
Twig's core library contains a class called Twig_Environment, which is used for rendering views. This class has these methods:
$twig->display('view.html.twig', $variables);
This will immediately output the generated content, which is not what you want for your PDF. You want this method:
$content = $twig->render('view.html.twig', $variables);
This method will return the generated HTML and won't echo it. You can then pass $content to your PDF library to convert it to PDF.
I don't know the framework you're using, you'll need to find a way to access the instance of the Twig_Environment class.
I'm working on a way for users to be able to generate PDF copies of invoices and other tabular data. To do this, I've wrapped dompdf into a library that I can use with CI and created a method that will generate a PDF based on the return value of CI's output->get_output(). The wrapper is similar to this one on Github.
The problem is, I can't figure out a way to get the view (and HTML/CSS needed for the PDF) into CI's output class other than load->view(), which is going to write to the browser.
My only other choice would be to use curl to request the page, but that seems so silly to do since I can get it right from the output buffer. I just don't want the HTML sent to the browser, since I set headers telling the browser to expect a PDF.
To be clear, this is what I want to accomplish (in the order that I want to accomplish it):
Do everything I'd normally do to prepare the view for display
Load the view into the CI output class, but not display it
Pass the return value of output->get_output() to my dompdf library
Set the appropriate headers
Execute my dompdf method that will send the PDF to the browser
I don't see any way of doing step 2 based on the output class documentation.
Is it possible to get a view into the output class without displaying it? If so, how? I'm using CI 2.0.3.
Edit
The very helpful Anthony Sterling pointed out that I can just get what I want from the loader class by setting the third argument telling it to return a string rather than render the view to TRUE. E.g.:
$lotsaHtml = $this->load->view('fooview', $somearray, TRUE);
And that would be better in my particular instance since I don't need to load partials. However, this is still a valid and (I think) interesting question, it would also be handy to know if I could get the same from the OB, perhaps if I did have a bunch of partials. Those could be concatenated, but yuck.
It seems like I should be able to get the output class to not render anything (else, why does get_output() exist?) so I can do something else with everything it knows about. I just can't find a way to make that happen.
Edit 2
Some pseudo (but not far from reality) code illustrating what I hope to do, by showing what I did and then explaining what I actually wanted to do.
Let's say I have a public method genpdf($id) in a controller named invoice using a model named inv:
public function genpdf($invoiceId) {
$this->load->library('dompdflib');
$this->pagedata['invoice_data'] = $this->inv->getInvoice($invoiceId);
$html = $this->load->view('pdfgen', $this->pagedata, TRUE);
$this->dompdflib->sendPdf($html);
}
That is almost identical to code that I have that works right now. There, I ask the loader to parse and give me the results of the pdfgen view as a string, which I pass to the function in my dompdf wrapper that sets headers and sends the PDF to the browser.
It just seemed like this would be easy to do by just getting the output buffer itself (after setting headers correctly / etc).
Or do I just have to call the output class append_output() in succession with every partial I load?
Multiple methods loading a plethora of models need to work together to generate these (they're going in as an afterthought), so I was hoping to just collect it all and retrieve it directly from the output class. It could be that I just have to talk gradually to output->append_output() to make that happen.
...so - do I understand correctly - you want to get the whole final output (not just the view) as a string AND not display it to the user? Why dont you just overload the controllers _output() function?
class Your_controller extends CI_Controller
{
function stuff()
{
// do whatever - prep $data etc
$this->load->view('your_view', $data);
}
function _output($output)
{
// send $output to your library - get results blah blah
$result_pdf_file = $this->your_pdf_library_generator($output);
// Show something else to the user
echo "hi - I'm not what you expected - but here is your PDF";
echo $result_pdf_file; // or something like that
}
}
This means you can send ANYTHING you like to the output class - but nothing is displayed except what you want.
There are ways to improve this idea (i.e. hooks, variables to turn output on/off etc) - but the simplest would be to have this controller specifically for your pdf_generation command.
I don't see any way of doing step 2 based on the output class documentation. Is it possible to get a view into the output class without displaying it? If so, how? I'm using CI 2.0.3.
The controller _output() documentation is actually in the CI controller documentation, which is why it eluded you.
I'm working with a PHP MVC Framework. Works really well. I like the separation of the business layer (model) with the business logic (controller). But i just stumbled upon a problem. Here's the thing:
Suppose i navigate to the following url:
http://localhost/user/showall/
In this case the userController.php is called and within that file there is a method showallAction() which gets executed.
In the showallAction() method i simply do a request to a model which gets all the users for me. Something like this:
public function showallAction()
{
// create userModel object
$users = new userModel();
// get all users and assign the data to a variable which can be accessed in the view
$this->view->users = $users->getAllUsers();
// render views
$this->view->render();
}
So this method gets all the users, assigns the data returned from the userModel to a variable and i can easily work with the returned data in my view. Just a typical MVC thing.
Now here comes the problem.
I also need to create a native iphone variant. Ofcourse the looks will be totally different. So all i actually want to do is to request this url:
http://localhost/user/showall/
And that it just gives me the array (in json format) back. So i can use that for the mobile development.
But this obviously can't be done right now because the showallAction() method assumes that it is for web browser display. It doesn't echo JSON formatted, instead it simply assings the array of users to a variable.
So that means i have to create another method "showallMobileAction()" in order to get the data, but specifically for the mobile device. But this is not an elegant solution. I'm sure that are better ways...
Anyone any idea how can i solve this problem??
In your situation i would modify the routing mechanism.
It would be useful, if you could add extension at the end of URL, which represents the format you expect, like :
http://foo.bar/news/latest >> HTML document
http://foo.bar/news/latest.html >> HTML document
http://foo.bar/news/latest.rss >> you RSS feed
http://foo.bar/news/latest.json >> data in JSON format
It's a simple pattern to recognize. And you can later expand this to add .. dunno .. pdf output, or Atom feeds.
Additionally , two comments :
Model is not a type of objects. Instead it is a layer, containing objects responsible for business logic, and objects responsible for data storage/retrieval.
View should be a full blown object, to which you bind the domain objects (objects responsible for business logic).
You could pass parameters to your url:
/user/showall/json
and get the third URL segment with a custom function or a built-in one. For instance, with CodeIgniter: $this->uri->segment(3).
Some frameworks will pass the additional parameters to your method. Just try this with the URL I wrote above:
public function showallAction()
{
print_r(func_get_args());
}
I'm not familiar with PHP MVC but in general terms I'd use the "accepts" HTML header field to request the response in either "text/html" or "text/json", the controller would check for the accepts type and return the response accordingly.
I am in the process of learning the MVC pattern and building my own lightweight one in PHP
Below is a basic example of what I have right now.
I am a little confused on how I should handle AJAX requests/responses though.
In my example user controller below, If I went to www.domain.com/user/friends/page-14 in the browser, it would create a User object and call the friends method of that object
The friends method would then get the data needed for the content portion of my page.
My app would load a template file with a header/footer and insert the content from the object above into the middle of the page.
Now here is where I am confused, if a request is made using AJAX then it will call a page that will do the process over, including loading the template file. IF an AJAX call is made, I think it should somehow, just return the body/content portion for my page and not build the header/footer stuff.
So in my MVC where should I build/load this template file which will have the header/footer stuff? ANd where should I detect if an AJAX request is made so I can avoid loading the template?
I hope I am making sense, I really need help in figuring out how to do this in my MVC I am building. IUf you can help, please use some sample code
/**
* Extend this class with your Controllers
* Reference to the model wrapper / loader functions via $this->model
* Reference to the view functions via $this->view
*/
abstract class Core_Controller {
protected $view;
protected $model;
function __construct(DependencyContainer $dependencyContainer){
$this->view = new Core_View();
//$this->view = $dependencyContainer->get(view);
}
public function load($model){
//load model
//this part under construction and un-tested
$this->$model = new $model;
}
}
user controller
/**
* Example Controller
*/
class User_Controller extends Core_Controller {
// domain.com/user/id-53463463
function profile($userId)
{
//GET data from a Model
$profileData = $this->model->getProfile($userId);
$this->view->load('userProfile', $profileData);
}
// domain.com/user/friends/page-14
function friends()
{
//GET data from a Model
$friendsData = $this->model->getFriends();
$this->view->load('userFriends', $friendsData);
}
}
For me, I developed a separate object that handles all template display methods. This is good because you can then ensure that all the resources you need to display your UI is contained in one object. It looks like you've isolated this in Core_View.
Then, when an AJAX call is made, simply detect that it is an AJAX call. This can be done by either making the AJAX call through an AJAX object, which then references other objects, or you can take an easy approach and simply set an extra POST or GET field which indicates an AJAX call.
Once you've detected if it's an AJAX call, define a constant in your MVC such as AJAX_REQUEST. Then, in your template/UI object, you can specify that if it's an AJAX call, only output your response text. If it isn't, proceed with including your template files.
For me, I send it through an AJAX object. That way I don't have to worry about making a single output work for both cases. When it's ready to send a response, I just do something to the manner of print( json_encode( ...[Response]... ) ).
well, it would all start with normal request which would load the initial page. there are many options as to handle this but let's say that you start with /users/friends page which would list all your friends. then each of the friends should have link to specific friend's profile -- now this is the moment where ajax could kick in and you could ajaxify links to your friend profiles - this means that instead of normal you would instead use let's say jQuery and setup click handler in a such way that
$("a").click(function(){$.post($(this).attr("href"), null, function(data){$("#content").html(data);}});
this would use "href", and upon click would make post request to your backend. at backend, if you see that it's post, then you would just return the content for that particular friend. alternatively, if you have get request, you return all - header - content - footer.
if you use technique above, make sure to properly handle the data you receive. e.g. if there are further actions that should be done via ajax, make sure to "ajaxify" the data you get back. e.g. after updating html of the content, again apply the $("a").click routine.
this is just trivial example, to kick you off, but there are many more sophisticated ways of doing that. if you have time, I suggest reading some of agiletoolkit.org, it has nice mvc + ajax support.
You will need to use a different view. Maybe something like:
funciton friends() {
$this->view = new Ajax_Request_View();
$friendsData = $this->model->getFriends();
$this->view->load($friendsData);
}
I am new to Zend FW. I am looking to write a simple feedparser in a controller named Feedparsercontroller's indexAction. but i want to display the parsed feed output as a widget on my index page. how can i drive the output/ variable data to my indexview?
The below is my parser.
class FeedparserController extends Zend_Controller_Action {
public function init() {
/* Initialize action controller here */
}
public function indexAction() {
$feedUrl = 'http://feeds.feedburner.com/ZendScreencastsVideoTutorialsAboutTheZendPhpFrameworkForDesktop';
$feed = Zend_Feed_Reader::import ( $feedUrl );
$this->view->gettingStarted = array ();
foreach ( $feed as $entry ) {
if (array_search ( 'Getting Started', $entry->getCategories ()->getValues () )) {
$this->view->gettingStarted [$entry->getLink ()] = $entry->getTitle ();
}
}
}
}
i want to implement the same with my login , register controllers as well.
Perhaps I'm not understanding your question fully.
But, it seems the best approach here would be to create a separate feed controller that is solely responsible for the business logic associated with feeds (retrieving, massaging, setting to view, etc).
Then, create a partial which contains javascript code to call the feed controller, which then outputs the widget you're desiring. This does a few things very well.
It centralizes feed-related logic
It allows you to place the feed widget wherever you want
It is a SOA approach which is generally a good thing
Hope this helps!
I think the best logic with widgets is ajax.
Use some js widgets libraries (maybe jQuery ui for example), then make these widgets be loaded by some ajax queries, returning HTML, this allow you as well simple widgets reloading behviours (without relaoding the whole page).
In the server Side you'll need to allow your controller/Action to be called via ajax requests and to send only html snippets (not a whole page with all the layout).
To do that check ContextSwitch and AjaxContext Action Helpers. You will tell your FeedparserController that the index action can be called with /format/html in an XMLHHTTPRequest, and that in this case the view helper will be index.
In the init part you will say the indexAction can be called in ajax mode, rendering html snippets ('html'):
$Ajaxcontext = $this->_helper->getHelper('AjaxContext');
$Ajaxcontext->addActionContext('index', 'html')
->initContext();
Now simply rename your view script feedparser/index.phtml to feedparser/index.ajax.phtml
In the indexAction, do your stuff and output what you want on your view script, do not think about layout composition problems, you're working alone with your own layout part and the composition is done on the js side.
In the javascript part, ensure you're calling via ajax ($.load or $.ajax with jQuery maybe) the url with format/html added as parameters (so http://example.com/feedparser/index/format/html)
Note that in my opinion you should use json responses and not html, maybe json with some html inside. But that's a matter on how you want to control your ajax communication (and handle errors, redirection and such, and it's another subject).
What about a view helper ?
You can read about it View Helpers in Zend Framework