Building pricing logic using PHP - php

Hope y'all are having a wonderful day full of rainbows and roses!
Ok, ok .. I'll get to the point:
I've got a function that accepts multiple parameters and calculates the price of a product based on those parameters. Here's a conceptual example:
public function getPrice( $params ) {
// black magic goes here
return $price;
}
The parameters include:
$params[width] which ranges all the way from 10 - 72 inches
$params[height] which ranges from 10 - 44 inches
(There are actually more params, but for the sake of simplicity, I've kept those out).
Now, I have a table in Excel (something like a truth table) with rows that represent the width and columns that represent the height. The value in the corresponding cell is the price.
How could I best implement this pricing strategy in PHP? I thought nested if statements would work but got tired after the 10th if. Help?

You could store the information from Excel in a 2D array.
I.e.
$prices = array( // Columns --
array(1,2,3), // Rows
array(4,5,6), // |
array(7,8,9) // |
);
Then you can look up your price based on width/height by doing:
return $prices[row][column];
In your case, row would be width and column would be height.
Some extra work would be required as you have a range starting at 10, so you'd need to subtract 10 from the value you enter.
I.e:
return $prices[width-10][height-10];.

Why wouldn't you just put all that data in your database? Have a row with all values of every parameter, and the accoriding price ? It's just 1 query away ...

Related

How to insert / store multiple items in a single cell DataBase using PHP & MYSQL

I have a column named - points in a table
I need to insert/store multiple values inside a points column field and display them as list items
EX: points (column):
[100% Wool, Width approx 72cm / 28 inches, Can be used as an area carpet]
output required:
100% Wool
Width approx 72cm / 28 inches
Can be used as an area carpet
My way was to do it with an array, but how?
May I know any other ways to handle it using php & MySQL.
Yes, you can store an array in a single table column. But first you need to convert the array into a string. For examle:
$dataarray = [
'title' => '100% Wool',
'properties' => [
'Width approx 72cm / 28 inches',
'Can be used as an area carpet'
]
]
$datastring = serialize($dataarray); // returns string
// save to to your database, using $datastring as a value for the 'points' column
[...]
After you read the data from your database again, simply un-serialize the stored data and you get the array back:
// load data from database
[...]
$datastring = $row['points'];
$dataarray = unserialize($datastring);
print_r($dataarray);
be aware that there are limits to the amount of data a single mysql-column can store, see https://dev.mysql.com/doc/refman/8.0/en/char.html
as an alternative to serialize() / unserialize(), you may use json_encode() / json_dencode(), which is a bit safer and uses a more universal storage format, see https://www.php.net/manual/en/function.unserialize.php

dynamic calculation of simple math expression

We are taking simple math expression as inputs from user and want to evaluate it. Total number of fields are also dynamic. Each field contains the specific css class as per their index. For example, 1st field has css field "col1", 2nd field has "col2" and so on.
Users gives us input in the form of
"col5 = col4 * col3"
We are converting it to
jQuery(".col5").val(jQuery(".col4").val() * jQuery(".col3").val())
using str_replace function. To do so, we need to do loop for total no of fields. (below is php code example)
for($colLoop = 0; $colLoop < $total_cols; $colLoop++){
$formula = str_replace("col$colLoop","parseFloat(jQuery('.col$colLoop input').val())", $formula);
}
This works but we are looking for some proper solution as it's loops unnecessary for all fields. Is it possible using some other methods? Let us know

PHP increment booking number according to the last booking number in database

I'm using PHP 7 with Phalcon PHP and I'm trying to create a method to generate a booking number. Here is my current method :
public function generateNumber($company_code) {
// Build the prefix : COMPANY20190820
$prefix = $company_code . date('Ymd');
// It's like SELECT count(*) FROM bookings WHERE number LIKE 'COMPANY20190820%'
$counter = Bookings::count(array(
"number LIKE :number:",
"bind" => array('number' => $prefix.'%')
));
// Concat prefix with bookings counter with str_pad
// COMPANY20190820 + 005 (if 4 bookings in DB)
$booking_number = $prefix . str_pad($counter + 1, 3, 0, STR_PAD_LEFT);
// Return COMPANY20190820005
return $booking_number;
}
So I have a problem because sometime I have to delete 1 or multiple bookings so I can get :
COMPANY20190820001
COMPANY20190820002
COMPANY20190820005
COMPANY20190820006
COMPANY20190820007
And I need to add after the last in my DB so here 007, because I can get duplicated booking number if I count like that.
So how can I do to take the last and increment according the last booking number of the current day ?
You need to rethink what you want to do here as it will never work that way.
As I see it you have at least two options:
Use an auto-increment id and use that in combination with the prefix
Use a random fairly unique string (e.g. UUID4)
You should never manually try to get the current maximum id as that may and most likely will at some point result in race conditions and brittle code as a result of that.
So I found a solution, maybe there is a better way to do that but my function works now:
public function generateNumber($company_code) {
// Build the prefix : COMPANY20190820
$prefix = $company_code . date('Ymd');
// Get the last booking with the today prefix
// e.g : COMPANY20190820005
$last_booking = Bookings::maximum(array(
"column" => "number",
"number LIKE :number:",
"bind" => array('number' => $prefix.'%')
));
// Get the last number by removing the prefix (e.g 005)
$last_number = str_replace($prefix, "", $last_booking);
// trim left 0 if exist to get only the current number
// cast to in to increment my counter (e.g 5 + 1 = 6)
$counter = intval(ltrim($last_number, "0")) + 1;
// Concat prefix + counter with pad 006
$booking_number = $prefix . str_pad($counter, 3, 0, STR_PAD_LEFT);
// Return COMPANY20190820006
return $booking_number;
}
I reckon that the use case you describe does not justify the hassle of writing a custom sequence generator in PHP. Additionally, in a scenario where booking deletion is expected to happen, ID reusing feels more a bug than a feature, so your system should store a permanent counter to avoid reusing, making it less simple. Don't take me wrong, it can be done and it isn't rocket science, but it's time and energy you don't need to spend.
Your database engine surely has a native tool to generate autoincremented primary keys, with varying names and implementations (SQL Server has identity, Oracle has sequences and identity, MySQL has auto_increment...). Use that instead.
Keep internal data and user display separated. More specifically, don't use the latter to regenerate the former. Your COMPANY20190820007 example is trivial to compose from individual fields, either in PHP:
$booking_number = sprintf('%s%s%03d',
$company_code,
$booking_date->format('Ymd'),
$booking_id
);
... or in SQL:
-- This is MySQL dialect, other engines use their own variations
SELECT CONCAT(company_code, DATE_FORMAT(booking_date, '%Y%m%d'), LPAD(booking_id, 3, '0')) AS booking_number
FROM ...
You can (and probably should) save the resulting booking_number, but you cannot use it as source for further calculations. It's exactly the same case as dates: don't need to store dates in plain English in order to eventually display them to the end-user and you definitively don't want to parse English dates back to actual dates in order to do anything else beyond printing.
You also mention the possibility of generating long pure-digit identifiers, as Bookings.com does. There're many ways to do it and we can't know which one they use, but you may want to considering generating a numeric hash out of your auto-incremented PK via integer obfuscation.
you could split your database field in two parts, so you hold the prefix and the counter separately.
then, you simply select the highest counter for your desired prefix and increment that one.
if you can't change the table structure, you could alternatively order by the id descendingly and select the first. then you can extract its counter manually. keep in mind you should pad the numbers then, or you get #9 even if #10 exists.
if padding is not an option, you can direct the database to replace your prefix. that way, you can cast the remaining string to a number and let the database sort - this will cost some performance, though, so keep the amount of records low.

Magento collection : field occurrence counting

Say I have the following entity called inventory:
I would like to know if there are database, sql or magento actions or any other methods to produce:
I have solved this by iterating through the entire collection and inserting into a temporary table : i.e
$inventorySet = Mage::getModel('custom/module')->getCollection(*);
foreach($inventorySet as $item)
{
$this->insertItem($item->getSku());
}
}
public function insertItem($sku)
{
//insert sku if it does not exist in the temp set
// if it does exists add one to the QTY field
}
I can then retrieve what I want. I don't see an issue with it, but my entity is a lot larger than the example as well as the set of data containing anything between 2000 - 15 000 rows. is there not a more efficient way of doing this?
EDIT: In words, I would like to search the collection for occurrences of the "sku" field and return an array of unique sku's and the number of times it was found in the initial collection.
To get a particular set of column values from a collection you can use the getColumnValues() method.
For example, using a Magento product collection, this would return an array containing the sku attribute value for every product:
$collection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('sku');
$skus = $collection->getColumnValues('sku');
Finally, to answer the second part of your question, to count the occurence of each unique value:
array_count_values($skus);
This will give you a nice associative array of sku => occurrence count.

