Welcome to the Treehouse Community
Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.
Start your free trialyannverreault
12,599 PointsHow can I display database data from twig templates?
I'm using slim and twig. I did a PDO connection with mysql inside the index.php file where my slim controller is. It displays twig templates but inside twig templates, I have no idea on how to "echo" stuff from my database. Does anybody know how to do that?
8 Answers
Mayur Pande
Courses Plus Student 11,711 PointsYou will need to a value from your PDO associative array that stores the data required. Then create another associative array within your render for whichever template file you are rendering. If using twig you can then access the data with key for this associative array. Below is an example of what it would look like in your index file. Bare in mind I did this in slim v2 I think there have been changes on v3. I got stuck with this same problem for ages. Hope it helps. Any troubles let me know. Thanks
$app->get('/', function() use($app){
require_once('database.php');
try{
$result = $db->query('SELECT * FROM documentaries');
}catch(Exception $e){
echo $e->getMessage();
die();
}
$docs = $result->FetchAll(PDO::FETCH_ASSOC);
$items = array();
foreach ($docs as $doc){
$items[] = $doc;
}
$app->render('portfolio.twig', array('items' => $items) );
});
Mayur Pande
Courses Plus Student 11,711 PointsHi,
Try and have a go with this;
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require 'vendor/autoload.php';
require 'inc/database.php';
$app = new \Slim\App();
$container = $app->getContainer();
// Register component on container
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig('templates', [
'cache' => false
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
return $view;
};
// Render Twig template in route
$app->get('/', function ($request, $response, $args) {
return $this->view->render($response, 'home.twig');
});
$app->get('/about', function ($request, $response, $args) {
return $this->view->render($response, 'about.twig');
});
$app->get('/contact', function ($request, $response, $args) {
return $this->view->render($response, 'contact.twig');
});
$app->get('/upload', function ($request, $response, $args) {
return $this->view->render($response, 'upload.twig' );
});
$app->get('/hotels', function ($request, $response, $args) {
try {
$results = $db->prepare('SELECT * FROM hotels WHERE id = ?');
$results->bindParam(1, $id);
$results->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
}
$hotels = $results->FetchAll(PDO::FETCH_ASSOC);
$items = array();
foreach ($hotels as $hotel){
$items[] = $hotel;
}
return $this->view->render($response, 'hotels.twig', array('items' => $items));
});
$app->run();
Then in your dropdown on your twig template. You use the key items to access the desired data.
However you may need to loop through the items array in the twig template to access the data. However try the above first and let me know your outcome
yannverreault
12,599 PointsRight now the page loads correctly but the dropdown is empty. Here is what my dropdown looks like.
<div>
<select class="selecthotel" onchange="location = this.options[this.selectedIndex].value;">
<option>Select hotel</option>
<optgroup label="A-Z">
{% for i in items %}
<option value="hotels.php?id={{ i.id }}">{{ i.name }}</option>
{% endfor %}
</select>
</div>
Mayur Pande
Courses Plus Student 11,711 Pointsreplace the get method for /hotels with this
$app->get('/hotels', function ($request, $response, $args) {
try {
$results = $db->prepare('SELECT * FROM hotels WHERE id = ?');
$results->bindParam(1, $id);
$results->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
}
$ids = $results->FetchAll(PDO::FETCH_ASSOC);
foreach($ids as $id){
$i = $id;
}
try{
$result = $db->query('SELECT * FROM hotels');
}catch(Exception $e){
echo $e->getMessage();
die();
}
$hotels = $result->FetchAll(PDO::FETCH_ASSOC);
$items = array();
foreach ($hotels as $hotel){
$items[] = $hotel;
}
return $this->view->render($response, 'hotels.twig', array('i' => $i,'items' => $items));
});
This should work now. The reason it showed up blank is because when you were looping through the array in the twig file it didn't have the id stored in the key value you were using. Again if it doesn't work let me know. Hopefully it does this time.
Also not necessary, but good practice, is maybe at some point separate out the model code from the controller into a different file.
yannverreault
12,599 PointsHello Mayur, first of all I would like to thank you for your amazing help. Thank you for everything.
With some tweaks, I was able to get the dropdown to work. I need to tell you that maybe it was confusing but actually, I was trying to make the homepage to work, the homepage contains the dropdown
// Render Twig template in route
$app->get('/', function ($request, $response, $args) {
require 'inc/database.php';
try{
$result = $db->query('SELECT * FROM hotels ORDER BY REPLACE(name, "The ", "")');
}catch(Exception $e){
echo $e->getMessage();
die();
}
$hotels = $result->FetchAll(PDO::FETCH_ASSOC);
$items = array();
foreach ($hotels as $hotel){
$items[] = $hotel;
}
return $this->view->render($response, 'home.twig', array('i' => $i,'items' => $items));
});
This works great, when I select an hotel in the dropdown, it goes to hotels?id=2 as desired but now nothing show up on hotels?id=X because there is no query set for that page. Here is what I set in index.php and I'd like to know if it's correct.
$app->get('/hotels', function ($request, $response, $args) {
require 'inc/database.php';
try {
$roominfo = $db->prepare('SELECT hotels.name, rooms.*
FROM hotels
INNER JOIN rooms
ON rooms.hotel_id = hotels.id WHERE rooms.hotel_id = ?');
$roominfo->bindParam(1, $id);
$roominfo->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
};
if(!empty($_GET['id'])){
$id = intval($_GET['id']);
}
return $this->view->render($response, 'hotels.twig'
);
In hotels.twig, I have this. I guess I need to change it for twig to read it?:
<h2><?php echo $hotel['name']; ?></h2>
Mayur Pande
Courses Plus Student 11,711 PointsHi Yann,
Glad to here you got the first part working.
Now with regards to the second part.
In your dropdown we could change the url from hotels.php?id=x to hotels/{id} how do you feel about this? As this would make your url cleaner, and better for indexing on search engines.
They way you do this is first alter the url option value in the dropdown like so
<div>
<select class="selecthotel" onchange="location = this.options[this.selectedIndex].value;">
<option>Select hotel</option>
<optgroup label="A-Z">
{% for i in items %}
//made change here
<option value="hotels/{{ i.id }}">{{ i.name }}</option>
{% endfor %}
</select>
</div>
Then your correct we would run another query within the get method for hotels/{id}
$app->get('/hotels/{id}', function ($request, $response, $args) {
require 'inc/database.php';
$id = args['id'];
try {
$roominfo = $db->prepare('SELECT hotels.name, rooms.*
FROM hotels
INNER JOIN rooms
ON rooms.hotel_id = hotels.id WHERE rooms.hotel_id = ?'');
$roominfo->bindParam(1, $id);
$roominfo->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
};
//you need to fetch results here
$rooms = $roominfo->fetchAll(PDO::ASSOC);
//again loop through the assoc array
foreach($rooms as $room){
$r = $room;
}
//we don't need the get id here as this is done above in at the beginning of the method
return $this->view->render($response, 'hotels.twig','r' => $r );
});
So the above should now give you the page with url hotels/1 and then you again can access the data on your twig template with the key from the associative array like so.
<h2>{{ r.name }}</h2>
the above could need the other key to access the name variable. It depends in which table it is stored in. So it could be
<h2>{{ i.name }}</h2>
Hope this makes sense
yannverreault
12,599 PointsHello Mayur,
I had to do multiple tweaks to get it close to be working but I am stuck now. The hotels/id is working fine but I'm not able to get the information on the page. The problem is I did so many tweaks that now I'm kind of lost and I'm afraid I did something wrong in the index.php file.
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require 'vendor/autoload.php';
$app = new \Slim\App();
$container = $app->getContainer();
// Register component on container
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig('templates', [
'cache' => false
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
return $view;
};
// Render Twig template in route
$app->get('/', function ($request, $response, $args) {
require 'inc/database.php';
try{
$result = $db->query('SELECT * FROM hotels ORDER BY REPLACE(name, "The ", "")');
}catch(Exception $e){
echo $e->getMessage();
die();
}
$hotels = $result->FetchAll(PDO::FETCH_ASSOC);
$items = array();
foreach ($hotels as $hotel){
$items[] = $hotel;
}
return $this->view->render($response, 'home.twig', array('items' => $items));
});
$app->get('__root__/about', function ($request, $response, $args) {
return $this->view->render($response, 'about.twig'
);
});
$app->get('/contact', function ($request, $response, $args) {
return $this->view->render($response, 'contact.twig'
);
});
$app->get('/upload', function ($request, $response, $args) {
return $this->view->render($response, 'upload.twig'
);
});
$app->get('/hotels/{id}', function ($request, $response, $args) {
require 'inc/database.php';
$id = $args['id'];
try {
$roominfo = $db->prepare('SELECT hotels.name, rooms.*
FROM hotels
INNER JOIN rooms
ON rooms.hotel_id = hotels.id WHERE rooms.hotel_id = ?');
$roominfo->bindParam(1, $id);
$roominfo->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
};
//you need to fetch results here
$rooms = $roominfo->fetchAll(PDO::FETCH_ASSOC);
$r = array();
//again loop through the assoc array
foreach($rooms as $room){
$r = $room;
}
//we don't need the get id here as this is done above in at the beginning of the method
return $this->view->render($response, 'hotels.twig', array('r' => $r));
});
$app->run();
Here is what I try to show in my html on hotels.twig.
{% for i in r %}
<h2>{{ i.name }}</h2>
{% endfor %}
Mayur Pande
Courses Plus Student 11,711 Pointswhere has the mysql query to retrieve data i gone? You are looping through r with i but there is no query for that. Maybe try that. Is i meant to be the id of r?
Mayur Pande
Courses Plus Student 11,711 PointsAlso could you run some var_dump
tests on $id and r and let me know what you get please. Thanks
Mayur Pande
Courses Plus Student 11,711 Pointssorry one more thing you could try. Is within the for loop make *r a multidimensional array like so
$app->get('/hotels/{id}', function ($request, $response, $args) {
require 'inc/database.php';
$id = $args['id'];
try {
$roominfo = $db->prepare('SELECT hotels.name, rooms.*
FROM hotels
INNER JOIN rooms
ON rooms.hotel_id = hotels.id WHERE rooms.hotel_id = ?');
$roominfo->bindParam(1, $id);
$roominfo->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
};
//you need to fetch results here
$rooms = $roominfo->fetchAll(PDO::FETCH_ASSOC);
$r = array();
//again loop through the assoc array
foreach($rooms as $room){
//change here
$r[] = $room;
}
//we don't need the get id here as this is done above in at the beginning of the method
//change here
return $this->view->render($response, 'hotels.twig', array('r' => $r, 'i'=>$id));
});
Note being if you you use a for loop it will print out the names of all the hotels. Is this what you want? Or do you just want to print out the name of one hotel?
Also I just noticed your selecting hotels.name and room. so that might have something to do with it.
yannverreault
12,599 PointsHello Mayur, I will answer with to your 3 questions.
-
I realized that it was removed by accident but it was still working? I fixed it I think. Can you verify if it's okay?
$app->get('/', function ($request, $response, $args) { require 'inc/database.php'; try { $results = $db->prepare('SELECT * FROM hotels WHERE id = ?'); $results->bindParam(1, $id); $results->execute(); } catch(Exception $e) { echo $e->getMessage(); die(); } $ids = $results->FetchAll(PDO::FETCH_ASSOC); $i = array(); foreach($ids as $id){ $i = $id; } var_dump($id); try{ $result = $db->query('SELECT * FROM hotels ORDER BY REPLACE(name, "The ", "")'); }catch(Exception $e){ echo $e->getMessage(); die(); } $hotels = $result->FetchAll(PDO::FETCH_ASSOC); $items = array(); foreach ($hotels as $hotel){ $items[] = $hotel; } return $this->view->render($response, 'home.twig', array('i' => $i,'items' => $items)); });
When I'm doing var_dump($id) and var_dump($r) in the hotels page, I get this: string(1) "6" array(0) { }
In the hotels/id page, each id represent an hotel. When I load the hotel id 1, the name should only display the name of that hotel. In each hotel page, they have multiple unique rooms with their names, lets say that an hotel can have 10 different types(names) of rooms.
When I go to the hotel, I join the hotels table that has all the information about that particular hotel and the rooms table that is linked to that hotel with its own information. If I'm able to get at least the hotel information to show up on the hotels page, that would be a great success!
Thank you Mayur,
If needed, I join an updated version of my index.php page.
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require 'vendor/autoload.php';
$app = new \Slim\App();
$container = $app->getContainer();
// Register component on container
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig('templates', [
'cache' => false
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
return $view;
};
// Render Twig template in route
$app->get('/', function ($request, $response, $args) {
require 'inc/database.php';
try {
$results = $db->prepare('SELECT * FROM hotels WHERE id = ?');
$results->bindParam(1, $id);
$results->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
}
$ids = $results->FetchAll(PDO::FETCH_ASSOC);
$i = array();
foreach($ids as $id){
$i = $id;
}
try{
$result = $db->query('SELECT * FROM hotels ORDER BY REPLACE(name, "The ", "")');
}catch(Exception $e){
echo $e->getMessage();
die();
}
$hotels = $result->FetchAll(PDO::FETCH_ASSOC);
$items = array();
foreach ($hotels as $hotel){
$items[] = $hotel;
}
return $this->view->render($response, 'home.twig', array('i' => $i,'items' => $items));
});
$app->get('/about', function ($request, $response, $args) {
return $this->view->render($response, 'about.twig'
);
});
$app->get('/contact', function ($request, $response, $args) {
return $this->view->render($response, 'contact.twig'
);
});
$app->get('/upload', function ($request, $response, $args) {
return $this->view->render($response, 'upload.twig'
);
});
$app->get('/hotels/{id}', function ($request, $response, $args) {
require 'inc/database.php';
$id = $args['id'];
var_dump($id);
try {
$roominfo = $db->prepare('SELECT hotels.name, rooms.*
FROM hotels
INNER JOIN rooms
ON rooms.hotel_id = hotels.id WHERE rooms.hotel_id = ?');
$roominfo->bindParam(1, $id);
$roominfo->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
};
//you need to fetch results here
$rooms = $roominfo->fetchAll(PDO::FETCH_ASSOC);
$r = array();
//again loop through the assoc array
foreach($rooms as $room){
$r[] = $room;
}
//we don't need the get id here as this is done above in at the beginning of the method
return $this->view->render($response, 'hotels.twig', array('r' => $r));
});
$app->run();
{% for r in r %}
<h2>{{ r.name }}</h2>
{% endfor %}
Mayur Pande
Courses Plus Student 11,711 Points1) index.php looks good to me
2) so the var_dump($r)
returned array(0) { }
that would be the problem then. Its not returning any results from the query. You probably need to sort out the for loop to get the results. Keep trying until you get some results in the var_dump
then you should be able to continue.
Give this a go. I think this will be your problem.
If not let me know, or maybe send you database over, and I can try it on my machine.
yannverreault
12,599 PointsI cannot check on my laptop as I am at work currently but I just did a quick check. Could it be the variable in bindparam(1, $id) that is in cause?
try {
$roominfo = $db->prepare('SELECT hotels.name, rooms.*
FROM hotels
INNER JOIN rooms
ON rooms.hotel_id = hotels.id WHERE rooms.hotel_id = ?');
$roominfo->bindParam(1, $id);
$roominfo->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
};
//you need to fetch results here
$rooms = $roominfo->fetchAll(PDO::FETCH_ASSOC);
$r = array();
//again loop through the assoc array
foreach($rooms as $room){
$r[] = $room;
}
As you can see, $id is nowhere else in the code block of /hotels/
Mayur Pande
Courses Plus Student 11,711 PointsNo that would not be the case because when you obtained the id from the get method for hotels/{id}
using this;
$app->get('/hotels/{id}', function ($request, $response, $args) {
require 'inc/database.php';
$id = $args['id'];
try {
$roominfo = $db->prepare('SELECT hotels.name, rooms.*
FROM hotels
INNER JOIN rooms
ON rooms.hotel_id = hotels.id WHERE rooms.hotel_id = ?');
$roominfo->bindParam(1, $id);
$roominfo->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
};
//you need to fetch results here
$rooms = $roominfo->fetchAll(PDO::FETCH_ASSOC);
$r = array();
//again loop through the assoc array
foreach($rooms as $room){
$r[] = $room;
}
return $this->view->render($response, 'hotels.twig', array('r' => $r));
})
so this binds the $id we obtained from the url so when you click hotels/1 then this gets the value 1 which is $id and then the bindParam bind this $id with the mysql query.
I suggest running var_dump tests on $id again.
Also on $roominfo
and then finally $r.
This will show you where your results are not coming through. I think its either to do with your $roominfo or $r variables.
yannverreault
12,599 Points$roominfo = object(PDOStatement)#58 (1) { ["queryString"]=> string(207) "SELECT hotels.name, rooms.* FROM hotels INNER JOIN rooms ON rooms.hotel_id = hotels.id WHERE rooms.hotel_id = ?" } $id = string(1) "3"
r = $array(0) { }
Mayur Pande
Courses Plus Student 11,711 PointsOk I reckon testing your query string in mysql-workbench or phpmyadmin with the all of the id numbers that link to it from the homepage dropdown as it does not seem to be returning any results
yannverreault
12,599 PointsHello Mayur! I just came back from a 4 month trip and I couldn't work on my website. This evening I worked hard and I was able to get it partially working.
To refresh your mind, I have a database with two tables. One table is hotel names with their images, locations, descriptions. One table is rooms which is connected to each hotels.
On the main page "/", I have the hotels information and on "/hotels/idofthehotel I have the rooms information of that hotel.
The main problem right now is that my hotels page will show everything related to rooms but I am not able to display the hotel information.
do you have any idea on why it doesn't work?
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require 'vendor/autoload.php';
$app = new \Slim\App();
$container = $app->getContainer();
// Register component on container
$container['view'] = function ($container) {
$view = new \Slim\Views\Twig('templates', [
'cache' => false
]);
$view->addExtension(new \Slim\Views\TwigExtension(
$container['router'],
$container['request']->getUri()
));
return $view;
};
// Render Twig template in route
$app->get('/', function ($request, $response, $args) {
require 'inc/database.php';
try {
$results = $db->prepare('SELECT * FROM hotels WHERE id = ?');
$results->bindParam(1, $id);
$results->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
}
$ids = $results->FetchAll(PDO::FETCH_ASSOC);
$i = array();
foreach($ids as $id){
$i = $id;
}
try{
$result = $db->query('SELECT * FROM hotels ORDER BY REPLACE(name, "The ", "")');
}catch(Exception $e){
echo $e->getMessage();
die();
}
$hotels = $result->FetchAll(PDO::FETCH_ASSOC);
$items = array();
foreach ($hotels as $hotel){
$items[] = $hotel;
}
return $this->view->render($response, 'home.twig', array('i' => $i,'items' => $items));
});
$app->get('/about', function ($request, $response, $args) {
return $this->view->render($response, 'about.twig'
);
});
$app->get('/contact', function ($request, $response, $args) {
return $this->view->render($response, 'contact.twig'
);
});
$app->get('/upload', function ($request, $response, $args) {
return $this->view->render($response, 'upload.twig'
);
});
$app->get('/hotels/{id}', function ($request, $response, $args) {
require 'inc/database.php';
$id = $args['id'];
try {
$roominfo = $db->prepare('SELECT hotels.name, rooms.*
FROM hotels
INNER JOIN rooms
ON rooms.hotel_id = hotels.id WHERE rooms.hotel_id = ?');
$roominfo->bindParam(1, $id);
$roominfo->execute();
} catch(Exception $e) {
echo $e->getMessage();
die();
};
//you need to fetch results here
$rooms = $roominfo->fetchAll(PDO::FETCH_ASSOC);
$r = array();
//again loop through the assoc array
foreach($rooms as $room){
$r[] = $room;
}
return $this->view->render($response, 'hotels.twig', array('r' => $r));
});
$app->run();
yannverreault
12,599 Pointsyannverreault
12,599 PointsHey I just noticed your message and I'm still stuck!
This is what I have right now in my index.php file which is my controller. What I'm trying to do right now is to get a dropdown menu populated from a database on the homepage.
It will return the following error: Fatal error: Uncaught BadMethodCallException: Method render is not a valid method in /Applications/MAMP/htdocs/websites/website/vendor/slim/slim/Slim/App.php:129 Stack trace: #0 /Applications/MAMP/htdocs/websites/website/index.php(70): Slim\App->__call('render', Array) #1 {main} thrown in /Applications/MAMP/htdocs/websites/website/vendor/slim/slim/Slim/App.php on line 129