CakePHP - Render different view and set variables - php

I am attempting to render and set variables to a view that does not belong to any controller. Here is an example of my folder structure:
app/
-->View/
-->ExternalReportViews/ (There is no ExternalReportViews Controller)
-->example_view.ctp
I am trying to pass a variable called $orders to the view, I have verified that this variable exists and contains data by debugging from the controller.
I have succesfully rendered the view using any of the following methods:
// Method 1
$this->render('/ExternalReportViews/example_view');
$this->set('orders', $orders);
// Method 2
$view = new View($this, false);
$view->viewPath = 'ExternalReportViews';
$view->render('example_view');
$view->set('orders', $orders);
// Method 3
$this->viewPath = 'ExternalReportViews';
$this->render('example_view');
$this->set('orders', $orders);
It seems that regardless of whether the set method is placed before or after the render in any of the above methods, the $orders variable is not passed to the rendered view.
When attempting to debug($orders) in the view, I see that the variable is undefined.
I could obviously bypass this problem by temporarily storing $orders in $this->Session, but that seems a bit messy.
The reason for all of this is that I will have a number of views that will be created on a per-report basis, and I would rather have them in a separate (sub)folder(s) for cleaner file management.

As it would happen, I just needed to change the variable name. I'm either hitting on a reserved keyword, or I've previously defined the variable in my beforeFilter method. Not sure which yet, but credit goes to scrowler for pointing that one out.

Related

Laravel : form does not change the URL after submit, causing me to be unable to do another POST in web.php

I have a bit of a complicated issue. I could use some help.
I have a form that is being handled by the following function:
$module = request('module');
$classe = request('classe');
$horaire = request('horaire');
$date = request('date');
$students = DB::select('SELECT * FROM `etudiants` WHERE etudiants.id_classe = '.$classe);
return view('g_absence.absence',['module'=> $module, 'classe'=>$classe,'horaire'=>$horaire,'date'=>$date,'students'=>$students]);
I take the values $module, $class, $horaire, $date and $students and need to use them inside a different view: g_absence.absence. This works fine and when the view is returned I have access to said variables.
The issue is, inside the g_absence.absence view, I have another form that also needs to be handled, and because the url remains the same even tho a different view is returned, I cant make two posts for the same path.
web.php:
Route::get('/testboy', [App\Http\Controllers\g_absence::class,'index'])->name('marquer');
Route::post('/testboy',[App\Http\Controllers\g_absence::class, 'marquer']);
Route::post('/testboy',[App\Http\Controllers\g_absence::class, 'ajoutabsence']);
The first line is the one that send to the form page just a simple
return view
The second one handle the form in that view
The third one, I want it to handle the form inside the
g_absence.absence view, but they share the same path.
Excuse me if I'm being unclear, I'm a bit of a beginner in Laravel
your problem is using the same route for different methods
basically the first route gets executed every time you use the '/testboy' action that is why your second function never get's called.
you can solve this issue by changing your urls for example:
Route::post('/testboy-marquer',[App\Http\Controllers\g_absence::class, 'marquer']);
Route::post('/testboy-ajoutabsence',[App\Http\Controllers\g_absence::class, 'ajoutabsence']);
Or you can use one function that's handle both with one url by pathing additional parameter to your url depending on your function call :
Route::post('/testboy?type=marquer',[App\Http\Controllers\g_absence::class, 'ajoutabsence']);
in your function check the type :
if(request('type') == 'marquer') {
execute marquer logic here...
} else {
execute absence logic here...
}
Using method and path with two functionalities is wrong, but if you want to somehow use both routes my same method and path which I don't recommend you must let the request to pass through like a middleware in your first block of code Instead of return a view.
Recommended way is to have 2 routes with different paths or at least one route with a parameter by which you can determine what code block must be executed.

Access a variable from an non associated Controller in Cakephp

