Reducing Mysql Querys & OOP - php

Let's say I have:
class language_text{
protected $id;
protected $keyword;
protected $language;
protected $text;
function __construct($clave,$lan){
$consulta = mysql_query("SELECT id,clave,lengua,texto,id_usuario FROM textos WHERE clave = '$clave' AND lengua = '$lan'");
if(mysql_num_rows($consulta)>0){
while($item = mysql_fetch_array($consulta)){
$this->id = $item['id'];
$this->clave = $item['clave'];
$this->lengua = $item['lengua'];
$this->texto = $item['texto'];
$this->id_usuario = $item['id_usuario'];
$this->exists = true;
}
return true;
}else{
$this->exists = false;
$this->clave = $clave;
return $this->clave;
}
}
}
function get_texto_clave_html($clave){
$clave = htmlspecialchars($clave);
$lan = detectarIdioma();
$temporal = new texto($clave, $lan);
if($temporal->exists()==true){
return $temporal->get_texto_html();
}else{
return $clave;
}
}
}
So everytime I need some language text I call: get_texto_clave($lan, $keyword), but in every page might be about 25 texts, so I think I should load all language in an array and then access it instead of the database.
For example:
I want welcome text under Spanish get_texto_clave(2,'welcome_html');
I want goodbye text under Spanish get_texto_clave(2,'bye_bye_html');
Questions:
What do you think about it?
Would you add a new class like language_text_collection or something like that?
Thanks to experimentX contribution, here we have current solution:
Use static method to get the instances of object.
$data = language_text::getData($lan, $keyword);
And on getData method
public function getData($lan, $keyword)
{
$data = array();
//query here
$consulta = mysql_query("SELECT id,clave,lengua,texto,id_usuario FROM textos WHERE clave = '$clave' AND lengua = '$lan'");
while($item = mysql_fetch_array($consulta))
{
$selfitem = new self;
$selfitem->id = $item['id'];
$selfitem->clave = $item['clave'];
...
...
$data[] = $selfitem;
}
return $data[]; //end the end you send an array of data
}
Now $data will contain an array of objects. Use the loop to access its properties.
foreach($data as $d)
{
echo $d->id;
echo $d->clave;
...
...
}
but I can't see it yet,
I asume in $data we have all language text for current languageId,
so, how i can i extract, for example, 'welcome_body' from $data?

UPDATE::
I think database is not quite suited for this kind of operation. I would advise you to revise your database design.
+----+---------------+---------------+----------+
| id | message_type | message_text | language |
+----+---------------+---------------+----------+
| 1 | good morning | good morning | english |
| 2 | good_morning | something.... | spanish |
+----+---------------+---------------+----------+
First create a database like
Create a database object to query database like this one.
//do not use keyword, its no use at all
//Of course it's pointless say good morning and at the end ...goodbye in some language
//and also logically, it's useless because we have to query data
$message = language_text::getData($lan);
Your query must be something like this SELECT* FORM message WHERE language='english' or something. //also it's better to add DISTINCT for selecting. I will explain later why.
And use the the content message_type type to add property to the object.
while($item = mysql_fetch_array($consulta))
{
$selfitem = new self;
$selfitem->$item['message_type'] = $item['message_type'];
$data[] = $selfitem;
}
return $data;
And now echo out the property echo $data->hello_message; or goodbye message
Now, you have to consider that no two duplicate entry for message_type should be added for same language. So, it's better to add DISTINCT in select statement. And also you have to check it.
OTHER WAY:: You can also create database with static messages, its not flexible, but reliable, and can be used with the other method i presented to you.
+----+------------+--------------+-------------+
| id | language | goodmorning | goodnight |
+----+------------+--------------+-------------+
| 1 | english | good morning | good night | -- and so on and on
| 2 | spanish | something....| .......... | -- and so on and on
+----+---------------+-----------+-------------+
NOTE::Usually the content of page is loaded at once than to load one by one.
PS::Your english is terrible.

Related

PHP sorting multi-dimensional arrays based on values but getting unexpected results