PHP - Echo amount of pictures based on mysql_num_rows

I want to code a script that will echo an amount of images based on the mysql_num_rows(); function.
Like, I'm storing 3 in a row. Then I'll create:
$images = mysql_num_rows($count);
Then I would like it to echo 3 images.
Is this possible?
If you don't get the question or want me to rewrite it, please just tell me.
Then i think, all you need to do is fetch the rating (i.e. a number) from the database and just use that number directly to display the number of stars. Coz mysql_rows_count would give you the total number of records in a result set which is returned as a result of a select query on multiple columns, but in your case you only need to access one column which would contain the rating and another column which would probably contain user id or some sort of key to associate the ratings with. The result set can be fetched as an associative array which can then be used by indices to fetch the right column. Have a look at this: PHP-mysql_fetch_array() .
EDIT: just to sum up (not the actual syntax) :
$array = mysql_fetch_array(<your select query fetching only the needed columns>);
$images = $array[0] // assuming the rating number is at the 0th index
//image display code, do your stuff
So here is what I did:
I had the numbers from 1-5 in my database in a row called 'rating'. Now when I picked this out of the database I stuffed the number (1-5) into a variable called '$starRating'.
for($i=1;$i<=$starRating;$i++){
echo "<span class='star'><span class='starText'>$i</span></span>";
}
Then I created a class called star and starText:
.star{
width:18px;
height:18px;
background:url('../images/design/smallImg/star.png') no-repeat;
text-align:center;
float:right;
margin-top:2px;
}
/* star content */
.starText{
display:none;
}
.starText is made to hide the text that would've been from the for() loop.
* I don't know if you can avoid the text another way around *
This works for me perfectly.
I wrote this to help people searching for an easy solution to this.

Categories