Why set request object values with JInput->set in Joomla? - joomla

I was looking at joomla code of a controller and I came across this function.
public function display($cachable = false, $urlparams = array())
{
JRequest::setVar('view', 'categories');
parent::display();
}
what is the purpose of setting values of request object.The view can be set through
controller's getView() function.
thanks

getView() is not setting the actual view. It's getting it. This code is setting the value in the request. In particular this would be useful for setting the default view if no view was present in the request. Also, JRequest is deprecated, so that code is legacy code (as is getView().

Related

Cakephp 3 View variables set in App controller not available when rendering specific template / AJAX requests

I am setting few view variables within my App controller such as company name, address, contact information which changes based on sub domains so that they are available throughout all view templates. However I am struggling to identify why the are not available when making ajax request.
//App Controller beforeFilter
$this->set('company', 'Test Company');
$this->set('address', '14 Test Street, Test, TE5 3ST');
$this->set('email', 'test#test.com');
Above variable are available for all none ajax i.e when I am not rendering specific template request however for below example request I am not able to access those variables in test_data template.
function _ajaxGetTestData()
{
$view = new View();
$content = $view->render('Home/Ajax/test_data');
$response['content'] = $content;
$response['success'] = TRUE;
$this->set(compact('response'));
$this->set('_serialize', ['response']);
}
That is because you did not serialize the variables from the app controller.
You can try in your method:
$response['company'] = $company;
$response['address'] = $address;
$response['email'] = $email;
Or https://book.cakephp.org/3/en/views/json-and-xml-views.html#using-a-data-view-with-template-files
You have to set view variables before render is called.
$this->set('data');
$this->render('custom_view');
When you call $this->set it sets the view variables on the Controller class. These variables are eventually passed to the View Builder, which creates a new View class and returns a Result containing the HTML for this new View.
When you want to render your own View manually you need to pass it the view variables manually too - $this->set isn't setting view variables in this new View class you created here:
$view = new View();
$content = $view->render('Home/Ajax/test_data'); // Has nothing to do with $this->set, you'd have to pass the variables in manually
This isn't generally the simplest approach to take to render an AJAX view.
While you can generally continue to use $this->set in beforeFilter as you already are:
public function beforeFilter(Event $event)
{
$this->set('company', 'Test Company');
$this->set('address', '14 Test Street, Test, TE5 3ST');
$this->set('email', 'test#test.com');
}
.. the easiest method to make an AJAX-compatible is to enable the JSON/XML handler let the built-in JSON/XML renderers do their magic.
In the action function (index/view/edit/whatever) just include the company/address/email in the _serialize variable.
For example, a "view" function might look like:
public function view($id = null)
{
// Do regular view stuff:
$entity = $this->MyTable->get($id);
$this->set('entity', $entity);
// Include ALL the variables you want in the response in _serialize:
$this->set('_serialize', ['entity', 'company','address', 'email']);
}
If you are sure you need a custom template (which isn't required), don't render it manually, just set the template when AJAX is detected:
if($this->request->is('ajax')){
$this->viewBuilder()->setTemplate('Home/Ajax/test_data');
}
This will automatically be rendered for you, using the variables you set with $this->set.
If you want to make a global custom template (for example, wrapping all your data with a "response" node), for all AJAX requests, use a new Layout instead of a custom template:
if($this->request->is('ajax')){
$this->viewBuilder()->setLayout('custom_json');
}
Create this layout in src/Template/Layout/custom_json.ctp and format it as you wish, for example:
<?php
/**
* #var \App\View\AppView $this
*/
?>
{"response": <?= $this->fetch('content') ?> }
See from docs:
Enabling Data Views https://book.cakephp.org/3/en/views/json-and-xml-views.html#enabling-data-views-in-your-application
Using the _serialize Key https://book.cakephp.org/3/en/views/json-and-xml-views.html#using-data-views-with-the-serialize-key
Custom Layouts https://book.cakephp.org/3/en/views.html#layouts

How to load a CodeIgniter view in $promise->then() in a controller?

In my CodeIgniter 2 controller I call a model method which returns a ReactPHP promise, and I want to load a CodeIgniter view in the function called by that promise's ->then() method. How can I do this? What happens instead is the controller method returns nothing, so I get a blank page in the browser.
Here is a simplified example illustrating what I'm trying to do:
class My_class extends My_Controller {
function my_method() {
$this->my_model->returns_a_promise()->then(function ($data) {
// How can I pass the promise's resolved value to the template here?
// It seems this never gets called, because my_method() returns
// before we get here. :(
$this->load->view('my_view', $data);
});
}
}
Is there any way to tell the controller method not to send output to the browser until after the promise has resolved?
I'm not sure what are you trying to do but if you want to stop view from outputting and return it as a string then output it with echo yourself you can do this:
$view = this->load->view('my_view', $data, TRUE);
Now you have the view as a var string you can use it to do what you are trying to do.
It turns out the code in my original question does work. So the question is the answer. But the reason it wasn't working for me was that returns_a_promise() was not returning a resolved promise, so ->then() was not called and the view was not rendered. In order to make it return a resolved promise, I had to call $deferred->resolve(); in the code that returned the promise.
The upshot of this is that this code example demonstrates it is possible to run asynchronous PHP (via ReactPHP in this case) in CodeIgniter controller methods. My particular use case is to run many database queries concurrently in the CodeIgniter model.
try this:
function my_method() {
$data = array();
$data['promise'] =$this->my_model->returns_a_promise();
$data['view'] = 'my_view';
$this->load->view('my_view', $data);
}

MVC5 custom HandleErrorAttribute needs to detect whether to return partial view to ajax call

I've created a custom HandleErrorAttribute in order to implement logging as part of the exception handling. However, unrelated to the logging, I have run into an issue where I need to render a partialview on an Ajax request instead of a JsonResult. I can detect that it is an ajax request but I can't figure out how to determine when it is appropriate to generate a JsonResult or a PartialView. In most instances, a JsonResult is appropriate but in some cases a PartialView is appropriate. Is there a way to determine what the action is expecting from within OnException()?
I was hoping to find a way to detect the required type of response via a property in filterContext or something that would allow me to dynamically determine the expected response type. In all of my research, I could not find anything that would make that possible. So, I dealt with the situation by adding a bool property (defaulting to false) to the custom HandleErrorAttribute class. I then applied this attribute to the method that is responding with a partialView instead of a JsonResult, setting the property value to true. When the property value is true, the OnException() method responds with a partialView instead of a JsonResult.
If there is a better way, please let me know.
I think the following snippets could help you detect the required type of response
protected override void OnException(ExceptionContext filterContext)
{
//Determine the return type of the action
string actionName = filterContext.RouteData.Values["action"].ToString();
Type controllerType = filterContext.Controller.GetType();
var method = controllerType.GetMethod(actionName);
var returnType = method.ReturnType;
if (returnType.Equals(typeof(JsonResult)))
{
}
}

Laravel 4: Responding to AJAX requests from controller

I'm trying to generate ajax specific responses from my controllers by using the Request::ajax() method, which is working just fine. The only problem is that the way I have it set up right now isn't really a nice looking solution.
My controller:
class HomeController extends BaseController {
protected $layout = 'layouts/main';
public function __construct()
{
$this->beforeFilter('auth');
}
public function getIndex()
{
$view = View::make('content.home.index');
if(Request::ajax()) return $view; //For ajax calls we only want to return the content to be placed inside our container, without the layout
$this->layout->menu = 'content.menu';
$this->layout->content = $view;
}
}
So right now, for every method I define within my controllers I need to add the code snippet that checks for an AJAX request and returns a single view if the statement returns true.
This leads to my question that is probably more PHP related than it is to the framework;
Is there a way of executing my AJAX check on every method call, without actually placing it inside the method? Or is there some other solution to keep my code DRY?
Thanks in advance!
PS: This is my first post on stackoverflow, so feel free to correct me if I made any mistakes
Create a new barebone layout named 'layouts/ajax' (or any name you like).
<?php echo $content ?>
In your Base controller, override this setupLayout() function.
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$layout = Request::ajax() ? 'layouts/ajax' : $this->layout;
$this->layout = View::make($layout);
}
}
Change your getIndex() function to this.
public function getIndex()
{
$view = View::make('content.home.index');
$this->layout->menu = 'content.menu';
$this->layout->content = $view;
}
Now non-ajax requests will be rendered using layout set in the controller, where as ajax requests will receive whatever set to $this->layout->content.
Note : Controller will neglect the layout setup in setupLayout(), if the called method returns truthy value. So this method will not work for functions like below.
public function getIndex()
{
return View::make('content.home.index');
}
You could just change the layout property, in the constructor, if it's an ajax request:
public function __construct()
{
$this->beforeFilter('auth');
if(Request::ajax()) {
$this->layout = '';
}
}
If it doesn't work try setting it to NULL instead.
Why would you return a VIEW via ajax? Are you using it to create a SPA? If so there are better ways. I'm generally against returning HTML via AJAX.
The route I'd go in your position is probably opposite of how you're doing it. Render the view no matter what, if the request is ajax, pass the extra data back and have JS render the data on the page. That's essentially how most Javascript MVC frameworks function.
Sorry if I am totally missing the point here, just going on an assumption of your end goal with the info you provided.

