I'm having trouble getting categories and subcategories - php

Here's my database:
id name parent_id
1 Computers NULL
2 Apple 1
3 Books 1
4 Music NULL
5 CDs 4
6 Records 4
My categories function:
public function showCategories($parent_id = 0){
if($parent_id == 0){
$sql = "SELECT * FROM categories WHERE parent_id IS NULL";
} else {
$sql = "SELECT * FROM categories WHERE parent_id =:parentid";
}
$stmt = $this->db->prepare($sql);
$stmt->bindParam(':parentid', $parent_id);
$stmt->execute();
$categories = array();
while($row = $stmt->fetch(PDO::FETCH_ASSOC)){
array_push($categories, array($row['id'] => $row['name']));
}
return $categories;
}
Here's my category page:
<?php
//Instantiate categories class
$categories = new categories($db);
$categoriesMain = $categories->showCategories(0);
?>
<html>
<head></head>
<body>
<form action="" method="post">
<?php //Get parent categories and put them into a select box ?>
<select name="categoriesMain">
<?php for($i=0;$i<count($categoriesMain);$i++){ ?>
<option value="<?php echo $i; ?>">
<?php echo $categoriesMain[$i]; ?>
</option>
<?php } ?>
</select>
<input type="submit" name="submit" value="submit"/>
</form>
<?php //if form submits then show sub categories ?>
<?php if(isset($_POST['submit'])){
$categoriesSub = $categories->showCategories($_POST['categoriesMain']);
for($i=0;$i<count($categoriesSub);$i++){
echo $categoriesSub[$i];
}
} ?>
</body>
</html>
Let me try to explain what im having trouble with. I think my whole design is out of place because it feels like that but im having a brain block at the moment.
In the function I'm returning an array like Array ( [0] => Array ( [1] => Computers ) [1] => Array ( [4] => Music ) ). If you think this is the wrong way to return it let me know. Ok then do you see CategoriesMain? I'm using a for loop to output this array and for option=value im echoing $i however this $i goes like 1, 2, 3, 4 however I want the value to be the value of the parent category e.g. 1, 4 so that I can collect the value using $_POST['cateogoriesMain'] in the next for loop where I'm displaying cateogriesSub where it will get the database rows for those with the parent_id = to whatever was selected in the selectbox previously. I hope it makes sense.

You should use the key of the array for the option value, like this:
<select name="categoriesMain">
<?php foreach ($categoriesMain as $k => $v) { ?>
<option value="<?php echo $k; ?>">
<?php echo $v; ?>
</option>
<?php } ?>
</select>
edit also change the following line inside the php function, instead of:
array_push($categories, array($row['id'] => $row['name']));
do
$categories[$row['id']] = $row['name'];

Related

How to Change Multiple Checkbox Query to Multiple Chosen jQuery?

I have a multiple checkbox query, as below
<span style="width:276px;display:inline-block;"> <input type="checkbox" name="check_list[]" value="sub_category_id = '1''">Name1</span>
<span style="width:276px;display:inline-block;"> <input type="checkbox" name="check_list[]" value="sub_category_id = '2'">Name2</span>
<span style="width:276px;display:inline-block;"> <input type="checkbox" name="check_list[]" value="sub_category_id = '3'">Name3</span>
<span style="width:276px;display:inline-block;"> <input type="checkbox" name="check_list[]" value="sub_category_id = '4'">Name4</span>
then
<?php
$names = implode(' or ', (array)$_POST['check_list'.$i]);
echo $names;
?>
I got part of my query.
sub_category_id = '1'' or sub_category_id = '2' or sub_category_id = '3' or sub_category_id = '4'
Using chosen Jquery, I´m able to retrieve the MySQL data (Name1, Name2, Name3, Name4), as below:
<select name="sub_category_id[]" id="sub_category_id[]" multiple class="chosen-select" tabindex="8">
<option value="">Selecione...</option>
<?php foreach ($arrEstados as $value => $name) {
echo "<option value='{$value}'>{$name}</option>";
}?>
</select>
$names = $_POST['sub_category_id'];
$query=implode('sub_category_id=', $names);
echo $query;
But the 'or' is missing. I don´t have great skills in PHP, so I ask: Is this the right way to get my query? I´m not using PDO or mysqli.
change your html select element to follow this:
<select name="check_list[sub_category_id][]" id="sub_category_id[]" multiple class="chosen-select" tabindex="8">
<option value="">Selecione...</option>
<?php
foreach ($arrEstados as $value => $name) {
echo "<option value='{$value}'>{$name}</option>";
}
?>
</select>
doing this will create an array like this in your $_POST:
$_POST => Array
(
[check_list] => Array
(
[sub_category_id] => Array
(
[0] => 2
[1] => 3
)
)
)
then change your PHP like so:
<?php
$names = isset($_POST['check_list']) && isset($_POST['check_list']['sub_category_id']) ? $_POST['check_list']['sub_category_id'] : NULL;
$query = "SELECT * FROM tablename WHERE ";
if(!is_null($names)){
foreach($names as $i => $name){
if($i !== 0){
$query .= " OR ";
}
$query .= "sub_category_id = '$name'";
}
}
echo($query);
//Output: SELECT * FROM tablename WHERE sub_category_id = '2' OR sub_category_id = '3'
}
?>
you might need to change the query to fit your application, but this will help get in you in the right direction.
As Martin suggest de http://www.tutorialspoint.com/mysql/mysql-in-clause.htm turns the simple way to solve it. That´s what i did:
<select chosen still the same...>
$sub_category_1 = $_POST['sub_category_id'];
$query=implode(',', $sub_category_1);
$sql = "Select * from table WHERE sub_category_id IN($query)";

