I've got two tables. Skills, that contains all the available skills.
and user_skills, that contains which skills user got.
I need to output all the available skills, and those skills that the user have (I select it by session['username']) will be marked (checked checkbox).
$get_all_skills = mysqli_query($conn, "SELECT * FROM skills");
$web_design = array();
$web_develop = array();
$automation = array();
$security = array();
while($show_row = mysqli_fetch_array($get_all_skills)){
switch($show_row['skill_type']){
case '1':
array_push($web_design, $show_row['skill_name']);
break;
case '4':
array_push($web_develop, $show_row['skill_name']);
break;
case '3':
array_push($automation, $show_row['skill_name']);
break;
case '2':
array_push($security, $show_row['skill_name']);
break;
}
}
How can possibly I make this work?
Part of the html is:
<div class="">
<ul class="to_do">
<?php
for($i=0;$i<count($web_develop);$i++){
?>
<li>
<p>
<input type="checkbox" class="flat"> <?php echo $web_develop[$i];?> </p>
</li>
<?php } ?>
</ul>
</div>
Considering you have a user_skills array ($user_skills_array) declared and have the data, use the below html code
<div class="">
<ul class="to_do">
<?php
for($i=0;$i<count($web_develop);$i++){
// check the global skill is available in the user skill set
$checked = (in_array($web_develop[$i], $user_skills_array)) ? 'checked="checked"': '';
?>
<li>
<p>
<input type="checkbox" class="flat" <?php echo $checked;?>> <?php echo $web_develop[$i];?> </p>
</li>
<?php } ?>
</ul>
</div>
try the following, explanation below.
<?php
$get_all_skills = mysqli_query($conn, "SELECT * FROM skills");
$availableSkills = [];
$skillTypes = [
1 => 'Webdesign',
2 => 'Security',
3 => 'Automation',
4 => 'Web Development',
];
while($show_row = mysqli_fetch_array($get_all_skills)){
$skill = [
'id' => $show_row['id'];
'name' => $show_row['name'];
];
$skillType = $show_row['skill_type'];
$availableSkills[$skillType][] = $skill;
}
// assuming user_skills:
$userSkills = [
1,
2,
5,
8
];
?>
<ul class="to_do">
<?php foreach ($availableSkills as $type => $skillsForType) : ?>
<li>
<?= $skillTypes[$type] ?>
<ul>
<?php foreach ($skillsForType as $skill) : ?>
<li>
<input
type="checkbox"
class="flat"
name="skill[<?= $type ?>]"
value="<?= $skill['id'] ?>"
<?= in_array($skill['id'], $userSkills) ? 'checked="checked"' : ''
> <?= $skill['name'] ?>
</li>
<?php endforeach; ?>
</ul>
</li>
<?php endforeach; ?>
</ul>
First you gather all skills, as have you already done.
Next I optimized your different skills array into one and listed all skill types.
The available skills are indexed by their type id (see $skillTypes).
Next I assumed your user-skill collection could be like shown.
In the HTML section I am iterating over every skill type and in a nested foreach echo all corresponding skills.
If the skill id of the current iteration is in_array of the user-skill-relation the "checked" attribute is set.
To clarify I used short syntax in this example.
[] --> array()
<?= --> <?php echo
foreach () : endforeach;
Related
I am having problems pulling the pages through in PHP and HTML I have used :-
<li>
<!-- Pulling Categories from the database
dynamically -->
<?php
$nav_subjects = find_all_subjects(['visible' => $visible]);
while($nav_subject =
mysqli_fetch_assoc($nav_subjects)) {
?>
<span class="opener"><?php echo h($nav_subject['menu_name']); ?></span>
Which pulls the categories dynamically from the database and displays them with a drop down arrow just how I wanted but the pages will not show underneath them here's the code I have used for that bit:-
<!-- Categories listed correctly let's pull the pages for each one -->
<?php
if($nav_subject['id'] == $subject_id) {
$nav_pages = find_pages_by_subject_id($nav_subject['id'], ['visible' => $visible]);
while($nav_page = mysqli_fetch_assoc($nav_pages)) {
?>
<ul>
<li>
<?php echo h($nav_page['menu_name']); ?>
</li>
</ul>
<?php } // while $nav_pages
} // if($nav_subject['id'] == $subject_id)
} // while $nav_subjects ?>
</li>
<?php
mysqli_free_result($nav_subjects);
mysqli_free_result($nav_pages);
?>
I am pulling in the SQL from another page which is loaded correctly as the categories load and display correctly.
I will be grateful for any ideas.
I have also tried to echo back the sql result but nothing is shown.
I have now got it working with the following code:-
<li>
<?php $nav_subjects = find_all_subjects(['visible' => $visible]);
while($nav_subject = mysqli_fetch_assoc($nav_subjects)) {?>
<span class="opener"><?php echo h($nav_subject['menu_name']); ?></span>
<ul>
<?php if($nav_subject['id'] == $subject_id);
$nav_pages = find_pages_by_subject_id($nav_subject['id'], ['visible' => $visible]);
while($nav_page = mysqli_fetch_assoc($nav_pages)) { ?>
<li><?php echo h($nav_page['menu_name']); ?></li>
<?php } ?>
<?php } ?>
</ul>
But now it is listing the secondary subjects as a child of the first instead of individual subjects of their own.
*********Resolved**********
please advise if you think the code could be better i've currently used :-
<li>
<?php $nav_subjects = find_all_subjects(['visible' => $visible]);?>
<?php while($nav_subject = mysqli_fetch_assoc($nav_subjects)){?>
<span class="opener"><?php echo h($nav_subject['menu_name']);?></span>
<ul>
<?php if($nav_subject['id'] == $subject_id);
$nav_pages = find_pages_by_subject_id($nav_subject['id'], ['visible' => $visible]);
while($nav_page = mysqli_fetch_assoc($nav_pages)) { ?>
<a href="<?php echo url_for('index.php?id=' . h(u($nav_page['id']))); ?>">
<?php echo h($nav_page['menu_name']); ?></a>
<?php } ?>
<?php mysqli_free_result($nav_pages); ?>
</ul>
<?php } ?>
<?php mysqli_free_result($nav_subjects); ?>
</li>
im trying to make a loop in php that spits out the below
$sqlons = "SELECT * FROM products WHERE ons = 1";
$ons = $db->query($sqlons);
$sqlpopa = "SELECT * FROM products WHERE popa = 1";
$popa = $db->query($sqlpopa);
$sqlnewr = "SELECT * FROM products WHERE newr = 1";
$newr = $db->query($sqlnewr);
$sqlpopm = "SELECT * FROM products WHERE popm = 1";
$popm = $db->query($sqlpopm);
$sqlpopm2 = "SELECT * FROM products WHERE popm = 2";
$popm2 = $db->query($sqlpopm2);
$sqlfeata = "SELECT * FROM products WHERE feata = 1";
$feata = $db->query($sqlfeata);
$sqlfeata2 = "SELECT * FROM products WHERE feata = 2";
$feata2 = $db->query($sqlfeata2);
$sqlbests = "SELECT * FROM products WHERE bests = 1";
$bests = $db->query($sqlbests);
$sqlbests2 = "SELECT * FROM products WHERE bests = 2";
$bests2 = $db->query($sqlbests2);
$sqlbests3 = "SELECT * FROM products WHERE bests = 3";
$bests3 = $db->query($sqlbests3);
$sqlsea = "SELECT * FROM products WHERE sea = 1";
$sea = $db->query($sqlsea);
i've currently done this
$vart = array("sqlons", "sqlpopa", "sqlnewr", "sqlpopm", "sqlfeata", "sqlbests", "sqlsea");
$vart2 = array("ons", "popa", "newr", "popm", "feata", "bests", "sea");
$var = array("ons", "popa", "newr", "popm", "popm", "feata", "feata", "bests", "bests", "bests", "sea");
$var2 = array("1", "1", "1", "1", "2", "1", "2", "1", "2", "3", "1");
foreach($var as $v){
foreach($var2 as $v2){
foreach($vart as $t){
"$".$t = "SELECT * FROM products WHERE $v = $v2";
foreach($vart2 as $t2){
"$".$t2 = $db->query("$".$t);
}
}
}
}
but i get an undefined variable such a "Undefined variable: ons in C:\xampp\htdocs\AniBuy\pages\index.php
on line 90"
please help me! :)
sorry this might of helped if i added the html/php code
<?php while($product = mysqli_fetch_assoc($ons)) : ?>
<div class="<?= $product['class']; ?>">
<div class="grid-col-1">
<img class="featured-image img-responsive" src="<?= $product['img']; ?>">
</div>
<div class="grid-col-2">
<h2 class="featured-heading"><?= $product['title']; ?></h2>
<div class="grid-col-3">
<div class="span-text"><?= $product['about']; ?><br></div><div class="buy-now">BUY NOW</div>
</div>
</div>
</div>
<?php endwhile; ?>
there is more then just one there are multiple of theses that spit out the img title ect each from the phpmyadmin database
<?php while($product = mysqli_fetch_assoc($popa)) : ?>
<div class="<?= $product['class']; ?>">
<div class="buy-now buy">BUY NOW</div>
<div h4 class="read-more" onclick="rmModal(<?= $product['id'];?>)">READ MORE</div>
<div class="featured-image"><img class="featured-image img-pop-anime img-responsive" src="<?= $product['img']; ?>"></div>
</div>
<?php endwhile; ?>
<?php while($product = mysqli_fetch_assoc($newr)) : ?>
<div class="<?= $product['class']; ?>">
<div class="buy-now buy">BUY NOW</div>
<div h4 class="read-more" onclick="rmModal(<?= $product['id'];?>)">READ MORE</div>
<div class="grid-col-1"><img class="featured-image img-new" src="<?= $product['img']; ?>"></div>
</div>
<?php endwhile; ?>
so far i have tried this
$vars = array("ons" => 1, "popa" => 1, "newr" => 1);
foreach ($vars as $key => $value) {
"$"."sql".$key = "SELECT * FROM products WHERE $key = $value";
"$".$key = $db->query("$"."sql".$key);
// echo "$"."sql".$key;
// echo $value;
// echo "$".$key;
}
but it sill gives me the error
mysqli_fetch_assoc() expects parameter 1 to be mysqli_result, string given in
C:\xampp\htdocs\AniBuy\pages\index.php
on line 142
if anyone is interested in what the website looks like here's the url it only has html, css and js: https://54x1.github.io/AniBuy/pages/indexv2.html
here are the files with php and mysql i've included the sql export in side the anibuy folder btw its .../pages/index.php: https://drive.google.com/drive/folders/1mUYm2sH1bsxF3UaCxAvOIwTkubLCoVod?usp=sharing
your problem is that you're using strings as code in lines like:
"$".$t = "SELECT * FROM products WHERE $v = $v2";
and:
"$".$t2 = $db->query("$".$t);
what you need to do is to put the code inside eval() function like this:
eval('$'.$t.' = "SELECT * FROM products WHERE $var$v = $v2";');
and I think you will have another problem with all the foreach loops you're using I think since all your arrays have the same number of elements you should do something like this:
for ($i=0; $i <count($vart) ; $i++) {
eval('$'.$vart[$i].' = "SELECT * FROM products WHERE $var[$i] = $var2[$i]";');
eval("$".$vart2[$i] .'= $db->query("$".$vart[$i]);');
}
try it and tell me how it worked out for you
Wrap $v like this {$v} when it's in the query string.
You should also redesign your arrays:
$vars = ["ons" => 1, "popa" => 1, ... ];
$results = [];
foreach($vars as $vkey => $vval){
$results[$vkey] = $db->query("SELECT * FROM products WHERE {$vkey} = {$vval}")->fetch_assoc();
}
Edited: Added fetch_assoc() call, assuming you are only getting one row back. Otherwise you'll have to use a nested while:
$vars = ["ons" => 1, "popa" => 1, ... ];
$results = [];
foreach($vars as $vkey => $vval){
$results[$vkey] = [];
$result = $db->query("SELECT * FROM products WHERE {$vkey} = {$vval}");
while($row=$result->fetch_assoc()){
$results[$vkey][] = $row;
}
}
The error that was triggered on your side, it's weird because when I run your code on my side, I did not get it.
In the first array add all your fields names and values where ons is the field name and 1 is the value for the where condition. Do the same for the others.
$key = fields names in database
$value = value of field name
// As you have different values for bests, 1, 2, 3 and for others
// If we used bests as index ex: array('bests' => 2, 'bests' => 3). The data
// will be overwritten by the next bests as they have the same index.
// 'fieldname_value' where fieldname = ons and value = 1
$vars = array('ons_1', 'bests_1', 'bests_2', 'bests_3');
$results = array();
foreach ($vars as $key => $value) {
// Here I break the value which is ex: ons_1 into
// an array(ons, 1). This will repeat for the other values.
$values = explode('_', $value);
$sql = "SELECT * FROM products WHERE $values[0] = $values[1]"; // $values[0] = fieldname $values[1] = value_of_fieldname
$result = mysqli_query($db, $sql);
if (mysqli_num_rows($result) > 0) {
// output data of each row
while($row = mysqli_fetch_assoc($result)) {
$results[$value][] = $row; // Add all rows for fieldnames (ex: ons_1, bests_1, bests_2) inside $result array
}
}
}
/**
*
* First var_dump($results); to get a clearer view of what's going on below
*
* The array $results contain an array of arrays
* Ex: $results = array ('ons_1' => array( 0 => array('class' => your_class), 'bests_1' => array( 0 => array('class' => your_class))
*
* This if line checks whether the index exist isset($results['ons_1']) and if it is not empty !empty($results['ons_1'])
* before doing the foreach loop. It would be unecessary to do a foreach loop that will trigger an error if ons_1 does
* not exist and has no data. This is why this check is done.
*
* The foreach loop on the other hand will loop through all the data present in 'ons_1' array. var_dump($result['ons_1']); to
* have an idea of what's going ons.
*
*/
?>
<div class="grid-container container-fluid ">
<div id="home-page" class="home-page">
<h2 class="featured-heading-2">On Sale Now!</h2>
<div class="home-page-onsale">
<?php if (isset($results['ons_1']) && !empty($results['ons_1'])) { ?>
<?php foreach ($results['ons_1'] as $key => $product) { ?>
<div class="<?php echo $product['class']; ?>">
<div class="buy-now buy">BUY NOW</div>
<div h4 class="read-more" onclick="rmModal(<?php echo $product['id']; ?>)">READ MORE</div>
<div class="grid-col-1"><img class="featured-image img-new" src="<?php echo $product['img']; ?>"></div>
</div>
<?php } ?>
<?php }?>
</div>
<div class="breakpoint-3">
<div class="home-page-best-anime">
<h2 id="home-page-best-anime bpshow" class="featured-heading-2">Best Sellers</h2>
<div class="home-page-best-anime-row-1">
<?php if (isset($results['bests_1']) && !empty($results['bests_1'])) { ?>
<?php foreach ($results['bests_1'] as $key => $product) { ?>
<div class="<?php echo $product['class']; ?>">
<div class="buy-now buy">BUY NOW</div>
<div h4 class="read-more" onclick="rmModal(<?php echo $product['id']; ?>)">READ MORE</div>
<div class="grid-col-1"><img class="featured-image img-new" src="<?php echo $product['img']; ?>"></div>
</div>
<?php } ?>
<?php }?>
</div>
<div class="home-page-best-anime-row-2">
<?php if (isset($results['bests_2']) && !empty($results['bests_2'])) { ?>
<?php foreach ($results['bests_2'] as $key => $product) { ?>
<div class="<?php echo $product['class']; ?>">
<div class="buy-now buy">BUY NOW</div>
<div h4 class="read-more" onclick="rmModal(<?php echo $product['id']; ?>)">READ MORE</div>
<div class="grid-col-1"><img class="featured-image img-new" src="<?php echo $product['img']; ?>"></div>
</div>
<?php } ?>
<?php }?>
</div>
<div class="home-page-best-anime-row-3">
<?php if (isset($results['bests_3']) && !empty($results['bests_3'])) { ?>
<?php foreach ($results['bests_3'] as $key => $product) { ?>
<div class="<?php echo $product['class']; ?>">
<div class="buy-now buy">BUY NOW</div>
<div h4 class="read-more" onclick="rmModal(<?php echo $product['id']; ?>)">READ MORE</div>
<div class="grid-col-1"><img class="featured-image img-new" src="<?php echo $product['img']; ?>"></div>
</div>
<?php } ?>
<?php }?>
</div>
</div>
</div>
</div>
</div>
In your foreach loop, what is the $v variable? It does not appear to be defined anywhere.
"$".$t = "SELECT * FROM products WHERE $v = $v2";
Given your comment, you've got the correct basic idea, but the implementation can actually be a lot simpler than you've got it. First of all, your "control" values, i.e. the arrays $vart etc. are in a format known as a Structure of Arrays, while you'll probably find this a lot easier with an Array of Structures.
The problem you've got with a Structure of Arrays is that you've got multiple nested loops trying to iterate over them, when you really want to advance along all four arrays in parallel - that problem largely vanishes if you use an Array of Structures.
So change that data to look something like this:
$vars = array(
array(
"select" => "ons",
"compare" => "1",
"result" => "ons"
),
// etc. etc.
array(
"select" => "bests",
"compare" => "2",
"result" => "bests2"
),
// ...
select while be the left hand side of the SELECT clause, compare will be the right hand side, and result will be where the data lands.
Now craft the loop like this:
foreach ($vars as $sqldata) {
$select = $sqldata->select;
$compare = $sqldata->compare;
$result = $sqldata->result;
$$result = $db->query("SELECT * FROM products WHERE $select = $compare");
}
And yes, I did mean two '$'s in the last line. That should get you where you want to be, with one caveat. You'll need to do something to get the target variables to exist before entering this, if not your results in $$result will go out of scope the moment you exit the foreach loop.
Either that, or create an empty array before starting, and store the results in that array as you go.
I am setting this array, and for the most part it works properly in my site. NOTE: This is a Joomla site and a VirtueMart PHP file for the email that the customer receives when ordering a product.
$addressBTOrder = array('email{br}', 'company{br}', 'title', 'first_name', 'last_name{br}', 'address_1{br}', 'address_2{br}', 'city', 'virtuemart_state_id', 'zip{br}', 'virtuemart_country_id{br}', 'phone_1{br}', 'phone_2{br}');
However, I need to add a comma (,) after CITY in the array to actually display a comma in the final output. If I just put the comma after city:
'city,'
... it does not work and the city output just doesn't display at all. I also tried the hex value for comma (%2c) but it didn't work either.
Here is the code that is creating the output:
<?php
foreach ($addressBTOrder as $fieldname) {
$fieldinfo = explode('{',$fieldname);
if (!empty($this->userfields['fields'][$fieldinfo[0]]['value'])) { ?>
<span class="values vm2<?php echo '-' . $this->userfields['fields'][$fieldinfo[0]]['name'] ?>" ><?php echo $this->escape($this->userfields['fields'][$fieldinfo[0]]['value']) ?></span> <?php
if (isset($fieldinfo[1]) && $fieldinfo[1] == 'br}') { ?>
<br class="clear" /> <?php
}
}
}
?>
What code do I need to put there to display a comma in the final output? For instance, I am making the line break work by using {br}. Thanks!
What I'm getting from your code is that you want to specify some sort of suffix after each output of the corresponding userfield value.
A differentapproach is to make use of your CSS classes. This means you can properly style your content without adding extra elements.
For example, going back to your original array without anything extra
$addressBTOrder = ['email', 'company', 'title', 'city', ...];
foreach ($addressBTOrder as $field) :
$userField = $this->userfields['fields'][$field];
if (!empty($userField['value'])) : ?>
<span class="values vm2-<?= $userField['name'] ?>">
<?= $this->escape($userField['value']) ?>
</span>
<?php endif; endforeach ?>
and, since you're already adding CSS classes which I'm guessing are like vm2-email, vm2-company, etc...
.vm2-email, .vm2-company {
display: block; /* same as adding a newline */
}
.vm2-city:after {
content: ",";
}
Original answer here...
I would recommend using a more succinct data format. For example
$br = '<br class="clear" />';
$addressBTOrder = [[
'key' => 'email',
'suffix' => $br
], [
'key' => 'company',
'suffix' => $br
], [
'key' => 'title',
'suffix' => ''
], /* etc */ [
'key' => 'city',
'suffix' => ','
]];
then you can iterate like this...
<?php foreach ($addressBTOrder as $field) :
$userField = $this->userfields['fields'][$field['key']];
if (!empty($userField['value'])) : ?>
<span class="values vm2-<?= $userField['name'] ?>">
<?= $this->escape($userField['value']), $field['suffix'] ?>
</span>
<?php endif; endforeach ?>
It's more clean and easy to design the view exactly you want instead of try to do this with code. For example something like this:
<?php if(!empty($this->userfields['fields']['email']['value'])): ?>
<span class="values vm2-email">
<?= $this->escape($this->userfields['fields']['email']['value']) ?></span>
</span>
<br class="clear" />
<?php endif; ?>
<?php if(!empty($this->userfields['fields']['city']['value'])): ?>
<span class="values vm2-city">
<?= $this->escape($this->userfields['fields']['city']['value']) ?>, </span>
</span>
<?php endif; ?>
<?php if(!empty($this->userfields['fields']['virtuemart_state_id']['value'])): ?>
<span class="values vm2-virtuemart_state_id">
<?= $this->escape($this->userfields['fields']['virtuemart_state_id']['value']) ?></span>
</span>
<?php endif; ?>
The problem is that you're expecting everything before { in the array element to be a key in the $this->userfields['fields'] array. But when you have a comma there, it doesn't match the array keys. So you need to remove the comma before using it as a key. And if it has a comma, you need to add that to the output.
foreach ($addressBTOrder as $fieldname) {
$fieldinfo = explode('{',$fieldname);
$name = $fieldinfo[0];
if ($name[-1] == ",") {
$comma = ",";
$name = substr($name, 0, -1);
} else {
$comma = "";
}
if (!empty($this->userfields['fields'][$name]['value'])) { ?>
<span class="values vm2<?php echo '-' . $this->userfields['fields'][$name]]['name'] ?>" ><?php echo $this->escape($this->userfields['fields'][$name]['value']) . $comma; ?></span> <?php
if (isset($fieldinfo[1]) && $fieldinfo[1] == 'br}') { ?>
<br class="clear" /> <?php
}
}
}
I am populating data from database to radio button and want to check the first value as default but I have no idea on how to do it. Here is my coding that I've done so far.
View
<?php if($designThemes != null){; ?>
<?php foreach ($designThemes as $designTheme) { ?>
<?php
$designThemesValue = (set_value('theme_name') ? set_value('theme_name') : $designTheme['slug_url']);
$designThemesAttr = array(
'name' => 'designThemes',
'value' => $designThemesValue,
);
?>
<div class="col-md-4 col-sm-4">
<div class="radio custom-radio">
<label>
<?php echo form_radio($designThemesAttr); ?>
<span class="fa fa-circle"></span> <?php echo $designTheme['theme_name'] ?>
</label>
</div>
</div>
<?php }}; ?>
If I add 'checked' => TRUE in $designThemesAttr = array() the system will check the last value of radio button as the default, but I wanted to check the first value.
solved your issue you can set it by conditional statement as replace your code by this
<?php if($designThemes != null){; ?>
<?php $i=1;foreach ($designThemes as $designTheme) { ?>
<?php
$designThemesValue = (set_value('theme_name') ? set_value('theme_name') : $designTheme['slug_url']);
$designThemesAttr = array(
'name' => 'designThemes',
'value' => $designThemesValue,
);
if($i==1){
$designThemesAttr['checked'] = TRUE;
}
?>
<div class="col-md-4 col-sm-4">
<div class="radio custom-radio">
<label>
<?php echo form_radio($designThemesAttr); ?>
<span class="fa fa-circle"></span> <?php echo $designTheme['theme_name'] ?>
</label>
</div>
</div>
<?php $i++; }}; ?>
'checked' => TRUE in $designThemesAttr = array() the system will check the last value of radio button as the default. This is right, because you doing it inside a for loop, and only one radio remains selected inside a group. So the last one is showing checked.
So maintain a variable to count the iteration like:
$count = 1;
if( $count = 1; )
{
// use 'checked' => TRUE here
$count++; // The value is incremented so that the if condition can't run again. This will add 'checked' => TRUE to first radio only.
}
I am trying to keep presentation and logic separate without using a template engine like Smarty. What I have so far is working, but I am not sure how to do certain things without putting more PHP into my presentation than I would like to. For example, right now I have something like this:
product_list.php
try {
$query = $conn->prepare("SELECT p.id, p.name, p.description, IFNULL(url, title) AS url, GROUP_CONCAT(c.category SEPARATOR ', ') AS category,
FROM products p
LEFT JOIN product_categories pc ON p.id = pc.product_id
LEFT JOIN categories c ON pc.category_id = c.id
WHERE p.active = 1
GROUP BY p.id");
$query->execute();
$result = $query->fetchAll(PDO::FETCH_ASSOC);
}
catch (PDOException $e) {
echo $e->getMessage();
}
include('templates/product_list_tpl.php');
product_list_tpl.php
<div class="card">
<div class="product-list with-header">
<div class="product-list-header center-align">
<h2><?= $header_title; ?></h2>
</div>
<?php foreach ($result as $row): ?>
<!-- Some Product Info -->
Category: <?= $row['category']; ?>
<?php endforeach; ?>
</div>
</div>
In the above example some products will have one category, some will have multiple. They display nicely in a comma separated list, but I would like to make the category names into links. I know I can do something like below, but it seems messy to me.
<div class="card">
<div class="product-list with-header">
<div class="product-list-header center-align">
<h2><?= $div_title; ?></h2>
</div>
<?php foreach ($result as $row): ?>
<?php $categories = explode(', ', $row['category']); ?>
<div class="product-list-item avatar">
<img src="img/product/<?= $row['id']; ?>.jpg" alt="<?= $row['title']; ?>" class="square">
<?= $row['title']; ?>
<p class="caption"><?= $row['caption']; ?></p>
<div class="item-bottom">
<span class="responsive"><?= $row['description']; ?></span>
<p>
Category:
<?php foreach ($categories as $key => $category): ?>
<?= $category; ?>
<?= (sizeof($categories) > 1 && $key == end($categories)) ? ', ' : ''; ?>
<?php endforeach; ?>
</p>
<p>
<span>Rating: <?= $row['rating']; ?></span>
<span class="right">Rated <?= $row['rated']; echo ($row['rated'] == 1) ? ' time' : ' times'; ?></span>
</p>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
Thank you in advance for any suggestions. Also, if anyone has any input on the general separation format I used on the example code I would love to hear it. I am just getting back into coding after an 8 year break.
EDIT: Added missing endforeach and improved indentation on third code block as per #Devon suggested in comments.
EDIT: I updated the third code block to include HTML I previously left out and added all PHP functionality needed to achieve the output I am looking for. It works, but IMO doing it this way removes the little separation I had. I now basically just have one file with my database call and another file with this mess. I feel like I am not going in the right direction for proper business logic / presentation logic separation.
Where am I going wrong?
Lengthy, complicated logic such as:
(sizeof($categories) > 1 && $key == end($categories)) ? ', ' : '';
shouldn't be in the view to bother a front-end developer. "What is this hideous line of code?
What does it do? Why didn't the back-end developer give me something easier to work with?" Part of the power of MVC is not only in separation of concerns, but
also keeping back-end and front-end developers' work separate.
Code like <?php foreach ($result as $row): ?> contains no indication as to what it's working with. The DIVs, Ps, and SPANs are out of control as well.
This is why I'm a fan of view helpers.
I'd suggest:
product_list_tpl.php
<div class="card">
<div class="product-list with-header">
<div class="product-list-header center-align">
<h2><?= $div_title; ?></h2>
</div>
<?= displayItems($items); ?>
</div>
</div>
The view helper used above:
function displayItems($items)
{
foreach ($items as $item)
{
$categories = explode(', ', $item['category']);
$id = $item['id'];
$title = $item['title'];
$url = $item['url'];
$caption = $item['caption'];
$description = $item['description'];
$rating = $item['rating'];
$rated = $item['rated'];
include('product_list_item_tpl.php');
}
}
product_list_item_tpl.php
<div class="product-list-item avatar">
<img src="img/product/<?= $id; ?>.jpg" alt="<?= $title; ?>" class="square">
<?= $title; ?>
<p class="caption"><?= $caption; ?></p>
<div class="item-bottom">
<span class="responsive"><?= $description; ?></span>
<p>
Category:
<?php displayCategories($categories); ?>
</p>
<p>
<span>Rating: <?= $rating; ?></span>
<span class="right">Rated <?= $rated; ?> <?= isPluarl($rated)?'times':'time'; ?></span>
</p>
</div>
</div>
The view helpers used above:
function isPlural($number)
{
return $number != 1;
}
function displayCategories($categories)
{
$last = end($categories);
$count = sizeof($categories);
foreach ($categories as $key => $category)
{
$cat = strtolower($category);
$isLast = $category == $last;
include('product_list_category_tpl.php');
}
}
product_list_category_tpl.php
<?= $category; ?>
<?= ($count > 1 && !$isLast) ? ', ' : ''; ?>
Note I inverted the $key == end($categories) part from what you were using before with !$isLast and swapped $key to $category. This logic still feels dirty as two categories could have the same name. Probably better to just use count($categories) in conjunction with $i++ to decide if it's the last loop.
Edit:
This works nicely and avoids the prior mentioned issue as it relies on the key rather than the value:
function displayCategories($categories)
{
end($categories);
$last = key($categories);
$count = sizeof($categories);
foreach ($categories as $key => $category)
{
$cat = strtolower($category);
$isLast = $key == $last;
include('product_list_category_tpl.php');
}
}