I am developing a quiz using a 'form' in cakephp. I have declared a variable within my CourseModules controller ($passMark) where the HR developing the quiz can set the pass percentage the user needs to successfully complete the quiz. I have declared the variable like so:
case "Quiz":
$quiz = $this->CourseModules->FormTemplates->find('list')->where(['active'=>true,'type'=>'Quiz']);
$passMark = [100=>'100%',90=>'90%',80=>'80%',70=>'70%',60=>'60%',
50=>'50%',40=>'40%',30=>'30%',20=>'20%',10=>'10%',0=>'0%'];
$this->set('passMark',$passMark);
$this->set('quiz',$quiz);
break;
I then need to access the variable $passMark within my FormsController so that I can check it against another variable ($percCorrect). $percCorrect is declared as so in my Forms Controller:
$percCorrect = $numberCorrect / $numberOfQuizQuestions * 100;
$this->set('percCorrect', $percCorrect);
I want to do an if statement so check in if $percCorrect is < $passMark but I'm unsure how to access $passMark because CourseModules isn't associated with Forms Controller.
I do have another controller called CoursesEnrolledModules that is related so I'm wondering if I can somehow access it through there?
I have the following code in my FormsController to load the CoursesEnrolledModules:
//Check if courses_enrolled_module_id is set
$courses_enrolled_module_id = $this->request->getQuery('courses_enrolled_module_id');
//If so make sure it is valid
if($courses_enrolled_module_id){
$this->loadModel('CoursesEnrolledModules');
$coursesEnrolledModule = $this->CoursesEnrolledModules->get($courses_enrolled_module_id,
['contain'=>[],
]);
//Pass variable to view so we can show correct back button
$this->set('coursesEnrolledModule', $coursesEnrolledModule);
//Also after save we will redirect.
}
Any time you ask yourself "how do I access one controller from another controller", just stop yourself right there and think about a different option. In this case, you should put your array in a central location accessible by everything that might need it. Include it in the config in your app.php, perhaps, and then reference it with Configure::read(...) anywhere you need it.

Laravel passing variable out of view partial to main blade, or between partials

I have a Laravel 5.5 app that uses view blades conventionally, nothing fancy. My blade is a long table of data and I split the group sections (item categories) into their own partials to manage the code better.
However, I can't find a way to pass variable data from the partials back to the main blade, or even between partials. The scope of the variables are bound within the partials and I need to show a page total that aggregates the sub-totals from the various partials (sections). I did try using
View::share('portfolio_total', 100);
in the AppServiceProvider, to no avail. I can set a value (like the 100 shown) that stays intact in the master blade, but doesn't pick up the value set in that variable in the partial. Changing the variable value inside the partial doesn't update the value available to the master blade. I've searched extensively for this and there are many examples of passing values into partials, but not back out.
Is there a Laravel trick for defining the equivalent of global variables that can have their value set in an included partial blade, and carry that value to another partial blade, or out to the master blade?
Thanks in advance.
I can't find a way to pass variable data from the partials back to the main blade, or even between partials.
That is because this is absolute bad practice. Hence the framework does not allow that (without abuses).
Why?
In the MVC world (which Laravel implements), views are responsible for displaying data.
If you are computing anything in your views (partials or not), then it means you are giving Views the responsibility of the Controller and/or Model. Which is not good of course.
Then what?
Idea is to compute everything you need before using the views. Two options:
If your view/partial is used only by a single controller method, simply pass the data to the view as usual.
If your view/partial is used in various places, setup a ViewComposer which will be able to pass the computed data each time that partial is used.
What usually I do is the following.
On my controller, to return data I do this:
$data = [];
$data['dummyData'] = Dummy::all();
$data['extraData'] = 'Extra string';
return view('myroute.index', array('data' => $data));
Then on each of my views (The view and the partials)
#php
$dummy = $data['dummyData'];
$extra = $data['extraData'];
#endphp
And then I can use the variable in the blade as any other: {{ $extra }}

Silverstripe customize controller data/variables

I'm trying to return search results to a new controller than where the search action was performed from. Problem is Results is never accessible from CustomSearchResultPage.ss. I've added inline comments for what I think is happening, am I right in my thinking here?
// Customise content with results
$response = $this->customise(array(
'Results' => $results ? $results->getResults() : '',
));
if ($results) {
$response = $response->customise($results);
}
// Use CustomSearchResultPage.ss template
$templates = array('CustomSearchResultPage', 'Page');
// Create a new CustomSearchResultPage page
$page = CustomSearchResultPage::get_one('CustomSearchResultPage');
// Build a controller using the CustomSearchResultPage
$controller = CustomSearchResultPage_Controller::create($page);
// Add the custom data to the newly minted controller
$result = $controller->customise($response);
// Return the controller and tell it how to render
return $result->renderWith($templates);
The page seems to render as expected just the variable is always empty...
Your explanation is a little hard to follow I'm afraid. So I'm answering for what I can ascertain as below:
Performing a search. This requires loading a controller to do as such.
Customising the current controller with the results
RE-customising the current controller with itself.
Setting the template for the current (double customised) controller.
Disregarding all of the above.
Fetching a random page (or an empty record).
Creating a controller for the empty page.
Customising the new controller with the customised controller of the current controller customised with itself.
Returning that page, which shows no results.
You need only stop at step 4 (skip step 3), and return the customisation ($response).
If there is some reason you think you need another controller however (which seems superflous, but who knows), creating and then customising that one (only) before returning it would be better.
Being that you have only used this second controller for rendering a result, the URL will not have changed or anything. The whole thing seems beyond requirements.
A much more simple way to render a result from this action would probably be:
return $this
->customise(['Results' => $results ? $results->getResults() : null])
->renderWith(['CustomSearchResultPage', 'Page']);
(from the top of my head, may need a little refining).