How to override save() method in a component

Where and how I am overriding the save method in Joomla 3.0 custom component ?
Current situation:
Custom administrator component.
I have a list view that displays all people stored in table.
Clicking on one entry I get to the detailed view where a form is loaded and it's fields can be edited.
On save, the values are stored in the database. This all works fine.However, ....
When hitting save I wish to modify a field before storing it into the database. How do I override the save function and where? I have been searching this forum and googled quiet a bit to find ways to implement this. Anyone who give me a simple example or point me into the right direction ?
Thanks.
Just adding this for anyone who wants to know the answer to the question itself - this works if you explicitly wish to override the save function. However, look at the actual solution of how to manipulate values!
You override it in the controller, like this:
/**
* save a record (and redirect to main page)
* #return void
*/
function save()
{
$model = $this->getModel('hello');
if ($model->store()) {
$msg = JText::_( 'Greeting Saved!' );
} else {
$msg = JText::_( 'Error Saving Greeting' );
}
// Check the table in so it can be edited.... we are done with it anyway
$link = 'index.php?option=com_hello';
$this->setRedirect($link, $msg);
}
More details here: Joomla Docs - Adding Backend Actions
The prepareTable in the model (as mentioned above) is intended for that (prepare and sanitise the table prior to saving). In case you want to us the ID, though, you should consider using the postSaveHook in the controller:
protected function postSaveHook($model, $validData) {
$item = $model->getItem();
$itemid = $item->get('id');
}
The postSaveHook is called after save is done, thus allowing for newly inserted ID's to be used.
You can use the prepareTable function in the model file (administrator/components/yourComponent/models/yourComponent.php)
protected function prepareTable($table)
{
$table->fieldname = newvalue;
}

Resources