i have this process that is the heart of my app, that im creating, but for some reason i feel like its the worst way to do it(instinct) , and i wanted to see if thier is something wrong with this process, and am i approaching it in a bad way! p.s. the code works fine, just refactoring problem.
the process is:
users go to homepage, they see thier latest activities, by other site memebers(home.php),
//function to bring the latest activities from database
$results=function getUserUpdates($_SESSION['user_id'];
while($row = mysql_fetch_array($results))
{
//another function to format the activities in a social stream
echo formatUpdate($row['user_note'],$row['dt'],$row['picture'],$row['username'],$row['id'],$row['reply_id'],$row['reply_name'],$row['votes_up'],$row['votes_down']);
}
i have put the function codes in pastie.
formatUpdate function http://pastie.org/1213958
getUserUpdates function http://pastie.org/1213962
EDIT both functions are from different files they are included in home.php,
formatUpdate from functions.php
getUserUpdates from queries.php
First of all, it's good that you have separate functions for getting the data and for formatting the data. It's a good start toward refactoring your code. It makes it easier in the future: if you ever want to format your data differently, you can just expand your formatter.
Second, this is what coreyward meant by a lambda:
$results=function getUserUpdates($_SESSION['user_id'];
Remove the function keyword. You use function when you're defining a function. But here you're only calling one. (You defined it in queries.php.)
Third, I agree with webbiedave about the echo statements. A good way to avoid that: In the "heart" of your app, collect all the HTML into one place. Then, when you've collected everything you're going to display on the page, you can echo it all at once. This makes it a lot easier to keep track of what you're doing, and to remember the order of everything. It also makes it easier to add headers and footers, or do more formatting. Otherwise, if you have echo statements scattered around your code, it's a lot easier to let something slip that shouldn't be there.
Here's a very basic example of what I mean:
$html = '';
$results = getUserUpdates($_SESSION['user_id'];
while($row = mysql_fetch_array($results)) {
$fields = array(
'user_note' => $row['user_note'],
'dt' => $row['dt'],
'picture' => $row['picture'],
'username' => $row['username'],
'id' => $row['id'],
'reply_id' => $row['reply_id'],
'reply_name' => $row['reply_name'],
'votes_up' => $row['votes_up'],
'votes_down' => $row['votes_down'],
);
$html .= formatUpdate($fields);
}
// This way you can do whatever you want to $html here.
echo $html;
Also notice that I put all the fields from $row into an array and passed it to formatUpdate(). That has two advantages:
It's easier to read.
If you ever
want to change the fields that
formatUpdate deals with, you don't
have to worry about searching
through your code to change the
arguments every time you call it.
Firstly, I think you mean:
$results = getUserUpdates($_SESSION['user_id']);
In your getUserUpdates() function there is a redundant branch:
if ($username == $_SESSION['u_name']){
// return something
}
if ($username != $_SESSION['u_name']){
// return something else
}
You don't need the second if statement as any code run at that point will only be run if $username != $_SESSION['u_name'].
In my opinion, it's usually better not to have different functions directly echoing HTML up the stack (such as echoVote()). It's preferred to have functions return data and have the original caller echo it. This allows the caller to perform additional data massaging if desired.
Other than that, your code is fetching data, looping through and acting on the results which is pretty much standard fare.
I think your instinct is to be a little too harsh on yourself ;) There are improvements to be made but it's certainly not the worst way to do anything.
Related
I'm trying to store multiple data and then at the end go a head and push the data into the new .ini file. I found solutions which works but I want to get all the data first and then update the file at the end but the solutions i found updates the file straight away!
A solution I liked and worked is located: https://stackoverflow.com/a/36997282/6613233
I am trying to allow it gather information and then push it to the file at the end. My own attempt at this is below but i keep getting array array in my ini file.
Code:
$fbsettingsDB = parse_ini_file("location.ini", true);
$fbsettingsDB["id"]["value"] = $_POST['fbconfigid'];
$fbsettingsDB["location"]["value"] = $_POST['fbconfigcty'];
file_put_contents('location.ini', implode("\n", $fbsettingsDB));
The above is how I want to collect data. I have a bunch of code which goes in and out of statements, I want it to go ahead.. Assign the values required and at the very end go ahead and put the contents in the file like shown above.
Using the referred code i would then have to do:
config_set("location.ini", "id", "value", $_POST['fbconfigid']);
config_set("location.ini", "location", "value", $_POST['something']);
config_set("location.ini", "result", "value", $_POST['somethingelse']);
Which overwrites the file every time which in my opinion is just crazy! Overkill for my idea, there is obviously some way that can suit my needs so i can just call the function once after making a list of edit/changes and then when i call the function it grabs all my changed data and saves the file the way i want it!
I'll try to explain first why your code doesn't work, compared to the other.
Your inifile-array is build up of a nested array, $array[section][item] = value. The first dimension has the section names. The second dimension is the name of the items in the sections. So $fbsettingsDB["location"] contains an array of items, of which "value" is one.
Implode doesn't check if the array is nested. It just takes the first dimension (the sections) and tries to treat their values as a string. Since those values are actually arrays of items, PHP just converts that to the text 'array'.
Apart from that, you can't just implode the whole array. Section names should be enclosed in square brackets, so there is a little more work to do in that regard too.
If you check the solution in the answer you referred to, you'll see that it contains a loop which takes care of the first layer, the sections.
The array of items of each section is converted separately with implode, which is then prefixed by the section name in square brackets, and the whole lot is appended to the end result.
So, your intention here: You don't want to set a value and write it back to file at once, but update multiple values and only write the end result to disk. Well, fortunately the function doesn't have to be atomic. It already performs three separate actions: loading from disk, modifying the data, and serializing it back to disk. Let's see if those can be isolated in separate functions:
Read the data. Well, hardly worth to make a function, but it may make your application somewhat more consistent if you use the same naming et cetera in a collection of related functions.
Note: I just wrote these from scratch. No PHP at hand to test, so they might contain minor syntactical errors.
So here it is:
// Loads ini file data
function config_read($config_file) {
return parse_ini_file($config_file, true);
}
Setting the config in the loaded data. Again, hardly worth to have a function, but it adds readability and hides how exactly the ini file data is built up, so you don't have to worry about implementation details when using it. Note that the array is passed by reference. The array you specify is updated. The function doesn't return a value.
// Update a setting in loaded inifile data
function config_set(&$config_data, $section, $key, $value) {
$config_data[$section][$key] = $value;
}
Then writing it:
// Serializes inifile config data back to disk.
function config_write($config_data, $config_file) {
$new_content = '';
foreach ($config_data as $section => $section_content) {
$section_content = array_map(function($value, $key) {
return "$key=$value";
}, array_values($section_content), array_keys($section_content));
$section_content = implode("\n", $section_content);
$new_content .= "[$section]\n$section_content\n";
}
file_put_contents($config_file, $new_content);
}
Note that so far I didn't modify any of the code. I just wrapped it in separate functions. If you like, you could even call those functions in another function, so you still got the shorthand to write everything to disk at once. You'll have the original functionality, but without having duplicate code:
// Short-hand function for updating a single config value in a file.
function config_set_file($config_file, $section, $key, $value) {
$config_data = config_read($config_file);
config_set($config_data, $section, $key, $value)
config_write($config_file, $section, $key, $value);
}
So, now you got this collection of functions, you can decide which to use based on the situation. If you just want to update a single value, you might as well write this:
config_set_file("location.ini", "id", "value", $_POST['fbconfigid']);
But if you have multiple configs to set, you can do this:
// Load
$config_data = config_read("location.ini");
// Set multiple values
config_set($config_data, "id", "value", $_POST['fbconfigid']);
config_set($config_data, "location", "value", $_POST['something']);
config_set($config_data, "result", "value", $_POST['somethingelse']);
// Save
config_write($config_data, $config_file);
I can imagine you can add other shorthands, like config_set_array_file, which you could call like this.. I'll leave the implementation of this one to you for exercise. ;)
array_config_set_file($config_file, array(
"id" => $_POST['fbconfigid'],
"location" => $_POST['something'],
"result" => $_POST['somethingelse']));
And after that, you can poor all this into an IniFile class to make it even nicer. :)
My site has a large number of products in the database. I want to add a product sheet for each product but the database has no set "slot" for it. So I was thinking of writing a php code into the template which checks the part number and use this to load the correct url for the product sheet as a link. For Example
<?php
if (strpos($product_sku,'KE15000/12') !== false) {
$factsheetimage_urlZ='/images/FactsheetBTN.png';
$factsheetweblink_url="images/factSheetKE15000/12.pdf";
} else if (strpos($product_sku,'KE2000/12') !== false) {
$factsheetimage_urlZ='/images/FactsheetBTN.png';
$factsheetweblink_url="images/factSheetKE20000/12.pdf";
} else {
$factsheetimage_urlZ='/images/blank.png';
}
?>
<div>
<a href="<?php echo $factsheetweblink_url;?>">
<img src="<?php echo $factsheetimage_urlZ;?>"></a>
</div>
At moment I'm using if else statements (I'm pretty new to PHP) and I was wondering if there's a way to check the $product_SKU against an XML document to auto load the correct link rather than doing around 300 if else statements. ($product_SKU is the unique product code loaded on each page)
There are a few ways to go about it.
If the $factsheetweblink_url can be generated base on the $product_sku in some programatic way, that would probably be my first preference. eg. $factsheetweblink_url = "images/factSheet{$product_sku}.pdf";
Secondly, adding this column to the database would be a the best option if possible.
Otherwise, the lookup table you mention is certainly possible, XML is one option. If you're writing it by hand, or it needs to be written by a non-technical person would be some considerations for choosing a format. If it's just you, I'd probably use a simpler format (even a plain PHP array).
A simple example of this type of mapping as a PHP array might look like:
sku_url_map.php:
<?php
return [
'KE15000/12' => 'images/factSheetKE15000/12.pdf',
'KE20000/12' => 'images/factSheetKE20000/12.pdf',
];
product_page.php:
<?php
$sku_url_map = require 'sku_url_map.php';
// ...
if (isset($sku_url_map[$product_sku])) {
$factsheetweblink_url = $sku_url_map[$product_sku];
}
of course, more complex structures can be used if it's more that a simple 1:1 mapping.
Lets say I've got 50 pages, and I want to write a description for about 30 of them.
The description will be about two paragraphs on each page.
Is it more efficient for my server if I save the descriptions in a MySQL database and then query on each page to see if there is a corresponding description, or is it best if I store them in an array in my PHP file and see if the element exists?
Extra Info:
I would edit the array file manually or the db entry through phpMyAdmin which would both take the same amount of time. Also it would only be me editing them so I don't have to worry about making a quick edit file.
Do it like this:
Store them in an array, in a sepparate file data.php, in this form:
<?php
return array(
// here be data
);
In the caller script you use it like this:
$data = require 'data.php';
and then use the $data variable throughout the site, as needed. You could also split the array and use several files based on specific criterias, like "the language", or "article category" or whatever.
If you do it this way, you can always plug in an editor with a web interface to edit that array and store it back with file_put_contents('data.php', '<?php return '. var_export($data));, where $data has got its value after processing a POST form, for instance, which was generated from the old value of $data.
Really elegant, fast, and maintainable!
As a bonus, write helper functions around those serializations, deserializations, etc, such that if you ever change your mind (because your site grows and you end up with hundreds of such arrays), you only have to reimplement those functions to use a database backend, without ever touching the rest of the codebase.
Code reusability and maintanability at its peak! And you get it up and running immediately, without losing the prospect of making it better in the future, if required.
If you don't change those descriptions frequently, you can store them in array. But it'll be better to keep them in separated files, instead of keeping them all in one PHP file.
But your server can easily handle that kind of small rows. So do what is easy for you.
Maybe you can store them in database for adding/editing stuff and do a cache of it to read from your page.
I would store the information in a DB. It is more slowy but more elegant.
If you want to do it with an array:
Class Page
{
// global configuration
private static $config = null;
// individuel configuration
public $title, $content;
// constructor
function __construct($page) {
// get the configuration
$config = self::getConfig();
// cheack weather the page exists
if(!isset($config[$page]))
die('unknown page "'.$page.'"');
// set some stuff
$this->title = $config[$page]['title'];
$this->content = $config[$page]['content'];
}
// get the configuration
private function getConfig() {
if(self::$config === null)
self::$config = include(dirname(__FILE__) . '/config.php');
return self::$config;
}
}
Configuration:
return Array(
'home' => Array(
'title' => 'Welcome!',
'content' => 'Welcome to my site!' /* maybe include some html for complxe stuff */
)
);
Example:
$myPage = new Page('home');
echo $myPage->content;
I'm using Wordpress and developed some site-specific plugins for it, additionally my theme is customized to fit the requirements of the plugins in the backend.
The last days I fiddled with transients in Wordpress. In some tutorials they're saying "If your're using custom queries and their results are cachable: Use a transient". Sounds good but I'm wondering when to use transients to get a real advantage.
I mean, even when using transients there have to be at least two queries in the background, haven't it? The first one for checking the validity, second one for the transient itself.
So is it really useful to use a transient i.e. for a custom WP_Query?
Thanks a lot for your help and thoughts.
Seems fairly straightforward. It's a literal class helper that allows you to store objects in a 'memcache' type fashion. You first set the transient
function do_something_here($callback_param = 'value'){
$key = 'do_something_' . $callback_param;//set the name of our transient equal to the value of the callback param being passed in the function.
$my_query = get_transient($myKey); //if we've stored this request before, then use it.
if($my_query !=== false){
//we found a previous existing version of this query. let's use it.
return $my_query;
}else{
//it doesn't exist, we need to build the transient.
//do our database querying here, global $wpdb; etc
//We are going to pretend our returned variable is 'george'
$value = george;
$length = 60*60*24; //how long do we want the transient to exist? 1 day here.
set_transient($key, $value, $length);
return $value;
}
}
Now that we have created our trigger and bound it to the name of '$key', we can access it anytime by using the exact value that key implies (which we declared earlier).
echo 'I wanted to do something, so : ' . do_something('value') . ' is what i did! ';
By utilizing this format you can hold queries in a 'cache' like world and use them to generate your responses. This is similar in a way to using 'trigger' events in MySql. Infact, this is a PORTION of a TECHNIQUE commonly referred to as long polling.
I'm working on a patch to submit to the Registration Code module for Drupal. In short, is there a more efficient way to write the code below?
if (module_exists('regcode_voucher')) {
$cnfg = variable_get('regcode_voucher_display', array('regform' => 'regform'));
if (empty($cnfg['regform'])) {
return;
}
}
It seems like I should be able to reduce it to one if statement with && combining two conditions, but I haven't found the syntax or the necessary php array function that would allow me to do that.
In case some context helps, the regcode_voucher sub-module allows users to enter their registration code on the user edit page. On our sites, after a "beta" period, we want to simplify the registration form by removing the registration code field; but we'd like users to still be able to enter the code on their account edit page. The code above is part of a patch that allows the regcode's hook_user changes to be bypassed.
Code looks like good, what efficient do you want? Little changes may be:
if (module_exists('regcode_voucher')) {
$cnfg = variable_get('regcode_voucher_display', null);
if ($cnfg) {
// do your actions
}
}
And I don't recommend to merge if..., code should be clear and simpler to understand. If you merge these for optimizing, you win "tiny" milliseconds for real-live processors, but lost your clean code.
Why are you returning an array from variable_get if the variable is not found? variable_get will always return a string or a serialized array (that needs to be unserialized). If I'm missing something, you can use array_key_exists('regcode', variable_get(...)) to check for the array key.
This should work... note returning "false" from variable_get as a default if the variable is not found, which will cause the if conditions to not match. I personally find this more readable than nested if statements (for 3+ conditions I'd nest, though).
if( module_exists('regcode_voucher') && variable_get('regcode_voucher_display', false) ) {
// stuff
}