so I've been scratching my head about this one for a while and almost there but still getting unexpected results.
So I have a database containing the following data
username | level1 | level2 | level3
user1 | 39.76072 | 79.41869 | 151.2955
user2 | 39.80072 | 80.73846 | 270.6498
user3 | 39.84072 | 80.81845 | 83.41801
user4 | 39.85321 | 80.90525 | 88.31719
user5 | Zero | Zero | Zero
I've been trying to put these into a multi-dimensional array in order from the lowest to the highest but have really been struggling. These are basically level times and I'm trying to create a leaderboard.
I assume the problem is that the level columns are not INT but rather CHAR
I am currently trying the following
function order_by_time($a, $b) {
return $b["Level".$_POST["level"]] < $a["Level".$_POST["level"]] ? 1 : -1;
}
$query = mysqli_query($con, "SELECT userName, Level".$_POST["level"]." FROM table");
$results = array();
$unranked = array();
while($line = mysqli_fetch_array($query, MYSQLI_ASSOC)){
if($line["Level".$_POST["level"]] == "Zero"){
$unranked[] = $line;
} else{
$results[] = $line;
}
}
usort($results, "order_by_time");
$results = array_merge($results, $unranked);
This works for level1 and for level2 but not for level3.
Level1 displays as it does in the aboce database example and so does level2 but the problem is so does level3 and that isn't the correct order.
it looks like its something to do with the number of characters before the decimal.
Any advice on how i can resolve this without touching the database? that isn't really an option as its already being used.
I'd really appreciate some help with this :-)
First off, don't inject something from $_POST directly into an SQL query. That's how sites get hacked. In this particular case, I'd recommend setting a variable with that parameter cast to integer, and check its value as well:
$level = (int)$_POST["level"];
if ($level > 0 && $level < 4) {
$query = $con->query("SELECT userName, Level$level FROM table");
} else {
die();
}
As to your question, the simple solution here is to sort in the database. ORDER BY Level$level and you're done.
$level = (int)$_POST["level"];
if ($level > 0 && $level < 4) {
$query = $con->query("SELECT userName, Level$level FROM table ORDER BY Level$level");
} else {
die();
}
$results = $query->fetch_all(MYSQLI_ASSOC);
If that's not possible for some reason, what you've got there should be working just fine according to my testing. But it's rather hacky, especially pulling information from $_POST to a custom function. Instead just use PHP's built-in abilities to work with multidimensional arrays.
$level = (int)$_POST["level"];
if ($level > 0 && $level < 4) {
$query = $con->query("SELECT userName, Level$level FROM table");
} else {
die();
}
$results = $query->fetch_all(MYSQLI_ASSOC);
$usernames = array_column($results, "username");
$times = array_column($results, "Level$level");
array_multisort($times, SORT_ASC, $results);
The only reason I can think of that this wouldn't work would be that there are some leading or trailing spaces in the values that are preventing them from being converted to numbers for the comparison.
If you're just echoing them out in HTML, you probably wouldn't see the spaces, but you'll see them if you var_dump the variable. The normal behavior of PHP is to compare numeric strings as numbers, but it won't work that way if there are extra spaces.
$test = '151.2955' > '83.41801';
var_dump($test); // true
$test = '151.2955 ' > '83.41801 ';
var_dump($test); // false
Try trimming the values.
$query = mysqli_query($con, "SELECT userName, TRIM(Level3) AS userValue FROM table");
The expression is aliased, so refer to it in your PHP code as $row['userValue'] rather than using the value from $_POST. If this does work, it may also let you use ORDER BY in MySQL. I'm not really sure if whitespace has the same result there as it does in PHP. I think you'll need to cast the column to a numeric type for it to sort properly regardless of spaces. It's unfortunate that you can't alter the table to store the number as a number.

Selecting associative array in mysql

I currently have the following:
$query='select concat("[",key,"=>",value,"]")
from table';
if(isset($query))$r=$mysql->query($query);
if(isset($r)){
for($i=1;$i<=$r->num_rows;$i++){
$r->data_seek($i-1);
$a[$i-1]=$r->fetch_array(MYSQLI_ASSOC);
$a[$i-1]=parse_array($a[$i-1]);
}
}
$mysql->close;
function parse_array($parent){
foreach($parent as$k=>$val){
if(strpos($val,']')){
$array=explode(',',substr($val,1,-1));
foreach($array as$val){
$keypair=explode("=>",$val);
$newarray[$keypair[0]]=$keypair[1];
}
$parent[$k]=parse_array($newarray);
}
}
}
There has to be a more elegant way of doing this - perhaps built into MySQL? I'm trying to minimize the time this spends running PHP - I would like it to arrive to PHP already in array form, but MySQL kicks Subquery returns more than one result if I attempt a subquery.
Edit: Here's table:
+----------+----------+
| value | key |
+----------+----------+
| img.jpg | src |
+----------+----------+
Output should be:
[
'src'=>'img.jpg'
]
Just move all of the manipulation over to php. Fetch the query with numeric indexes. Make the assumption that the every even index is a key and every odd index is a value (or vice versa).
$query = 'select key1, value1, key2, value2
from table';
if(isset($query))
$result = $mysql->query($query);
if(isset($result)) {
$newResult = []; // if your version of php doesn't support this syntax to create a new array use `$newResult = array();`
while($row=$result->fetch_array(MYSQLI_NUMERIC)) {
$newResult[] = build_assoc_array($row);
}
}
$mysql->close;
function build_assoc_array($flat_arr) {
$newArr = [];
$numCol = count($flat_arr);
for($colIndex = 0; $colIndex < $numCol; $colIndex+=2) {
$newArr[$flat_arr[$colIndex]] = $flat_arr [$colIndex+1];
}
return $newArr;
}

