I'm trying to sort out a web portfolio but can't get my head around how I can implement it, if it can!
Basically what I'm after is...
On the portfolio page, list details of the client with their name, description, TAGS (html, css, photoshop, jquery etc), COLOURS USED (black, white, blue, green etc) and services used etc.
At the moment in my client table i have:
"ID title description tags services colours client"
With this current system I have to state all the colours and services all in one row, meaning I can't separate the contents to style it with css (see below).
**I'd like to be able to show the colours used by each project as 16x16 colour blocks and the services as a <ul><li></li></ul> list.
Is this possible?
My current script can be found here:
http://davidpottrell.co.uk/paste/portfolio.txt
What I'm after (found on right of image)
http://davidpottrell.co.uk/paste/todo.png
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');
$query = $db->query('SELECT * FROM client');
foreach($query as $row) {
// I assume you're storing colours as a delimited string? (red,green,yellow)
$colours = explode(',', $row['colours']);
if (count($colours)) {
foreach ($colours as $colour) {
echo '<div class="colour_block" id="'.$colour.'"></div>';
}
}
// Same thing with services
$services = explode(',', $row['services']);
if (count($services)) {
echo '<ul>';
foreach ($services as $service) {
echo '<li id="'.$service.'">'.$service.'</div>';
}
echo '</ul>';
}
}
How are you saving the services and colors at the moment? Do you write strings like service1;service2;service3 into the service column? If so, use PHPs explode() function
$var = "service1;service2;service3";
$result = explode(";", $var);
var_dump($result)
Now you can iterate through the array and replace each service with some image/list item or whatever. It should work like that, although I didn't test it:
while($row = mysql_fetch_array($result)) {
$service_array = explode(",", $row[services]);
echo "<div class='portfolio_block'><h3>Services</h3>";
if(count($services)) {
echo "<ul>";
foreach($service_array as $service) {
echo "<li>" . $service . "</li>";
}
echo "</ul>"
}
echo "</div>";
}
I would also recommend taking Jamies advice and switch from mysql_* functions to PDO. And for "styling" the list items add some class tags :)
Related
I was hoping I could get some help with something I am struggling with. I parsing an XML feed with SimpleXML but, I am trying to remove the duplicates.
I have done a lot of research and can't seem to get this sorted. Best approach would be array_unique I think but, the variable $event which contains the output from the parse doesn't seem to work with it.
Link to the script http://www.mesquiteweather.net/inc/inc-legend.php
Code I am using. Any help would be greatly appreciated. I have spent several days trying to resolve this.
// Lets parse the data
$entries = simplexml_load_file($data);
if(count($entries)):
//Registering NameSpace
$entries->registerXPathNamespace('prefix', 'http://www.w3.org/2005/Atom');
$result = $entries->xpath("//prefix:entry");
foreach ($result as $entry):
$event = $entry->children("cap", true)->event;
endforeach;
endif;
// Lets creat some styles for the list
$legendStyle = "margin:10px auto 10px auto;";
$legend .= "<table style='$legendStyle' cellspacing='5px'>";
$legend .= "<tr>";
$i = 1;
foreach ($result as $entry) {
$event = $entry->children("cap", true)->event;
//Set the alert colors for the legend
include ('../inc-NWR-alert-colors.php');
$spanStyle = "background-color:{$alertColor};border:solid 1px #333;width:15px;height:10px;display:inline-block;'> </span><span style='font-size:12px;color:#555;";
$legend .= "<td> <span style='$spanStyle'> $event</span></td>";
if($i % 5 == 0)
$legend .= "</tr><tr>";
$i++;
}
$legend .= "</tr>";
$legend .= "</table>";
echo $legend;
The example below uses the DOM instead of SimpleXML as the DOM provides the handy method C14N() to create canonical XML.
The basic idea of creating canonical XML is that two nodes that are effectively identical will have the same serialized output, regardless of their representation in the source document.
For example attribute order doesn't matter on an element, so both:
<element foo="Foo" bar="Bar"/>`
and:
<element bar="Bar" foo="Foo"/>
are effectively identical. Canonicalize them and the resulting XML for each will be:
<element bar="Bar" foo="Foo"></element>
If you iterate over your desired elements to create an array and use their canonical representations as keys, you'll end up with an array of unique nodes.
Example:
$dom = new DOMDocument();
$dom->load("http://alerts.weather.gov/cap/ca.atom");
// Create an array of unique events
$events = [];
foreach ($dom->getElementsByTagNameNS("urn:oasis:names:tc:emergency:cap:1.1", "event") as $event) {
$events[$event->C14N()] = $event;
}
// ... do whatever other stuff you need ...
// Output event text.
foreach ($events as $event) {
echo "$event->nodeValue\n";
}
Output:
Coastal Flood Advisory
High Surf Advisory
Wind Advisory
Winter Weather Advisory
Beach Hazards Statement
I recently (2 weeks ago) started coding in PHP and today I ran into a problem and wondering if somebody can help/guide me.
I am getting xml data from a Web Service and want to render the data as show in below image
The fetched XML looks like this
<pricesheets>
<pricesheet>
<buyinggroupname>China</buyinggroupname>
<categoryname>Category B</categoryname>
<currency>USD</currency>
<discamt>39330.00</discamt>
<productdesc>Product B description</productdesc>
<prdouctId> Product B </productId>
</pricesheet>
<pricesheet>
<buyinggroupname>Asia</buyinggroupname>
<categoryname>Category A</categoryname>
<currency>USD</currency>
<discamt>39330.00</discamt>
<productdesc>Product A description</productdesc>
<prodouctId> Product A </productId>
</pricesheet>
</pricesheets>
The issue I am having is what's the best way to parse above XML so that I can render products based on 'buyinggroupname' and 'categoryname'. I can easily accomplish the collapse and expand feature once I know how to render the data.
Below is what I have done to achieve what I want. But I know for sure that my code is NOT efficient and scalable.
$xmldata; // XML return by the webservice
$data = simplexml_load_string($xmldata);
$category_A_items = '';
$category_B_items = '';
foreach ($data as $object) {
if($object->categoryname == 'Category A') { // Bad Idea : Hard coded category
$category_A_items .= '<tr><td>'.$object->prdouctId.'</td><td>'. $object->productdesc. '</td><td>'. $object->discamt. '</td></tr>';
}
elseif($object->CATEGORYNAME == 'Category B') { // Bad Idea : Hard coded category
$category_B_items .='<tr><td>'.$object->prdouctId. '</td><td>'. $object->productdesc. '</td><td>'. $object->discamt. '</td></tr>';
}
}
//Render Category A items in table
if(strlen($category_A_items) > 0) {
echo '<h3>CAD</h3>';
echo '<table><tr><th>Product Name</th><th>Description</th><th>Price</th></tr>';
echo $cadItems;
echo '</table>'. PHP_EOL;
}
//Render Category B items in table
if(strlen($category_B_items) > 0) {
echo '<h3>Breast Biopsy</h3>';
echo '<table><tr><th>Product Name</th><th>Description</th><th>Price</th></tr>';
echo $breastBiopsy;
echo '</table>'. PHP_EOL;
}
The above code only renders the data based on categories ( which are hard coded). Now what would be better way of doing the same so that I can render the data based on 'buyingroupname' and 'categoryname' without hard coding either of this two values in the php code.
Thanks in advance!
get an array of unique <categoryname>-nodes with xpath, then loop through it and select all <pricesheet>-nodes with that specific category, letting xpath do that job, again:
$xml = simplexml_load_string($x);
$cat = array_unique($xml->xpath("//categoryname"));
foreach ($cat as $c) {
echo "$c<br />";
foreach ($xml->xpath("//pricesheet[categoryname='$c']") as $p) {
echo $p->productId."<br />";
}
}
see a live-demo # http://codepad.viper-7.com/m9ruRU
Of course, you have to add code for creating tables...
Putting the strings in arrays with variable keys lets PHP keep them organized for you, and you don't have to know any category names at all. I used multidimensional arrays so that each buyingroup has its categories inside it. Then you loop through the arrays to make each table. Let me know if you need more explanation. I misunderstood your image the first time I saw it.
$xmldata; // XML return by the webservice
$data = simplexml_load_string($xmldata);
$buyinggroups = array();
foreach ($data as $object) {
if(isset($object->buyinggroupname) || isset($object->BUYINGGROUPNAME)) {
if(isset($object->buyinggroupname)) {
$name = $object->buyinggroupname;
} else {
$name = $object->BUYINGGROUPNAME;
}
}
if(isset($object->categoryname) || isset($object->CATEGORYNAME)) {
if(isset($object->categoryname)) {
$category = $object->categoryname;
} else {
$category = $object->CATEGORYNAME;
}
}
if(isset($category) && isset($name)) { //just making sure this row is OK
if(!isset($buyinggroups[$name])) {
$buyinggroups[$name] = array(); //initialize the outer array
}
if(!isset($buyinggroups[$name][$category])) {
$buyinggroups[$name][$category] = ''; //this is like your previous $category_A_items
}
$buyinggroups[$name][$category] .= '<tr><td>'.$object->productId.'</td><td>'. $object->productdesc. '</td><td>'. $object->discamt. '</td></tr>';
}
}
//Render all categories in lots of tables
//I am guessing at what HTML you want here; I don't think it's necessarily correct
echo '<table>'. PHP_EOL;
foreach($buyinggroups as $name=>$set) {
echo '<tr><th colspan="2">'.$name.'</th></tr>'. PHP_EOL;
echo '<tr><th> </th><td>';
foreach($set as $category=>$rows) {
echo '<table>';
echo '<tr><th><h3>'.$category.'</h3></th>'. PHP_EOL;
echo '<td><table><tr><th>Product Name</th><th>Description</th><th>Price</th></tr>';
echo $rows;
echo '</table>'. PHP_EOL;
}
echo '</td></tr>';
}
echo '</table>';
EDIT:
This can't possibly be beyond your ability to debug. You are getting everything you need in order to debug. PHP tells you the line number and the error. You google the error and find out what it means. Then you go to that line number and see how what's there corresponds to the thing you googled. In this case, I can tell you that "illegal offset type" means that you have an array key that is not a string or integer. On those lines in the error messages, you have the array keys $name and $category. Try var_dump($name) and var_dump($category) to find out what they actually are, or even var_dump($object) to find out how to get name and category out of the object.
I'm having a some trouble accessing attributes in my XML. My code is below. Initially I had two loops and this was working with no problems.
I would first get the image names and then use the second loop to get the story heading and story details. Then insert everything into the database. I want to tidy up the code and use only one loop. My image name is store in the Href attribute. ()
Sample XML layout (http://pastie.org/1850682). The XML layout is a bit messy so that was the reason for using two loops.
$xml = new SimpleXMLElement('entertainment/Showbiz.xml', null, true);
// Get story images
//$i=0;
//$image = $xml->xpath('NewsItem/NewsComponent/NewsComponent/NewsComponent/NewsComponent/NewsComponent/ContentItem');
// foreach($image as $imageNode){
// $attributeArray = $imageNode->attributes();
// if ($attributeArray != ""){
// $imageArray[$i] = $attributeArray;
// $i++;
// }
//}
// Get story header & detail
$i=0;
$story = $xml->xpath('NewsItem/NewsComponent/NewsComponent/NewsComponent');
foreach($story as $contentItem){
//$dbImage = $imageArray[$i]['Href'];
foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.head/hedline/hl1') as $headline){
$strDetail = "";
foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.content/p') as $detail){
$strDetail .= '<p>'.$detail.'</p>';
foreach($contentItem->xpath('NewsComponent/NewsComponent/ContentItem') as $imageNode){
$dbImage = $imageNode->attributes();
}
}
$link = getUnique($headline);
$sql = "INSERT INTO tablename (headline, detail, image, link) VALUES ('".mysql_real_escape_string($headline)."', '".mysql_real_escape_string($strDetail)."', '".mysql_real_escape_string($dbImage)."', '".$link."')";
if (mysql_query($sql, $db) or die(mysql_error())){
echo "Loaded ";
}else{
echo "Not Loaded ";
}
}
$i++;
}
I think I'm close to getting it. I tried putting a few echo statements in the fourth nested foreach loop, but nothing was out. So its not executing that loop. I've been at this for a few hours and googled as well, just can't manage to get it.
If all else fails, I'll just go back to using two loops.
Regards,
Stephen
This was pretty difficult to follow. I've simplified the structure so we can see the parts of the hierarchy we care about.
It appears that the NewsComponent that has a Duid attribute is what defines/contains one complete news piece. Of its two children, the first child NewsComponent contains the summary and text, while the second child NewsComponent contains the image.
Your initial XPath query is for 'NewsItem/NewsComponent/NewsComponent/NewsComponent', which is the first NewsComponent child (the one with the body text). You can't find the image from that point because the image isn't within that NewsComponent; you've gone one level too deep. (I was tipped off by the fact I got a PHP Notice: Undefined variable: dbImage.) Thus, drop your initial XPath query back a level, and add that extra level to your subsequent XPath queries where needed.
From this:
$story = $xml->xpath('NewsItem/NewsComponent/NewsComponent/NewsComponent');
foreach($story as $contentItem){
foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.head/hedline/hl1') as $headline){
foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.content/p') as $detail){
foreach($contentItem->xpath('NewsComponent/NewsComponent/ContentItem') as $imageNode){ /* ... */ }}}}
to this:
$story = $xml->xpath('NewsItem/NewsComponent/NewsComponent');
foreach($story as $contentItem){
foreach($contentItem->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.head/hedline/hl1') as $headline){
foreach($contentItem->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.content/p') as $detail){
foreach($contentItem->xpath('NewsComponent/NewsComponent/NewsComponent/ContentItem') as $imageNode){ /* ... */ }}}}
However, the image still doesn't work after that. Because you're using loops (sometimes unnecessarily), $dbImage gets reassigned to an empty string. The first ContentItem has the Href attribute, which gets assigned to $dbImage. But then it loops to the next ContentItem, which has no attributes and therefore overwrites $dbImage with an empty value. I'd recommend modifying that XPath query to find only ContentItems that have an Href attribute, like this:
->xpath('NewsComponent/NewsComponent/NewsComponent/ContentItem[#Href]')
That should do it.
Other thoughts
Refactor to clean up this code, if/where possible.
As I mentioned, sometimes you are looping and nesting when you don't need to, and it just ends up being harder to follow and potentially introducing logical bugs (like the image one). It seems that the structure of this file will always be consistent. If so, you can forgo some looping and go straight for the pieces of data you're looking for. You could do something like this:
// Get story header & detail
$stories = $xml->xpath('/NewsML/NewsItem/NewsComponent/NewsComponent');
foreach ($stories as $story) {
$headlineItem = $story->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.head/hedline/hl1');
$headline = $headlineItem[0];
$detailItems = $story->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.content/p');
$strDetail = '<p>' . implode('</p><p>', $detailItems) . '</p>';
$imageItem = $story->xpath('NewsComponent/NewsComponent/NewsComponent/ContentItem[#Href]');
$imageAtts = $imageItem[0]->attributes();
$dbImage = $imageAtts['Href'];
$link = getUnique($headline);
$sql = "INSERT INTO tablename (headline, detail, image, link) VALUES ('".mysql_real_escape_string($headline)."', '".mysql_real_escape_string($strDetail)."', '".mysql_real_escape_string($dbImage)."', '".$link."')";
if (mysql_query($sql, $db) or die(mysql_error())) {
echo "Loaded ";
} else {
echo "Not Loaded ";
}
}
I have following code:
SELECT q21, q21coding AS Description FROM `tresults_acme` WHERE q21 IS NOT NULL AND q21 <> '' ORDER BY q21coding
It brings back the following (excerpt):
Text Description
Lack of up to date equal pay cases&legislation - t... Content needs updating
The intranet could contain more "up to date traini... Content needs updating
Poorly set out. It is hard to find things. Difficulty in navigating/finding content
Only use the intranet as a necessity. Will ask my ... Difficulty in navigating/finding content
Now, I'd like to display this in a table on a PHP page but am having some problems because of the way I'd like it displayed, it needs to be as follows:
Content needs updating
----------------------
[List all the comments relating to this description]
Difficulty in navigating/finding content
----------------------------------------
[List all the comments relating to this description]
and so on.
Now I think it is a For Each loop in PHP but I am having terrible difficulty getting my head around this - any ideas and suggestions very very welcome!
Thanks,
Simple approach
Set prev_desc to NULL
For each row print text
If description is not equal to prev_desc prepend with the description for the new "section" and set prev_desc <- description
E.g.1 (untested!),
$prev_desc = null;
while ($row = mysql_fetch_assoc(...)) {
if ($prev_desc != $row['description']) {
print '<h1>' . $row['description'] . '</h1>';
$prev_desc = $row['description'];
}
print $row['text'] . '<br />'; // Formatting needed
}
Note: You must keep the ORDER BY <description-column> in order to have rows "grouped". Otherwise this simple approach will not work.
Less presentation-specific approach
I could be considered more "clean" to create some kind of 2D container to "categorize" the extracted data, e.g.,
$items = array(
'Content needs updating' => array(
'Lack of ...',
'The intra...'
),
...
);
You could then loop over these items like so1:
foreach ($items as $desc => $texts) {
print '<h1>' . $desc . '</h1>';
foreach ($texts as $text) {
print $text . '<br />';
}
}
1 As #bobince has noted, make sure that content going directly into the final HTML is properly escaped, see e.g. htmlspecialchars().
You just need to keep track of which heading you last displayed. I don't know which library you're using for database access, so the details of how you access columns/rows will be slightly different, but here it is in kind-of pseudocode:
$lastHeading = '';
foreach($rows as $row)
{
if ($lastHeading != $row['Description'])
{
if ($lastHeading != '')
echo '</ul>';
$lastHeading = $row['Description'];
echo "<h1>$lastHeading</h1>";
echo '<ul>';
}
echo '<li>'.$row['Text'].'</li>';
}
if ($lastHeading != '')
echo '</ul>';
This has the added feature of putting comments in a <ul>, not sure if that's required for you or not.
This works because you've sorted by the "description" column. That means you know that all of the rows with the same "description" will come together.
you can either create multiple queries for each of the sections or loop over the data multiple times and filter based on the type of description using php.
$descriptions = array('Content needs updating','Difficulty in navigating/finding content');
$rows = <fetch all rows from the query>;
foreach($descriptions as $description)
{
echo '<h1>',$description,'</h1>';
foreach($rows as $row)
{
if ($row['description'] == $description)
{
echo $row['text'],'<br />';
}
}
}
OK I hope this isn't too specific. I have a database driven CMS that a coworker uses with many categories in it. Here's how it echoes some products we have now:
$offers = get_offers('category1','none','compare');
foreach ($offers as $row) {
$offername = $row['name'];
$offerlogo = $row['logo'];
$offera=$row['detailA'];
$offerb=$row['detailB'];
$offerc=$row['detailC'];
echo "you can have $offername, it's logo looks like <img src='$offerlogo'>" it's characteristics are $offera, offerb, offerc, etc";}
This works fine. My the problem is I want to get offera, offerb and offerc from another category, category 2. I tried going like this:
$offers = get_offers('category1','none','compare');
foreach ($offers as $row) {
$offername = $row['name'];
$offerlogo = $row['logo'];
$offers = get_offers('category2','none','compare');
$offera=$row['detailA'];
$offerb=$row['detailB'];
$offerc=$row['detailC'];
echo "you can have $offername, it's logo looks like <img src='$offerlogo'>" it's characteristics are $offera, offerb, offerc, etc";}
But of course that doesn't work. I don't want my coworker to have to go through the CMS and copy all the information over, is there a way to make this work?
Assuming the ordering of the results from both calls to get_offers matches up, I believe this might work for you:
$offers['cat1'] = get_offers('category1', 'none', 'compare');
$offers['cat2'] = get_offers('category2', 'none', 'compare');
$numberOfOffers = count($offers['cat1']);
for ($i = 0; $i < $numberOfOffers; $i++)
{
$offername = $offers['cat1'][$i]['name'];
$offerlogo = $offers['cat1'][$i]['logo'];
$offera = $offers['cat2'][$i]['detailA'];
$offerb = $offers['cat2'][$i]['detailB'];
$offerc = $offers['cat2'][$i]['detailC'];
echo "you can have $offername, its logo looks like <img src='$offerlogo'> its characteristics are $offera, $offerb, $offerc, etc\n";
}
I agree with ngm. If the categories match up then you could bring the results from the different call with the following:
$offersCat1 = get_offers('category1','none','compare');
$offersCat2 = get_offers('category2','none','compare');
foreach ($offers as $key=>$row) {
$offera=$offersCat2[$key]['detailA'];
$offerb=$offersCat2[$key]['detailB'];
$offerc=$offersCat2[$key]['detailC'];
echo "you can have {$row['name']}, it's logo looks like <img src='{$row['logo']}'> it's characteristics are $offera, offerb, offerc, etc";
}
This example will do the same thing, but you keep it in the foreach loop. By using the $key=>$row you are able to access the key of the array. I also took the liberty to echo your variables directly rather than putting them in variables. If you put {} around an array variable (or class variable) you can use them within an echo, print or <<<. This makes my life easier.
Example: echo "This variable {$variable['test']}";