Using foreach with mysqli_fetch_assoc

I have a mysql table with two columns; id and type. I'm trying to retrieve those values to use in a select list of values (aka drop down list). Outside of my html, this php works perfectly:
$sql = "SELECT * FROM `usertype`";
$query = mysqli_query($con, $sql);
while ($type_lov = mysqli_fetch_assoc($query)) {
echo '<pre>', print_r($type_lov,true), '</pre>';
};
Output from php above:
Array ( [id] => 1 [type] => System Admin )
Array ( [id] => 2 [type] => System Admin2 )
Array ( [id] => 3 [type] => System Admin3 )
Array ( [id] => 4 [type] => Account Admin )
Array ( [id] => 5 [type] => Account User )
To get it into the SELECT / OPTIONS tags, I attempted several things unsuccessfully. The two attempts that made the most sense to me (but that did not work) were:
<!--ATTEMPT 1-->
<select>
<?php while ($type_lov = mysqli_fetch_assoc($query)) {
foreach ($type_lov as $id=>$type) { ?>
<option value="<?php echo $id; ?>"><?php echo $type; ?></option>
<?php };
}; ?>
</select>
<!--ATTEMPT 2-->
<select>
<?php foreach ($type_lov = mysqli_fetch_assoc($query) as $id=>$type) { ?>
<option value="<?php echo $id; ?>"><?php echo $type; ?></option>
<?php }; ?>
</select>
Neither worked. What is the proper way to go about this?
You should read up on mysqli_fetch_assoc. It returns it's data as an associative array, meaning your table columns are used as indices for the array.
Furthermore, why are you coupling while with foreach in your first example? What's the thought process that you went on?
Anyway, this should help you on your journey:
<select>
<?php
while (($data = mysqli_fetch_assoc($query)))
{
echo '<option value="' . $data['id'] . '">' . $data['type'] . '</option>';
}
?>
</select>

PHP Inner Join, Using a foreach loop when one table has multiple outputs