How to get recursively all analogs from table by an article?

I've create a simple table of analogs:
+----+-------+-------+
| id | sku_1 | sku_2 |
+----+-------+-------+
| 1 | a1 | abcd |
| 2 | a2 | a3 |
| 3 | a3 | a1 |
+----+-------+-------+
3 rows in set (0.00 sec)
What it mean? It mean that product with article abcd has an analog with article a1, otherwise for example product with article a3 has an analog with article a1.
How to recursively get all the products from this table by a single article?
My solutions is wrong:
// Small Class to get analogs of products
class Analogs {
public function get_analogs($sku)
{
if (!$sku) return false;
$link = mysql_connect('localhost','','');
mysql_select_db('test');
$sku = mysql_real_escape_string($sku,$link);
$query = mysql_query("SELECT * FROM analogs WHERE sku_1='".$sku."' OR sku_2='".$sku."'");
while($analogs[]=mysql_fetch_assoc($query))
continue;
return $analogs;
}
public function MixedAnalogs($sku)
{
if (!$sku) return false;
$link = mysql_connect('localhost','','');
mysql_select_db('test');
$sku = mysql_real_escape_string($sku,$link);
$query = mysql_query("select sku_1 sku from analogs where sku_2 = '$sku' UNION
select sku_2 sku from analogs where sku_1 = '$sku'");
while($analogs[]=mysql_fetch_assoc($query))
continue;
return $analogs;
}
}
$mixed_analogs = AnalogsMix('abcd',$ids=array());
echo "<pre>";
print_r($mixed_analogs);
echo "</pre>";
// Recursive function to get analogs of analog
function AnalogsMix($sku,$ids=array())
{
$class_analogs = new Analogs();
$analogs = $class_analogs->get_analogs($sku);
foreach ($analogs as $analog)
{
$cross = null;
if ($analog['sku_1']==$sku)
{
$cross->sku = $analog['sku_2'];
}
else
{
$cross->sku = $analog['sku_1'];
}
$cross->id = $analog['id'];
if (!in_array($analog['id'],$ids))
{
$ids[] = $analog['id'];
$mixed[] = AnalogsMix($cross->sku,$ids);
}
}
if (isset($mixed))
{
return $mixed;
}
else
{
return false;
}
}
SQL UNION
select sku_1 sku from analogs where sku_2 = $yourid
union
select sku_2 sku from analogs where sku_1 = $yourid
Then you will get in results only ids of analogs.
Here, I suppose you have all your pairs in an array. For example, for your example, you would call analogsOf(array(array("a1", "abcd"), array("a2", "a3"), array("a3", "a1")), "abcd").
The idea is that you build a list of analogs containing initially only the string you are looking for and, every time you find an analog, you add it to the list of analogs and reiterate. You do so until you iterated the whole array of pairs without finding anything new.
function analogsOf(array $pairs, $key) {
$res = array($key); // The result, with only the given key
$i = 0; // Index of the current item
$changed = false; // Have we added an item to $res during that iteration ?
while ($i < count($pairs)) {
$current = $pairs[$i];
foreach ($res as $item) {
if (($current[0] === $item) && (!in_array($current[1], $res)) {
$res[] = $current[1];
$i = 0; // Reiterate as $res changed
}
else if (($current[1] === $item) && (!in_array($current[0], $res)) {
$res[] = $current[0];
$i = 0; // Reiterate as $res changed
}
else {
$i++; // Nothing found here, go to next item
}
}
}
return $res;
}
Note that this code was NOT tested, so there might be a few bugs here and there, but you've got the idea. Also note that I considered you could put the whole database content in an array, but that is probably not possible for obvious reasons, so you will probably have to adapt the code above.
I found a solution for this problem but the main problem in this approach is that.
it can make a loop like abcd->a1,a1->a3,a3->a2,a2->abcd. and it make recursive function endless and php throw an error. so you have to check for that if it is a big project.
in my solution i consider it parent-> child relation. and if a child found make it parent and check again and so on until there is no result.
let abcd is parent and after first execution a1 is child and relation is abcd->a1. but in next call a1 is parent and from first row of table it give a new relation that is a1->abcd and loop is endless.
To prevent checking in same row i use ID of last row from database and it now check row where id != ID (always check other row)
this is function i write, convert it according to your class and store the value in array as you like. I use a string only.
i knew it not a good solution but i works fine.
<?php
mysql_connect('localhost','','');
mysql_select_db('test');
function getSku($sku, $id, $rel = '') {
$query = mysql_query("SELECT * FROM analogs WHERE sku_1 = '$sku' AND id != '$id'" );
if (mysql_num_rows($query)) {
$row = mysql_fetch_assoc($query);
$sku = $row['sku_2']; //PARENT SKU
$id = $row['id']; //LAST ID
$rel .= $row['sku_1']. '-->' . $row['sku_2']. "<br>";
} else {
$query = mysql_query("SELECT * FROM analogs WHERE sku_2 = '$sku' AND id != '$id'" );
if (mysql_num_rows($query)) {
$row = mysql_fetch_assoc($query);
$sku = $row['sku_1']; //PARENT SKU
$id = $row['id']; //LAST ID
$rel .=$row['sku_2']. '-->' . $row['sku_1']. '<br>';
} else {
return (string)$rel; //NOTHING FOUND
}
}
return getSku($sku,$id,$rel);
}
echo $new = getSku('abcd','-1');

How do I process multiple results from a SQL query sharing a common ID?

I'm failing miserably to get my head around what I know ought to be simple, and am unsure if the solution lies in the query or in processing the result, so struggling to search for what I'm sure has been covered in another post.
I'm working with a single MySQL table, from which I need to be able to retrieve and process content that shares a common ID. Unfortunately, restructuring the database isn't an option.
Here's what a simple SELECT * WHERE contentID = '2' query returns:
|contentType|contentID|content |
--------------------------------------
|title |2 |<h1>title</h1>|
|intro |2 |<p>intro</p> |
|main |2 |<p>main</p> |
What's the correct way to retrieve the specific 'title', 'intro' or 'main' content?
Thanks in advance.
$result = mysql_query("SELECT * WHERE contentID = '2'");
$array = array();
while($rows = mysql_fetch_array($result,MYSQLI_ASSOC)){
$array[$rows['contentType']] = $rows['content'];
}
You can use the $array for each content type
Fetch all the rows into an array:
$data = array();
foreach ($rows as $r) {
$data[$r['contentType']] = $r['content'];
}
You'd have to put your content type into the where clause. The Id and type should form a natural ok and should be constrained as such. If not, time to redesign. Also, id consider putting the content type as a lookup rather than a string.
<?php
function executeQuery($query,$connectionObject)
{
queryString=$query;
recordSet=mysql_query(queryString,$connectionObject);
if(!$recordSet)
{
$errorString=mysql_error($this->connectionObject);
return array("error"=>$errorString);
}
return recordSet;
}
function getNextRecord($recordSet)
{
$resultArray =mysql_fetch_assoc($recordSet);
if(!empty($resultArray))
return($resultArray);
else
return "false";
}
$result = executeQuery("SELECT * FROM foo WHERE contentID = '2'");
$nextRecord = getNextRecord($result);
while($nextRecord!="false")
{
$nextRecord = getNextRecord($result);
//...........Process the record.....
->$nextRecord['contentType'];
->$nextRecord['contentID'];
->$nextRecord['content'];
//..................................
}

Passing value from php to?

I am going to select a list of items from a table, and pass it using json-framework.
Example, I want to select friends from my "shirts" table, from "players_shirts" table
pid | sid
================
1 | 2
2 | 3
1 | 5
Lets say, I get 30++ result (rows).
I assume (not yet tested this code), in php, I assign it by:
$array;
$count = 0;
while($r = mysql_fetch_assoc($exe){
$array[$count] = $r['sid'];
// EDIT START: I forgot to add counter
$count++;
// EDIT END
}
echo json_encode($array)
Is this method efficient/good enough?
I am new to php/database/manipulating data from database.
There is no need to specify an array keys in your case, so your code could be rewritten as:
$array = array();
while($r = mysql_fetch_assoc($exe){
$array[] = $r['sid'];
// or you may use array_push($array, $r['sid']); instead of the line above.
}

Categories