I have navigation with product categories at top of website.
Want to repeat this navigation in footer of website.
Instead of writing $args, defining variables and such once again I decided to make a function for this.
It looks like this:
However as every function should have a return I'm confused how should return of this function look like?
When I try to return <li> instead of echoing it - I get nothing, empty area, but with echo - function works.
Instead of echo you can write $return_data .= ... to concatenate a string which was initially declared as an empty string before the loop began.
Here is a sample for such cases:
function show_prod_cats($all_categories) {
$return_data = '';
foreach ($all_categories as $cat) {
//echo '<li>....</li>';
$return_data .= '<li>....</li>';
}
return $return_data;
}
given the following link:
http://finanzalocale.interno.it/apps/floc.php/certificati/index/codice_ente/1030491450/cod/4/anno/2012/md/0/cod_modello/CCOU/tipo_modello/U/cod_quadro/01
how am I supposed to scrpae the value of Popolazione residente (ab.)?
I have tried with some prehistorical code of mine, but it's terribly slow and many datas get unprocessed.
For example if I process 300 links, about 180/200 are not processed.
Any clue?
Thanks.
First of all it is verry difficult due to the fact that the first table doesn`t have a unique identifier(nor id nor class).
THIS WILL NOT WORK FOR EVERY PAGE!!!, it's more of an option at this point.
You would have to change the implementation depending on other page content with a case depending on the link I suppose....
I would use https://github.com/fabpot/goutte and implement something like this:
class MyController ...
public function __construct()
{
$this->count = 0; //no iteration
$this->scraped = array();
}
.....
public function scrape($url)
{
$crawler = $client->request('GET', $url);
$crawler->filter('table > tbody >tr >td')->each(function ($node) { //find all td`s
$this->count++;//increment
if($this->count == 1)
{//if first td with the text you want...
$this->scraped[] = $node->text();
}
});
}
I have 2 buttons with the same name. For design reasons only one of them is visible at the same time.
I want to click on any visible button.
If first button is hided this expression
$this->byCssSelector('[name="saveAndClose"]')->click()
returns
Element is not currently visible and so may not be interacted with
How to click on visible button?
I have written simple code to this.
public function clickOnDisplayedElementByName($name)
{
$elements = $this->elements($this->using('css selector')->value('[name="' . $name . '"]'));
foreach ($elements as $element)
{
if ($element->displayed())
{
$element->click();
return;
}
}
$this->fail('There is no visible elements with name ' . $name);
}
I use this code: PHP Sort Files In Directory by Type
But it opens up all directories. I just want directories that leads to the selected item to be open.
If im understanding you correctly, you don't want to recursively display the directories under the target. I think you would remove the recursive call from the code above like this :
/* Rendering */
function list_dir($path)
{
...
foreach($items as $item)
{
if ($item->type=='dir')
{
echo '<li class="folder">'.$item->entry.'</li>';
//list_dir($item->full_path); REMOVE THIS
}
else
{
echo '<li class="file">'.$item->entry.'</li>';
}
}
echo "</ul>";
}
So I'm setting up a system that has a lot of emails, and variable replacement within it, so I'm writing a class to manage some variable replacement for templates stored in the database.
Here's a brief example:
// template is stored in db, so that's how this would get loaded in
$template = "Hello, %customer_name%, thank you for contacting %website_name%";
// The array of replacements is built manually and passed to the class
// with actual values being called from db
$replacements = array('%customer_name%'=>'Bob', '%website_name%'=>'Acme');
$rendered = str_replace(array_keys($replacements), $replacements, $template);
Now, that works well and good for single var replacements, basic stuff. However, there are some places where there should be a for loop, and I'm lost how to implement it.
The idea is there'd be a template like this:
"hello, %customer_name%, thank you for
requesting information on {products}"
Where, {products} would be an array passed to the template, which the is looped over for products requested, with a format like:
Our product %product_name% has a cost
of %product_price%. Learn more at
%product_url%.
So an example rendered version of this would be:
"hello, bob, thank you for requesting
information on:
Our product WidgetA has a cost of $1.
Learn more at example/A
Our product WidgetB has a cost of $2.
Learn more at example/B
Our product WidgetC has a cost of $3.
Learn more at example/C.
What's the best way to accomplish this?
Well, I really dont see the point in a template engine that uses repalcements/regex
PHP Is already a template engine, when you write <?php echo $var?> its just like doing <{$var}> or {$var}
Think of it this way, PHP Already translates <?php echo '<b>hello</b>'?> into <b>hello</b> by its engine, so why make it do everything 2 times over.
The way i would implement a template engine is like so
Firstly create a template class
class Template
{
var $vars = array();
function __set($key,$val)
{
$this->vars[$key] = $val;
}
function __get($key)
{
return isset($this->vars[$key]) ? $this->vars[$key] : false;
}
function output($tpl = false)
{
if($tpl === false)
{
die('No template file selected in Template::output(...)');
}
if(!file_exists(($dir = 'templates/' . $tpl . '.php')))
{
die(sprintf('Tpl file does not exists (%s)',$dir));
}
new TemplateLoader($dir,$this->vars);
return true;
}
}
This is what you use in your login such as index.php, you will set data just like an stdClass just google it if your unsure. and when you run the output command it sends the data and tpl to the next class below.
And then create a standalone class to compile the tpl file within.
class TemplateLoader
{
private $vars = array();
private $_vars = array(); //hold vars set within the tpl file
function __construct($file,$variables)
{
$this->vars = $variables;
//Start the capture;
ob_start();
include $file;
$contents = ob_get_contents();
ob_end_clean(); //Clean it
//Return here if you wish
echo $contents;
}
function __get($key)
{
return isset($this->vars[$key]) ? $this->vars[$key] : (isset($this->_vars[$key]) ? $this->_vars[$key] : false) : false;
}
function __set($key,$val)
{
$this->_vars[$key] = $val;
return true;
}
function bold($key)
{
return '<strong>' . $this->$key . '</string>';
}
}
The reason we keep this seperate is so it has its own space to run in, you just load your tpl file as an include in your constructor so it only can be loaded once, then when the file is included it has access to all the data and methods within TemplateLoader.
Index.php
<?php
require_once 'includes/Template.php';
require_once 'includes/TemplateLoader.php';
$Template = new Template();
$Template->foo = 'somestring';
$Template->bar = array('some' => 'array');
$Template->zed = new stdClass(); // Showing Objects
$Template->output('index'); // loads templates/index.php
?>
Now here we dont really want to mix html with this page because by seperating the php and the view / templates you making sure all your php has completed because when you send html or use html it stops certain aspects of your script from running.
templates/index.php
header
<h1><?php $this->foo;?></h1>
<ul>
<?php foreach($this->bar as $this->_foo):?>
<li><?php echo $this->_foo; ?></li>
<?php endforeach; ?>
</ul>
<p>Testing Objects</p>
<?php $this->sidebar = $this->foo->show_sidebar ? $this->foo->show_sidebar : false;?>
<?php if($this->sidebar):?>
Showing my sidebar.
<?php endif;?>
footer
Now here we can see that were mixing html with php but this is ok because in ehre you should only use basic stuff such as Foreach,For etc. and Variables.
NOTE: IN the TemplateLoader Class you can add a function like..
function bold($key)
{
return '<strong>' . $this->$key . '</string>';
}
This will allow you to increase your actions in your templates so bold,italic,atuoloop,css_secure,stripslashs..
You still have all the normal tools such as stripslashes/htmlentites etc.
Heres a small example of the bold.
$this->bold('foo'); //Returns <strong>somestring</string>
You can add lots of tools into the TempalteLoader class such as inc() to load other tpl files, you can develop a helper system so you can go $this->helpers->jquery->googleSource
If you have any more questions feel free to ask me.
----------
An example of storing in your database.
<?php
if(false != ($data = mysql_query('SELECT * FROM tpl_catch where item_name = \'index\' AND item_save_time > '.time() - 3600 .' LIMIT 1 ORDER BY item_save_time DESC')))
{
if(myslq_num_rows($data) > 0)
{
$row = mysql_fetch_assc($data);
die($row[0]['item_content']);
}else
{
//Compile it with the sample code in first section (index.php)
//Followed by inserting it into the database
then print out the content.
}
}
?>
If you wish to store your tpl files including PHP then that's not a problem, within Template where you passing in the tpl file name just search db instead of the filesystem
$products = array('...');
function parse_products($matches)
{
global $products;
$str = '';
foreach($products as $product) {
$str .= str_replace('%product_name%', $product, $matches[1]); // $matches[1] is whatever is between {products} and {/products}
}
return $str;
}
$str = preg_replace_callback('#\{products}(.*)\{/products}#s', 'parse_products', $str);
The idea is to find string between {products} and {products}, pass it to some function, do whatever you need to do with it, iterating over $products array.
Whatever the function returns replaces whole "{products}[anything here]{/products}".
The input string would look like that:
Requested products: {products}%product_name%{/products}