I have a problem.
I created a function that returns a output.
My problem is how to return two outputs on one page. Inside a function i have two db_query. The first one gives me teacher information
$temp = '';
foreach($result as $item) {
$temp .= '<b>About teacher | </b>'. $item->title .' '. $item->name .' '. $item->lname .' , ' . $item->xyz .' <br />';
$temp .= '<br/>';
$temp .= '<b>E-mail | </b>' . $item->email . '<br />';
$temp .= '<br/>';
if ($item->tel > "")
{
$temp .= '<b>Phone | </b>'. $item->tel .''. $item->tele . '<br />';
$temp .= '<br/>';
}
if ($item->cell > "")
{
$temp .= '<b>Mobile phone | </b>'. $item->call .''. $item->cell . '<br />';
$temp .= '<br/>';
}
}
The other one returns a table and i use
$output = theme('table', array('header'=> $header, 'rows' => $rows, 'empty' => t("None")));
Now when I use
return $temp;
return $output;
It returns only one "output". If $temp if first it returns about teacher if $output is first then it renders a table without the teacher information.
This has nothing to do with Drupal, but is generic PHP. Return in PHP (and almost any language) means "return to the caller with this value". That means code after return is never ran.
return "foo";
print "I am never ran";
In your case, you want to glue the two strings together.
return $temp . $output;
The dot, concatenates two strings. and makes them one string.
you can return it as array.
$t_array['v1'] = $temp;
$t_array['v2'] = $output;
return $t_array;
Related
I have a function that prepares a receipt output. But since it has all kinds of conditions it ends up being very long and difficult to understand..
How would one go about refactoring this? Any ideas?
If I split this into 100 small functions would that really be better?
public static function prepare_receipt($printer)
{
if (self::hasItems($printer['id']))
{
$output = '';
if ($_POST['pre_receipt'])
{
$output .= "======== Pre receipt =======\n\n\n";
}
/**
* Time and table
*/
if ($_POST['isTakeaway'] || $_POST["isDeliveryGuys"] || $_POST["isBolt"]) {
$output .= "Table: " . $_POST['table'] . "\n";
$output .= "Floor: " . $_POST['floor'] . "\n";
$output .= "Time: " . $_POST['takeawayTime'] . "\n";
if ($_POST['order_comment']) {
$output .= "Comment: " . removeSpecialChars($_POST['order_comment']) . "\n";
}
} else {
$output .= "Table: " . $_POST['table'] . "\n\n";
$output .= "Floor: " . $_POST['floor'] . "\n\n";
if ($_POST['order_comment']) {
$output .= "Comment: " . removeSpecialChars($_POST['order_comment']) . "\n";
}
}
$output .= "------------------------\n";
/**
* Food items
*/
foreach ($_POST['orderedItems'] as $orderedItem)
{
$has_unprinted_quantity = false;
if (isset($orderedItem['last_printed_quantity'])) {
$unprinted_quantity_count = intval($orderedItem['is_printed_quantity']) - intval($orderedItem['last_printed_quantity']);
if ($unprinted_quantity_count > 0) {
$has_unprinted_quantity = true;
}
}
if ( ($orderedItem['should_print'] &&
!$orderedItem['is_printed'] &&
$orderedItem['is_visible']) ||
$_POST['pre_receipt'] ||
$has_unprinted_quantity)
{
if (is_array($orderedItem['printers'])) {
$in_printer = in_array($printer['id'], $orderedItem['printers']);
} else {
$in_printer = in_array($printer['id'], json_decode($orderedItem['printers'], true));
}
if ( $in_printer || $_POST['pre_receipt'] )
{
if ($orderedItem['is_sidedish'] && !$_POST['pre_receipt']) {
continue;
}
if ($has_unprinted_quantity) {
$output .= $unprinted_quantity_count . 'x ';
} else {
$output .= $orderedItem['quantity'] . 'x ';
}
// We ned to split it for multiple lines...
$itemDescriptionParts = self::split($orderedItem['description']);
foreach ($itemDescriptionParts as $itemDescription) {
$itemDescriptionClean = removeSpecialChars($itemDescription);
$output .= $itemDescriptionClean;
}
// Add price for pre receipt
if ($_POST['pre_receipt']) {
$output .= " - " . number_format($orderedItem['price_with_discount'], 2, '.', ',');
}
if (!$_POST['pre_receipt']) {
if ($orderedItem['comments'] != '') {
$output .= " > " . removeSpecialChars(substr($orderedItem['comments'], 0, 27)) . "\n";
}
}
/** Side dishes */
if (isset($orderedItem['side_dishes']) && !$_POST['pre_receipt'])
{
foreach ($orderedItem['side_dishes'] as $side_dish) {
$output .= "\n + " . removeSpecialChars(substr($side_dish['description'], 0, 27)) . "\n";
}
}
$output .= "\n";
}
}
}
/**
* Sums
*/
/**
* Footer
*/
$output .= "------------------------\n";
if ($_POST['pre_receipt'])
{
$output .= "\nSubtotal: " . number_format($_POST['order']['subtotal'], 2, '.', ',') . "\n";
$output .= "Discount: " . number_format($_POST['order']['discount'], 2, '.', ',') . "\n";
$output .= "Total: " . number_format($_POST['order']['total'], 2, '.', ',') . "\n\n";
}
$output .= "Time: " . getTime() . "\n";
return $output;
}
else
{
return 'EMPTY';
}
}
Any pointers in the right direction would be much appreciated.
Refactoring works often well, if it follows semantics. In your case: You made already comments for different sections. This is often a sign for a function on it's own.
Just to give you an idea: How it may look like afterwards:
$output .= create_headline(...);
$output .= create_time_table(...);
$output .= create_separator();
foreach ($_POST['orderedItems'] as $orderedItem) {
$output .= create_food_item($orderedItem, $_POST['pre_receipt'], ...);
}
$output .= create_separator();
$output .= create_footer(...);
This will save time when searching for a bug in a certain area of the receipt.
I would advice https://en.wikipedia.org/wiki/Divide-and-conquer_algorithm, and your function already has comment that indicates how this function can be divided in multiple that has a single responsability.
I would also advice not to use $_POST directly, all input data must always be validated and possibly filtered. Data from input should be passed as dependency, to adhere dependency injection, see https://phptherightway.com/ for other good practices.
I would also avoid the use of string concatenation, store all the parts within an array and then join/implode them using a separator.
Looking at your code smart use of ternary operators and shifting the orderitem loop into different function can drastically reduce your code length by half. There is no need to create function for each operation like printing head, printing tail etc as the logic in those print is pretty simple and your code can prettry muddy and difficult to navigate if there are large number of unwanted functions. You can do something like below. Also note using . (dot) operator for string concatenation make your string less readable hence prefer printing variables with {} operator.
<?php
public static function prepare_receipt($printer)
{
if (self::hasItems($printer['id']))
{
$output = isset($_POST['pre_receipt']) ? "======== Pre receipt =======\n\n\n" : "" ;
//addiing time table
$output .= "Table: {$_POST['table']}. \n Floor: {$_POST['floor']}. \n";
//adding time if it is takeaway or isDeliveryGuys or isBolt
$output .= ($_POST['isTakeaway'] || $_POST["isDeliveryGuys"] || $_POST["isBolt"]) ? "Time: {$_POST['takeawayTime']}. \n" : "" ;
//adding order comment
$output .= $_POST['order_comment']) ? "Comment: {removeSpecialChars($_POST['order_comment'])} \n" : "" ;
//print order items
this->getOrderItems($_POST[orderedItems], &$output);
// footer
$output .= "------------------------\n";
if ($_POST['pre_receipt'])
$output .= "\nSubtotal: {number_format($_POST['order']['subtotal'], 2, '.', ',')} \n Discount: { number_format($_POST['order']['discount'], 2, '.', ',') } \n Total: {number_format($_POST['order']['total'], 2, '.', ',')} \n\n";
$output .= "Time: " . getTime() . "\n";
return $output;
}
else
{
return 'EMPTY';
}
}
?>
.
I'm trying to create a dynamic navigation menu.
All allowed possibilities are defined in an array.
I'm trying to count the array, split it in half and print each half of the array into seperate div's. One on the left side of the screen and the other on the right side.
this is what i've got:
function menu_main() {
$count = count($GLOBALS['menu']);
$count = round($count / 2);
$menu_1 = array_slice($GLOBALS['menu'], 0, $count);
$menu_2 = array_slice($GLOBALS['menu'], $count++);
echo ' <div id="menu_1">' . "\n";
foreach($menu_1 as $page) {
echo ' <div class="menu_items">' . "\n";
echo ' <a class="menu" href="index.php?page=' . $page . '">' . $page . '</a> .' . "\n"; //Create menu left
echo ' </div>'. "\n";
}
echo ' </div>'. "\n";
echo ' <div id="menu_2">' . "\n";
foreach($menu_2 as $page) {
echo ' <div class="menu_items">' . "\n";
echo ' <a class="menu" href="index.php?page=' . $page . '">' . $page . '</a> .' . "\n"; //Create menu right
echo ' </div>'. "\n";
}
echo ' </div>'. "\n";
}
Is there a way to do this with itteration?
This works but it looks way to messy.
Ok, a couple of things:
$GLOBALS['menu'];
Why use $GLOBALS, or global $menu, for that matter? Why not pass what you need to the function?
function menuMain(array $menu)
{
$count = floor(count($menu)/2);
Would make a lot more sense. Also:
$menu_1 = array_slice($GLOBALS['menu'], 0, $count);
$menu_2 = array_slice($GLOBALS['menu'], $count++);//<== why the increment?
Why are you incrementing $count, only to then not use it anymore? You're post-incrementing the value, which means that if $count is 10, then the code above is evaluated to:
$menu_1 = array_slice($GLOBALS['menu'], 0, 10);
$menu_2 = array_slice($GLOBALS['menu'], 10);//10+1 happens AFTER the array_slice call is made
Also don't use "\n", because line-feeds are system dependent, PHP has a predefine constant for this reason: PHP_EOL. Use it (that's an order).
And don't concatenate what you echo, just comma-separate it:
echo 'foo', 'bar', PHP_EOL;
echo 'foo'.'bar'.PHP_EOL;
both may produce the same time, but the first version is faster, because the strings are pushed to the output, without first concatenating them into a new string.
Not that it matters here, because functions should return something, not echo it.
Anyway, your question: is there a way to do this with iteration? Yes, and you're already iterating (foreach iterates an array/object).
An alternative approach would be:
function mainMenu (array $menu)
{
$return =' <div id="menu_1">' . PHP_EOL;//functions shouldn't echo
//start with div 1
for($i = 0, $j= count($menu), $count = floor($j/2); $i<$j;++$i)
{
if ($i == $count)
{//reached half-way marker, close div 1, open div 2
$return .= '</div>'.PHP_EOL.'<div id="menu_2">'.PHP_EOL;
}
$return .= ' <div class="menu_items">' . PHP_EOL
.' <a class="menu" href="index.php?page=' . $menu[$i] . '">' . $menu[$i]
. '</a> .' .PHP_EOL;
}
return $return.'</div>';//close div2 and return
}
That should give you the exact same output as before, only it only uses a single loop, doesn't rely on globals, and doesn't echo things, so you call it like this:
$menu = array('your', 'global', 'array');
echo mainMenu($menu);//pass the array, echo what it returns
My solution if it helps.
$menu = array ("link1","link2","link3","link4","link5");
function menu_main()
{
global $menu;
$count = count($menu);
$menu_items = round($count / 2);
//initialize the divs for menus
$output_menu[0] = ' <div id="menu_1">' . "\n";
$output_menu[1] = ' <div id="menu_2">' . "\n";
$menu_count = 0;
foreach($menu as $link)
{
if ($menu_count < $menu_items)
{
//what enters in first menu
$output_menu[0] .= ' <div class="menu_items">' . "\n";
$output_menu[0] .= ' <a class="menu" href="index.php?page=' . $link . '">' . ucfirst($link) . '</a> .' . "\n"; //Create menu left
$output_menu[0] .= ' </div>'. "\n";
}
else
{
//what enters in second menu
$output_menu[1] .= ' <div class="menu_items">' . "\n";
$output_menu[1] .= ' <a class="menu" href="index.php?page=' . $link . '">' . ucfirst($link) . '</a> .' . "\n"; //Create menu left
$output_menu[1] .= ' </div>'. "\n";
}
$menu_count++;
}
//close the divs for menus
$output_menu[0] .= ' </div>'. "\n";
$output_menu[1] .= ' </div>'. "\n";
//return array with content for menus
return $output_menu;
}
$menu_main = menu_main(); // get content in variable
print_r($menu_main[0]); //print 1st menu
print_r($menu_main[1]); //print 2nd menu
I'm working on a project, and I've come across an issue that has me stumped. The code below is a class file and a test page to make sure it's working. It's for somebody else who is programming the site, otherwise I would code the JSON output differently. Basically, the person implementing it just has to pull a bunch of data (like below) from a database, and loop through, instantiating a class object for each result, and plugging each instance into an array, and passing the array to the printJson function, which will print the JSON string. Here is what I have:
Results.php
<?php
class Result
{
public $Category = NULL;
public $Title = NULL;
public $Price = NULL;
public function __construct($category, $title, $price)
{
$this->Category = $category;
$this->Title = $title;
$this->Price = $price;
}
public static function printJson($arrayOfResults)
{
$output = '{"results": [';
foreach ($arrayOfResults as $result)
{
$output += '{"category": "' . $result->Category . '",';
$output += '"title": "' . $result->Title . '",';
$output += '"price": "' . $result->Price . '",';
$output += '},';
}
$output = substr($output, 0, -1);
$output += ']}';
return $output;
}
}
?>
getResults.php
<?php
require_once('Result.php');
$res1 = new Result('food', 'Chicken Fingers', 5.95);
$res2 = new Result('food', 'Hamburger', 5.95);
$res3 = new Result('drink', 'Coke', 1);
$res4 = new Result('drink', 'Coffee', 2);
$res5 = new Result('food', 'Cheeseburger', 6.95);
$x = $_GET['x'];
if ($x == 1)
{
$array = array($res1);
echo Result::printJson($array);
}
if ($x == 2)
{
$array = array($res1, $res2);
echo Result::printJson($array);
}
if ($x == 3)
{
$array = array($res1, $res2, $res3);
echo Result::printJson($array);
}
if ($x == 5)
{
$array = array($res1, $res2, $res3, $res4, $res5);
echo Result::printJson($array);
}
?>
The end result is if I go to getResults.php?x=5, it will return $res1 thru $res5 (again, this is just to test, I would never do something like this in production) formatted as JSON. Right now, I get '0' outputted and I cannot for the life of me figure out why. Could my foreach loop not be written properly? Please, any help you could provide would be awesome!
It's because you're using + for concatenation rather than .:
$output .= '{"category": "' . $result->Category . '",';
$output .= '"title": "' . $result->Title . '",';
$output .= '"price": "' . $result->Price . '",';
$output .= '},';
But you should really not construct the JSON yourself, as it leads to a number of errors making for invalid JSON (trailing commas etc). Use something like this instead:
public static function printJson(array $arrayOfResults)
{
$results['results'] = array_map('get_object_vars', $arrayOfResults);
return json_encode($results);
}
I have a block of code thats working perfectly to pull data about different office locations.
What I would like to do is be able to make the last iteration of this loop change the div class to something else so I can apply a different set of css styles.
$fields = get_group('Offices');
foreach($fields as $field){
echo'<div class="oloc">';
if($locationVar==NULL || $locationVar!=$field['office-location'][1]) {
echo '<a name="' . strtolower(str_replace(' ', '-', $field['office-location'][1])) . '"></a><h3>' . $field['office-location'][1] . '</h3>';
$locationVar = $field['office-location'][1];
} else {
echo "<br />";
}
if($field['office-gm'][1]){
echo '<div class="gm"><img src="http://maps.googleapis.com/maps/api/staticmap?center=' . $field['office-gm'][1] . '&zoom=9&size=250x250&markers=color:blue|label:A|' . $field['office-gm'][1] . '&sensor=false"></div>';
}
if($field['office-name'][1]){
echo '<strong>' . $field['office-name'][1] . '</strong><br /><br />';
}
if($field['office-phone'][1]){
echo 'Phone: ' . $field['office-phone'][1] . '<br />';
}
if($field['office-fax'][1]){
echo 'Fax: ' . $field['office-fax'][1] . '<br />';
}
if($field['office-address'][1]){
echo '<br />Address:<br />' . strip_tags($field['office-address'][1], '<br><br />') . '<br />';
}
if($field['office-webpage'][1]){
echo 'Web: ' . 'Office Webpage<br />';
}
if($field['office-email'][1]){
echo 'Email: ' . 'Office Email<br />';
}
if($field['office-emp'][1]){
echo 'Jobs: ' . 'Employment Application<br />';
}
if($field['office-fb'][1]){
echo 'Facebook: ' . 'Facebook<br />';
}
if($field['office_office_twitter'][1]){
echo 'Twitter: ' . 'Twitter<br />';
}
echo '</div>';
}
For cases like these you can use a CachingIterator and the hasNext() method:
$fields = get_group('Offices');
$it = new CachingIterator(new ArrayIterator($fields));
foreach($it as $field)
{
...
if (!$it->hasNext()) echo 'Last:';
...
}
Put every echo in a var, this class definition in a other var. Then at the end of your foreach you check like so:
$i = 0;
foreach(...
if( $i == count($fields) ) { // change class }
Try this
$i = 0;
$total = count($fields);
$final = false;
foreach($fields as $field){
$i++;
$final = ($i + 1 == $total)? true : false;
if($final)
echo'<div class="NEW_CLASS">';
else
echo'<div class="oloc">';
....
}
First you should get the total count of the offices so that when you are on the last iteration, you can do something about it.
$fields = get_group('Offices');
$fields_count = count($fields);
$i = 0;
foreach ($fields as $field) {
$is_final = ++$i == $fields_count;
echo '<div class="oloc' . ($is_final ? ' oloc-final' : '') . '">';
[...]
}
I have the following code:
if(hasRows($resultC)){
while($row = mysql_fetch_row($resultC)) {
$mescategories = '<span><a href="' . CalRoot .
'/index.php?com=searchresult&t=' . $row[0] .
'" rel="tag" class="eventMain">' . cOut($row[1]) . '</a></span> | ' ;
echo $mescategories;
}//end while
}//end if
The rendered output looks like:
cat 1 | cat 2 | cat 3 | cat 4 |
How do I prevent the last | character being rendered.
$catArray = array();
if(hasRows($resultC)){
while($row = mysql_fetch_row($resultC)){
array_push($catArray, '<span>' . cOut($row[1]) . '</span>');
}//end while
echo implode('|', $catArray);
}//end if
You could count the number of rows using mysql_num_rows($resultC), and have a counter on your loop. Alternatively, the way I'd do it is something like:
if(hasRows($resultC)){
// Create an empty array
$links = array( );
while($row = mysql_fetch_row($resultC)){
// Add each text link to the array
$links[] = '<span>' . cOut($row[1]) . '</span>' ;
}
// "Glue" the array back together using implode, with the separator between each.
echo implode(' | ', $links );
}
How about putting in a conditional statement. Count the size of the row and if $count=$maxcount then don't echo the "|" character.
$i = 0; //set before while loop
$i++; //inserted into while loop
if ($i != mysql_num_rows($resultC) ) { //inserted into while loop
$mescategories .= " | " ;
}
mysql_num_rows will tell how many rows there are in the query, and then will append the pipe character for each row except the last one.
EDIT: I think the $i++ should come before the if statement, actually.
I have not checked your formatting. Just added a "first" variable.
if(hasRows($resultC)){
$first = true;
while($row = mysql_fetch_row($resultC)){
$mescategories = ' '.($first ? "":"|").' <span>' . cOut($row[1]) . '</span> ' ;
echo $mescategories;
$first = false;
}//end while
}//end if
try
if(hasRows($resultC)){
$i=0;
while($row = mysql_fetch_row($resultC)){
$spaceline =($i>0) ? '|' : '';
$mescategories = '<span>' . cOut($row[1]) . '</span>' ;
$i++;
echo $spaceline.$mescategories;
}//end while
}//end if
Just do
echo substr($mescategories, 0, -1);
instead of echo $mescategories
you let it put | after every instance and then delete the last char
else if you need to know the last key of an array you use:
end($array);
$lastKey = key($array);
but don't forget to reset before you do things with it
reset($array);