Passing two arrays from controller in cakePHP

I'm trying my best to learn MVC and cakePHP and I had a question about passing arrays to the view. Currently, I have some basic code below.
class AwarenesscampaignsController extends AppController {
public function view($id = null) {
$this->Awarenesscampaign->id = $id;
$this->set('data', $this->Awarenesscampaign->read());
}
This is what I "think" is currently happening.
AwarenesscampaignsController is set up. The view paramater requests id and matches it up with the Model, Awarenesscampaign. This matches up with the database and returns an array which is set to the variable "$data", and then the view is loaded.
My first question: is my understanding accurate?
What I would like to do is with this is to be able to pass another array, from a different model. For instance, I would like to query the table Posts (Controller: PostsController/ Model: Post).
For instance, my first attempt was to do the following inside the function:
$this->Post->find('all');
But this yields the error:
Indirect modification of overloaded property AwarenesscampaignsController::$Post has no effect [APP/Controller/AwarenesscampaignsController.php, line 20]
Additionally, I'm not sure how I would send both variables to the view.
To recap:
Was my understanding accurate?
How do I query a variable from another controller/model?
How do I sent this array to the appropriate view for that controller?
Thanks,
-M
You're on the right lines, and aren't doing it wrong per se. I would say your understanding is pretty good for a beginner.
By default Cake automatically loads a model that it thinks is directly related to the controller. So in AwarenesscampaignController, you can automatically access Awarenesscampaign (the model).
It doesn't know about any other model, though. One way you might solve this is by adding the following property to your controller:
// This has to contain ALL models you intend to use in the controller
public $uses = array('Awarenesscampaign', 'Post');
This goes at the top of the class, before you start declaring the functions. It tells Cake that you want to use other models except the 'default' one, but you have to add that one to the array too, or you'll lose access to it.
You can also use loadModel inside your action, if it's a one-off. It's then accessed the same way as you would access a model normally:
public function view($id = null) {
$this->loadModel('Post');
$posts = $this->Post->find('all');
...
}
To send this to your view, you can call set again, but you might want to change data to something more readable, and to prevent confusion:
public function view($id = null) {
...
$this->set('campaign', $this->Awarenesscampaign->read());
$this->set('posts', $this->Post->find('all'));
}
They'll be accessible as $campaign and $post respectively.
One tweak I would make, though, is to not use 'read' unless you intend to edit something. You can use findByColumnName to get the same data. Since you're using just an id, you can call findById:
$campaign = $this->Awarenesscampaign->findById($id);
There's quite a lot of magic going on there. It just means you can search for a particular value in a more short-hand format.
http://book.cakephp.org/2.0/en/models/retrieving-your-data.html
Finally, while you can access other models (as demonstrated), you can't, or generally shouldn't, try and access one controller from another. If you have code that you want to use in more than one controller, but can't go in the model, you can create Components.
http://book.cakephp.org/2.0/en/controllers/components.html#creating-a-component
The manual is fairly comprehensive. While sometimes hard to navigate, it will often have an answer to most of your questions.
http://book.cakephp.org/2.0/en/
1) Your understanding is good enough. What this is doing is basically mapping a row of database table with object. So after setting the Model id $this->Awarenesscampaign->id = $id, now Model is pointing to the row of database table that has id equals to what has been passed to view action.
2) you can query another table by calling the methods of that particular Model. If your model is somehow associated with the current Model that you are in, you can use chaining to call that Model's action. e.g. if your in Posts controller and Post Model is associated with Comment Model t get the data you can chain through.
$comments = $this->Post->Comment->find();
If however your Model of interest is not associated with current Model, there are couple of ways to perform operations of other Model. A good option is to use Class Registry. Say for example you want to use Customer Model which is not related to your current Model. In your controller you will do
$customer= ClassRegistry::init("Customer");
$customers= $customer->find();
3) to set multiple variables for the view you can set them via compact function or using associated row.
$posts = $this->Post->find();
$comments = $this->Post->Comment->find();
$this->set(compact('posts', 'comments'));
// or
$this->set('posts' => $posts, 'comments' => $comments);

Categories