Cake PHP multiple view pages have access to the same variables - php

I'm doing the blog tutorial (CakePHP 2.4.1) and have a question.
What is the reasoning ( and why) does the index.ctp page require me to loop through the
$posts variable to get data but the view.ctp file lets me just grab $post without looping?
I deleted the following action in PostController.php
and still could render the view.ctp file so I figure the two are not connected.
public function index() {
$this->set('posts', $this->Post->find('all'));
}

You're setting post in both of the controller's functions:
index()
$this->set('posts', $this->Post->find('all'));
view()
$post = $this->Post->findById($id);
$this->set('post', $post);
It would be odd if you weren't able to access the variables, but it seems everything is functioning as normal in your example
Edit:
You loop through the array in the index because you have multiple posts inside of an array. And in the view you're setting only a singular array containing one post so there is no need to loop through anything, you're able to grab the elements directly.

$this->set('posts', $this->Post->find('all'));
This will return an array of posts - notice the find('all')
$this->set('post', $this->Post->findById($id));
This will return a single post by the passed $id parameter.
The reason you have to loop through $posts is because its an array (returned by the find all), where $post is just a single post returned by findById)

Related

Laravel View Composer Paginating with ajax

I managed to find some resources to paginate a normal page with ajax. It's pretty easy. you can simply have this:
if($request->ajax()) {
return [
'posts' => view('ajax.index')->with(compact('posts'))->render(),
'next_page' => $posts->nextPageUrl()
];
}
But for Composer View this won't work, since I can't have $request in View Composer. Can anybody enlighten me. Maybe there is someway to get variables inside composer, since the link for it's pagination is basicaly the current page plus the extension for next contnet.
You can! just type hint the Request class and the service container will inject it at run time.Then you can access all the properties of request object
use Illuminate\Http\Request;
class MyComposer
{
public function __construct(Request $request)
{
$this->request= $request;
}
function compose($view)
{
if($this->request->ajax()) {
return [
'posts' => view('ajax.index')->with(compact('posts'))->render(),
'next_page' => $posts->nextPageUrl()
];
}
}
}
Update:
If you don't pass it from controller to your view but $category object still used in composer you get an error.
To avoid this you can either remove the * and explicitly pass view names those view that use category and create another declaration passing names of those views that do not, so you will need two view composers
//these views use category
View::composer([ 'view1','view2'], 'App\Http\ViewComposers\MyComposerWithCategory' );
//these views don't
View::composer([ 'view3','view4'], 'App\Http\ViewComposers\MyComposerWithoutCategory' );
Or you can just check if $category variable is set in an if statement
So here is an answer to this question. In case of View Composer Pagination. You can not paginate in composer, you technically have the ability to do that, but even if you get passed of doing requests to the provider(Which is obviously a bad idea) the pagination is still not going to work very well.
One of the basic issues you will face immideatly is pagination the page in a different page like posts/postslug, this one is going to throw errors easly. So what you should do instead is to create a very basic function in controller and do the requests to that page.
Here is an example.
Lets say you provide the data with the following query:
$posts = Post::orderBy('created_at', 'desc')
->paginate(15, ["*"], 'sidebar')->withPath('postPaginator');
The function that will paginate this needs to be something like this:
public function postPaginator(){
$posts = Post::orderBy('created_at', 'desc')->paginate(15 , ["*"], 'sidebar');
}
if you would like this pagiantor to be flexible for both ajax request and basic get requests, than you can return the result like:
if($this->request->ajax()) {
return [
'posts' => view('ajax.sidebarindex', ['posts' => $posts])->render(),
'next_page' => $posts->nextPageUrl(),
];
}
$posts->nextPageUrl() is there to provide the next page link so you can assigne it to the button for the next pagination.

How to pass variables from view to controller without form in laravel php