I have a situation where I have several tables that I am pulling from with an INNER JOIN. There is a one to many relationship, where the main table has one line for each park, but the photos table could have several lines for some parks. My code works in that a photo is being displayed for each park, but I can only get one to display. I suspect the problem is in the foreach loop, but I'm a little stumped. Here's the code:
try
{
$sql = 'SELECT parks.id, parks.state, parks.name, parks.description, parks.site, parks.sname, parks.street, parks.city, parks.zip, parks.phone, comments.comment, comments.commentname, events.event, events.date, events.description2, photos.parkid, photos.type, photos.filename, photos.big FROM parks
INNER JOIN comments INNER JOIN photos INNER JOIN events ON parks.parkid = comments.parkid and parks.parkid = photos.parkid and parks.parkid = events.parkid
GROUP BY parks.id
ORDER BY parks.name asc';
$result = $pdo->query($sql);
}
catch (PDOException $e)
{
$error = 'Error fetching data: ' . $e->getMessage();
include 'output.html.php';
exit();
}
//This is pulling the information from the database for display. On the foreach it will display each
//line until there are no more lines to display.
foreach ($result as $row)
{
$datas[] = array ('id' =>$row['id'],
'parkid' =>$row['parkid'],
'state' =>$row['state'],
'name' =>$row['name'],
'description' =>$row['description'],
'site' =>$row['site'],
'sname' =>$row['sname'],
'street' =>$row['street'],
'city' =>$row['city'],
'phone' =>$row['phone'],
'zip' =>$row['zip'],
'commentname' =>$row['commentname'],
'comment' =>$row['comment'],
'event' =>$row['event'],
'date' =>$row['date'],
'description2' =>$row['description2'],
'type' =>$row['type'],
'filename' =>$row['filename'],
'big' =>$row['big']);
}
include 'writing.html.php';
and
<?php
foreach ($datas as $name)
{
if ($name['state'] === 'PA')
{
?>
Back to top
<input type="hidden" name="id" value="' . $name['id'] . '" />
<h1 id="name"> <?php echo ($name['name']) ?> </h1>
<p id="descriptionlist">
<?php echo ($name['description']) ?>
<br />
<ul id="link">
<li class="l1">
<?php echo $name['sname'] ?>
</li>
</ul>
</p>
<h2>Location</h2>
<div class = "loc">
<p class="loct">
<a class = "fancyImg" href="maps/<?php echo $name['id'] ?>state.gif"> <img src= "maps/<?php echo $name['id'] ?>state.gif"> </a>
<br />
<php echo ($name['street']) . ?>
<br />
<?php echo ($name['city']) .
($name['state']) .
($name['zip']) ?>
<br>
<?php echo ($name['phone']) ?>
<br> <br>
</p>
</div>
<h2>Trail Map</h2>
<div class = "map">
<p class = "mapt">
Click to Enlarge
<a class ="fancyImg" href= "/maps/<?php echo $name['id'] ?>maplink.gif">
<img src= "/maps/<?php echo $name['id'] ?>.gif"></a> <br> <br>
</p>
</div>
<h2>Photos</h2>
<div class = "pho">
<p class = "phot">
<a class = "fancyImg" href= "/assets/indiv/<?php echo $name['big'] ?>.gif">
<img src= "<?php echo $name['filename'] ?>.gif"></a>**
Submit <i>your</i> photos of <?php echo ($name['name']) ?> through our <ul id = "link"><li>Facebook Page!</li></ul></h3><p> Or go to our Contact Us page for information on how to e-mail us your favorite pictures!
</p>
</div>
The issue at hand is in the pho div at the end here. I was hoping that $name['big'] would give me all of the items for this loop, but it only gives me the first. I'm missing something fundamental here.
The link is http://www.ride4wheel.com/new_ma.php
The relational database results will be always returned as rows beside the fact that your query has a relationship one to many, I think in your case you will have to loop again using your unique Id and looking for different values for 'big' field.
I don't also think that you need the foreach loop to make you results like associative array, you may need to use this instead : PDOStatement::fetchAll
The problem is in your query.
You INNER JOIN photos which would create a row for all photos and the parks repeating for each assigned foto. The GROUP BY distincts the parks again but forces MySQL to select one of the assigned photos.
If a park doesn't have a picture, it will not be in the list at all ( INNNER JOIN = give me all which have a relation in both tables )
You could remove the GROUP BY and replace the INNER JOINs by LEFT JOINs ( give me all parks and attach the images and comments if you got any ) which would require checks in the output loop ( whats my current park, did I display this park already, display curren picture, display current comment )
The cleaner but slower solution would be to remove the joins and field for fetching images and comments so you only get the parks; then in the parks loop fetch the comments and fetch the images for the current park in two extra queries.
EDIT 1:
Just like said in the comments this is not a really good alternative since you'll fire two additional queries and run two more loops for every park you add. I want you to understand the basic problematic of a many to many relationship - db results can be only two-dimensional tables
EDIT 2:
I've fixed your code to what I suggested, watch this
<?php
try
{
$sql = 'SELECT
parks.id,
parks.state,
parks.name,
parks.description,
parks.site,
parks.sname,
parks.street,
parks.city,
parks.zip,
parks.phone,
comments.comment,
comments.commentname,
events.event,
events.date,
events.description2,
photos.type,
photos.filename,
photos.big
FROM
parks
LEFT JOIN comments ON comments.parkid = parks.id
LEFT JOIN photos ON photos.parkid = parks.id
LEFT JOIN events ON events.parkid = parks.id
ORDER BY
parks.name ASC';
$result = $pdo->query($sql);
}
catch (PDOException $e)
{
$error = 'Error fetching data: ' . $e->getMessage();
include 'output.html.php';
exit();
}
//This is pulling the information from the database for display. On the foreach it will display each
//line until there are no more lines to display.
$datas = array();
foreach ( $result as $row )
{
// we didn't add this park yet
if ( !array_key_exists( $row['id'], $datas )
{
$datas[$row['id']] = array (
'id' => $row['id'],
'state' => $row['state'],
'name' => $row['name'],
'description' => $row['description'],
'site' => $row['site'],
'sname' => $row['sname'],
'street' => $row['street'],
'city' => $row['city'],
'phone' => $row['phone'],
'zip' => $row['zip'],
'comments' => array(),
'photos' => array(),
'events' => array()
);
}
// if there is no comment for this park, this will be null
if ( $row['comment'] )
{
$datas[$row['id']]['comments'][] = array (
'comment' => $row['comment'],
'commentname' => $row['commentname']
);
}
// same for photos
if ( $row['filename'] )
{
$datas[$row['id']]['photos'][] = array (
'type' => $row['type']
'filename' => $row['filename']
'big' => $row['big']
);
}
// same for events
if ( $row['event'] )
{
$datas[$row['id']]['events'][] = array (
'event' => $row['event'],
'date' => $row['date'],
'description2' => $row['description2']
);
}
}
include 'writing.html.php';
and writing.html.php
<?php
foreach ($datas as $park)
{
// do you only want to display PA?
// then add " WHERE state = 'PA' " to your query
if ($park['state'] === 'PA')
{
?>
Back to top
<input type="hidden" name="id" value="' . $park['id'] . '" />
<h1 id="name"> <?php echo ($park['name']) ?> </h1>
<p id="descriptionlist">
<?php echo ($park['description']) ?>
<br />
<ul id="link">
<li class="l1">
<?php echo $park['sname'] ?>
</li>
</ul>
</p>
<h2>Location</h2>
<div class = "loc">
<p class="loct">
<a class = "fancyImg" href="maps/<?php echo $park['id'] ?>state.gif"> <img src= "maps/<?php echo $park['id'] ?>state.gif"> </a>
<br />
<php echo ($park['street']) . ?>
<br />
<?php echo ($park['city']) .
($park['state']) .
($park['zip']) ?>
<br>
<?php echo ($park['phone']) ?>
<br> <br>
</p>
</div>
<h2>Trail Map</h2>
<div class = "map">
<p class = "mapt">
Click to Enlarge
<a class ="fancyImg" href= "/maps/<?php echo $park['id'] ?>maplink.gif">
<img src= "/maps/<?php echo $park['id'] ?>.gif"></a> <br> <br>
</p>
</div>
<?php if ( !empty( $park['photos'] ) ): ?>
<h2>Photos</h2>
<?php foreach( $park['photos'] as $photo ): ?>
<div class = "pho">
<p class = "phot">
<a class = "fancyImg" href= "/assets/indiv/<?php echo $photo['big'] ?>.gif">
<img src= "<?php echo $photo['filename'] ?>.gif"></a>**
Submit <i>your</i> photos of <?php echo ($photo['name']) ?> through our <ul id = "link"><li>Facebook Page!</li></ul></h3><p> Or go to our Contact Us page for information on how to e-mail us your favorite pictures!
</p>
</div>
<?php endforeach; ?>
<?php endif; ?>
<?php if ( !empty( $park['comments'] ) ): ?>
<h2>Comments</h2>
<?php foreach( $park['comments'] as $comment ): ?>
<?php echo $comment['comment']; ?>
<?php endforeach; ?>
<?php endif; ?>
<?php if ( !empty( $park['events'] ) ): ?>
<h2>Events</h2>
<?php foreach( $park['events'] as $event ): ?>
<?php echo $event['event']; ?>
<?php endforeach; ?>
<?php endif; ?>
<?php
}
}
EDIT 3:
What you need to understand is, that you can only return a two-dimensional result table from the database. So how would you return 10 photos for one park if your park would not be repeated? Right, that's not ( cleanly ) possible. That's why you have to filter the duplicate rows and only take the photos, comments and events once you got your park.
In the code above I use the unique park id as array index so I can determine wether this park is already in the datas array or not, then add photos, events and comments.
If you do print_r( $results ) and compare this to print_r( $datas ) you'll understand the whole thing
Unless every one of the parks has at least one comment and one photo, your query won't return rows for all parks. This is how INNER JOIN works, it only takes the intersection of all the rows that match according to the join criteria you specify.
If you want to display all parks, regardless of whether or not they have comments and/or photos, may I suggest you use LEFT JOIN instead:
SELECT
parks.id,
parks.state,
parks.name,
parks.description,
parks.site,
parks.sname,
parks.street,
parks.city,
parks.zip,
parks.phone,
comments.comment,
comments.commentname,
events.event,
events.date,
events.description2,
photos.parkid,
photos.type,
photos.filename,
photos.big
FROM
parks
LEFT JOIN comments ON (parks.parkid = comments.parkid)
LEFT JOIN photos ON (parks.parkid = photos.parkid)
LEFT JOIN events ON (parks.parkid = events.parkid)
ORDER BY
parks.name asc
EDIT:
I removed the GROUP BY clause since I'm pretty sure it's not what you want; you'll probably want to see every photo or comment associated with a park, not have them all arbitrarily reduced to a single row for each park.
EDIT:
Using this query should solve any problems you might have had with the original query not returning the rows you were expecting for comments and photos. You had said that the relationship was 1 park to many comments and many photos. This query should return every comment and photo associated with each park, but there will be multiple rows returned for each park. You'll need to adjust your code to compensate for this, perhaps by creating an array of park data, where each element in the array corresponds to a single park. Each element should also contain an array of comments and photos, for which there might be more than one for each park.
Each iteration over the result set should be prepared to create a new element in the park data array, or recognize that the current result set row corresponds to a park whose data you've already begun to build. Additionally, if there are any comments or photos in the current iteration, they should be added to the current (new or existing) park's array of comments and/or photos. Here's an example foreach loop of how to do this:
$parks = array();
foreach ($result as $row) {
// Create a new element in $parks because it's not in the $parks array yet
if (! array_key_exists($row['id'], $parks)) {
$park = array();
$park['id'] = $row['id'];
$park['state'] = $row['state'];
$park['name'] = $row['name'];
$park['description'] = $row['description'];
$park['site'] = $row['site'];
$park['sname'] = $row['sname'];
$park['street'] = $row['street'];
$park['city'] = $row['city'];
$park['zip'] = $row['zip'];
$park['phone'] = $row['phone'];
$park['comments'] = array();
$park['photos'] = array();
$parks[$row['id']] = $park;
} else {
// Otherwise, this is a park we've already seen
$park = $parks[$row['id']];
}
// If there are comments in this result set row, add them
if ($row['comment'] || $row['commentname']) {
$park['comments'][] = array(
'comment' => $row['comment'],
'commentname' => $row['commentname']
);
}
// If there are photos in this result set row, add them
if ($row['type'] || $row['filename'] || $row['big']) {
$park['photos'][] = array(
'type' => $row['type'],
'filename' => $row['filename'],
'big' => $row['big']
);
}
}
This code isn't that pretty or well-factored, and it could certainly be improved. I just hastily threw it together to give you an example of how to build such a structure.
Relational data doesn't always map cleanly to hierarchical object graphs, this is the object-relational impedance mismatch.
To get all rows in one array instead of the first foreach loop try using <?$datas = $pdo->fetchAll();?>

PHP Form from Array Select Value Edit/Save

I'm using an array to output a form for product entry.
$labels = array(
"category" => "Model",
"model_number" => "Model No.",
"description" => "Description");
The categories are populated as select/option set, which is easy when adding a new product. The issue comes when I need to edit the product. I would like to query the category table to return all the available categories to populate the select/option set. At the same time, I need to query the products table so that I can provide their saved Model Number and Description.
The following is my code from the add form to give you an idea of how I'm structuring this.
foreach($labels as $field => $label) {
if($field == "category") {
echo "<label>$label:</label>";
echo "<select name=\"$field\">";
while($row=mysqli_fetch_assoc($result)) {
extract($row);
echo "<option value=\"$category\">$category</option>";
}
echo "</select>";
echo "<br />";
}
else {
echo "<label>$label:</label>";
echo "<input type=\"text\" name=\"$field\" />";
echo "<br />";
}
Thanks for the help. I'm sure it's simple, but my brain isn't quite providing me with the solution at the moment.
Having $labels array is a bad idea.
Get all your data first. Select your product data into array. Select your categories into array.
Show the form, as any other HTML you create with PHP
<label>Model:</label>
<select name="category">
<? foreach($cats as $category): ?>
<option<? if ($category == $row['category'])?> selected?>><?=$category?></option>
<? endforeach ?>
</select>
<br />
<label>Model No.:</label>
<input type="text" name="model_number" value="<?=$row['model_number']?>"/>
<br />
and so on
don't forget to htmlspecialchars() your values before placing them into value attribute
you can query the product table like this:
$sql = "SELECT * FROM products WHERE product_id = $product_id";
$q = mysql_query( $sql );
$row = mysql_fetch_assoc( $q );
$model_number = $row['model_number'];
$description = $row['description'];
$category = $row['category'];

How do I create this array? (PHP)

I am a little stuck on how to create this array.
My data:
category_id | category_name
1 bikes
2 cars
3 books
4 computers
Array:
$category=array();
$query = "SELECT * FROM categories ORDER BY name ASC";
$result = $db->query($query);
$category=array('category_id'=>$category_id, 'category_name'=>$category_name);
while ($row = $result->fetch_array()){
$category_id=$row['category_id'];
$category_name=$row['name'];
}
I want to create an array so that I can echo the data in a radio list like...
<input type='radio' value='<?PHP echo $category['category_id']; ?>'
name='category[]'><?PHP echo $category['category_name']; ?>
o bikes
o cars
o books
o computers
The problem is that the array only consists of one pair (1, bikes) and not all the data.
How can I make an array with all the data?
Thanks!
You are doing three things wrong, first you are not actually setting $category to equal anything - only the values of two undefined values, which default to null. So you end up with an array like:
array('category_id' => null, 'name' => null)
Second, you are doing nothing with the values of $category_id and $category_name when you do set them. Next, you are not going through the array item by item, you simply output the initial way it was set - which is linked to another problem that your array is short of a dimension. It should be 2-dimensional, not 1-dimensional.
This code sums up the gist of it all. I would suggest reading up on how arrays work in PHP and how to define them, they're a very commonly used data type throughout frameworks and the like.
$query = "SELECT * FROM categories ORDER BY name ASC";
$result = $db->query($query);
$categories=array();
while ($row = $result->fetch_array()){
$categories[] = array('category_id' => $row['category_id'], 'category_name' => $row['name']);
}
Then when you need to output:
foreach ( $categories as $category ) {
?>
<input type='radio' value='<?php echo $category['category_id']; ?>' name='category[]'><?php echo $category['category_name']; ?>
<?php
}
This can of course be cleaned up further.
That is because you are echoing out side of the loop there by giving you only first row records eg bikes, you should do like:
$category=array();
$query = "SELECT * FROM categories ORDER BY name ASC";
$result = $db->query($query);
$category=array('category_id'=>$category_id, 'category_name'=>$category_name);
while ($row = $result->fetch_array()){
$category_id=$row['category_id'];
$category_name=$row['name'];
?>
<input type='radio' value='<?PHP echo $category['category_id']; ?>'
name='category[]'><?PHP echo $category['category_name']; ?>
<?php
}
You are assigning to variables $category_id and $category_name, rather than to the array $category, so you're only seeing the first row returned from the query.
I normally use PDO, and would write it something like this:
<?php
$db = ...
$sql = 'SELECT * FROM categories ORDER BY category_name ASC';
$categories = $db->query($sql);
?>
<html>
<body>
<? foreach ($categories as $category): ?>
<input type="radio" name="category[]" value="<?= $category->category_id ?>">
<?= $category->category_name ?>
</input>
<? endforeach ?>
</body>
</html>

Categories