i have these values in the view folder.
.blade file is
#foreach($nam as $ergebnisse)
<h3>Id:{{$ergebnisse->id}}
Name_Id:{{$ergebnisse->name_id}}
Geometrie_Id:{{$ergebnisse->geometrie_id}}
</h3>
<h3>
<li>{{$ergebnisse->probe}}</li>
<li>{{$ergebnisse->schnittgrosse}}</li>
<li>{{$ergebnisse->temperatur}}</li>
<li>{{$ergebnisse->zeit}}</li>
<li>{{$ergebnisse->aussehen}}</li>
<li>{{$ergebnisse->farbe}}</li>
<li>{{$ergebnisse->deformation}}</li>
<li>{{$ergebnisse->geruch}}</li>
<li>{{$ergebnisse->texture}}</li>
</h3>
#endforeach
now i want to make another query in terms of these parameters.so how can i pass these to the controller or is there any other way of generating the queries within the view and displaying them?
Your question is not very clear, so i have 2 possible solutions:
If you want to load another view you can do something like this:
You can send parameters with links no need to be a form.
so you can do something like Do stuff
This will send the id of your $nam object to the route you prefer.
your route will look like this:
Route::get('your-url/{$nam}', YourController#test);
And in your controller you have to catch this value
public function test(Nam $nam) {
return $nam;
}
If you want to load the same view and have 2 different queries, just
do the 2 different queries inside your controller and send them
trough seperatly.
So in your current controller:
public function index(){
$nam = Nam::all();
// this is your second query:
$nam2 = Nam::latest()->get();
return view('your-view', compact('name','nam2' //this is the second variable))
}

Passing more than one array to more than one view

I'm trying to load a controller wich loads two two different views, and passes a different array to each view.
public function index(){
$this->load->view('Head');
$data=$this->DAOPromotor->recuperarPromotor();
$eventos=$this->DAOEvento->recuperarPromotorEventos();
$this->load->view('MostrarPromotor', $data);
$this->load->view('MostrarPromotorEventos', $eventos);
$this->load->view('Footer');
}
This is my Controller. Now, the first view ("MostrarPromotor') loads just fine, but the second one keeps throwing an Undefined Variable warning. I've used the recuperarPromotorEventos() method on differnt controllers, and it works just fine. I treat the array the same way on both scripts, but it only works in one.
I'm wondering if maybe it's not possible to have two views reciving data at the same time.
Found a solution after looking around some more: when you pass an array to a view, it breaks down said array on its different components, using the index names of the array as references. So, if I had this array:
$eventos = array(
'data1' => 'someData',
'data2' => 'someMoreData'
);
When I pass that array to a view, the view can access the variables $data1 and $data2, but not the $eventos data. As my original array didn't have any index named eventos, there wasn't any variable called that.
As for my particular problem, the only thing I had to do to fix it was to change the code to this:
public function index(){
$this->load->view('Head');
$data=$this->DAOPromotor->recuperarPromotor();
$eventos["eventos"]=$this->DAOEvento->recuperarPromotorEventos();
$this->load->view('MostrarPromotor', $data);
$this->load->view('MostrarPromotorEventos', $eventos);
$this->load->view('Footer');
}

Laravel4 - Trying to create widget like partials that will pass/accept a parameter to get the correct data

Within my views I am trying to reuse a partials, so I can create a list of latest posts anywhere in the site / sidebar by using the blade #include where the passed variable is the number of posts to be included, like this:
#include('widgets.lastestposts', array('numPosts' => '10')
However the problem I have is how to get the Post data for the correct number of posts within the partial?
I could pass through a list of all posts via Post::all() using the controller or even a View::composer and then within the partial use a #for|#endfor loop to only show the correct number based on the 'numPosts' value.
However this doesn't feel right and I am sure there must be a better way than pulling a complete list of Posts when I may only need 5 or 10.
I tried View::composers but I could find how to pass through a variable so I can get the correct number of Posts returned. I can't access the parameter 'numPosts' via
$view->getdata()
as I expect 'numPosts' needs to be passed to the view via the controller, rather than the Blade file - either that or I messed up!
Am I missing something easy here or is what I am looking to do actually a very bad idea and I should be doing something else?
Any pointers are most gratefully received. Thanks!
(ps - I was looking to be able to do this via the blade file rather than setting up the number of posts in the controller to allow our designers/HTML coders to simply add the widgets and parameters to the views rather than have to mess with controllers.)
I would do this using View Composers. You can pass data to the composer with your include:
#include('widgets.lastestposts', array('numPosts' => '10')
and then from within the view composer you should be able to access that param like so:
View::composer('widgets.latestposts', function($view)
{
$view_data= $view->getData();
$post_count = $view_data['numPosts'];
//You will have to implement something to do this
$post_data = Post::getLatestPosts($post_count);
and then you can pass the post data back with:
$view->with('posts', $post_data);
}
and then from within your blade partial widgets.latestposts you can iterate over $posts to display the posts.
I know you said in your post that you tried this method, but I am fairly certain that this approach should work. Double check all your filenames, file extensions (.blade.php) etc...
Hope this works.
Using a view composer is pretty easy:
You can, for instance, store your number of posts in a Session var:
View::composer('*', function($view)
{
$view->with('numPosts', Session::get('numPosts'));
}
Or just hardcode them:
View::composer('*', function($view)
{
$view->with('numPosts', 10);
}
And use it in your view:
<?php $i=1; ?>
#foreach($posts as $post)
{{ $post->title }}
<?php
$i++;
if ($i > $numPosts) break;
?>
#endforeach
Assuming that you've passed $posts to your view:
$posts = Post::all();
return View::make('your-view')->with('posts', $posts);
But, remember, you also can do things like
$posts = Post::orderBy('created_at', 'desc')->take(Session::get('numPosts'))->get();
// or
$posts = Post::orderBy('created_at', 'desc')->take(10)->get();
// and
return View::make('your-view')->with('posts', $posts);
So you won't have to filter them again in your view.

Clean way of passing variable to partial view

I'm looking for a clean way to pass variables to partial views. Consider the following example code:
In my controller I do:
$this->view->articles = $arrayWithArticles;
$this->render('articles.phtml');
In my articles.phtml view I do:
foreach($this->articles as $article) {
// show article
$this->render('comments.phtml');
}
In another controller I do:
$this->view->products = $arrayWithProducts;
$this->render('products.phtml');
In my products.phtml view I do:
foreach($this->products as $product) {
// show product
$this->render('comments.phtml');
}
As you can see I use the same (partial) view comments.phtml to display comments about written articles as well as products. The 'comments' I want to display are in $article->comments and $product->reviews. The partial view will need these to display them.
What would be a clean way to pass them to the partial view. I really don't want to do:
$this->comments = $article->comments;
$this->render('comments.phtml');
Because this would potentially become a pain to keep track off (i.e. setting the same view variables in both the controller as in the view).
Is there a clean solution to pass variables to partial views?
Well, I think adding a parameter to your render() method would be sufficient. Maybe something like...
$this->renderSubView($fileName, $data);
Then in renderSubView() you could do whatever it is that you need to do with the array and return the rendered partial view. This way you don't need to redeclare the variable in view, just pass the data appropriate for that specific partial when it is being rendered.

Categories