Problems With My Database Class - php

I'm new to OO PHP and I have created a Database Class, And I have a problem when I build My SELECT Query With the JOIN method.
If I do the Querys in Functions.
<?php
require_once("class.Database.php");
function test1($db) {
$test1 = $db->Select("*")
->From("Table1")
->Join("Table2","table_2_id = table_1_id")
->Join("Table3","table_3_id = table_2_id")
->BuildSelect();
return $test1;
}
function test2($db) {
$test2 = $db->Select("*")
->From("Table4")
->Join("Table5","table_5_id = table_4_id")
->Join("Table6","table_6_id = table_5_id")
->BuildSelect();
return $test2;
}
echo test1($db);
echo "<br>";
echo test2($db);
?>
The problem is that the First function - test1 will print out -
SELECT * FROM Table1 LEFT JOIN Table2 ON table_2_id = table_1_id LEFT JOIN Table3 ON table_3_id = table_2_id - Which is good
But then the second function test2 will print out -
SELECT * FROM Table4 LEFT JOIN Table2 ON table_2_id = table_1_id LEFT JOIN Table3 ON table_3_id = table_2_id LEFT JOIN Table5 ON table_5_id = table_4_id LEFT JOIN Table6 ON table_6_id = table_5_id
The test2 function seems to be printing out the Values from the test1 function's JOIN method as well as its own Values from the JOIN method.
Can someone please help.

Your addition of the Reset() method is what you needed.
All of your member variables except your join array were being reset on each call. For example:
$this->where = trim($where);
Which will replace your where member every time you call your Where() method. In contrast, you are doing this in your Join() method:
$this->join[] = ...
Which adds a value to the end of the member array rather than rewriting what is already in the array. It has the same affect as using array_push() (see here)
One last suggestion I was going to make was to call Reset() at the end of BuildSelect() so that you wouldn't have to remember to do so in your queries, but it looks like you did that. My recommendation, however, would be to change this:
self::Reset();
To this:
$this->Reset();
In reality, either will work and PHP makes them functionally the same for what you are trying to accomplish, but other languages aren't as forgiving. :: is designed to be used to call static members, but earlier versions of PHP do the "automagic" thing of realizing that you are calling from an instantiated class and treating self:: the same as $this->
My understanding is that later versions of PHP (5.3+) refer to what is contained in scope at the point of definition, not the point of execution when you use self::. In most cases, you are going to want to reference the scope of the class at execution time. The two notes I have about that are:
I have never allowed the use of self:: when $this-> is
appropriate, so what I am saying here is only hearsay (I have
never tested it to be true)
Given the fact that your Reset() method doesn't do any form of
logic on instantiated variables, it won't have any adverse affect on
the specific code you are using. But it is best to start with good
coding habits. Some time down the road, this practice WILL bite you if you
continue coding in PHP.
PHP can be great when you are first learning, but the things that make it great for learning often come back to haunt you when you get to making any project of long-lasting consequence if you are not coding deliberately.

Related

Laravel 5. Using the USING operator

I tried to find it for a long time, and I can't believe that Laravel doesn't have this functionality.
So, I can write:
select * from a join b where a.id = b.id
or more beautiful:
select * from a join b using(id)
First case is simple for Laravel:
$query->leftJoin('b', 'a.id', '=', 'b.id')
But how to write second case? I expect that it should be simple and short, like:
$query->joinUsing('b', 'id')
But thereis no such method and I can't find it.
PS: it's possible that the answer is very simple, it's just hard to find by word "using", because it's everywhere.
UPDATE
I'm going deeper to source, trying to make scope or pass a function to join, but even inside of this function I can't to anything with this $query. Example:
public function scopeJoinUsing($query, $table, $field) {
sql($query->join(\DB::raw("USING(`{$field}`)")));
// return
// inner join `b` on USING(`id`) ``
// yes, with "on" and with empty quotes
sql($query->addSelect(\DB::raw("USING(`{$field}`)")));
// return
// inner join `b` USING(`id`)
// but in fields place, before "FROM", which is very logic :)
}
So even if forget about scope , I can't do this in DB::raw() , so it's impossible... First time I see that something impossible in Laravel.
So, the answer is - it's impossible.
Laravel doesn't support this functionality, which is really sad.
I fix it in Laravel source code, my PULL REQUEST here - https://github.com/laravel/framework/pull/12773
Nothing is impossible in Laravel.
Until support for join using is added to Laravel core, you can add support for it by installing this Laravel package: https://github.com/nihilsen/laravel-join-using.
It works like this:
use Illuminate\Support\Facades\DB;
use Nihilsen\LaravelJoinUsing\JoinUsingClause;
DB::table('users')->leftJoin(
'clients',
fn (JoinUsingClause $join) => $join->using('email', 'name')
);
// select * from `users` left join `clients` using (`email`, `name`)

stored procedures vs PDO php pl/pgsql

I have this query in my PHP class:
$this->query = "SELECT a.x, b.y, c.z FROM aaa a INNER JOIN bbb b ON b.ida = a.ida ";
$this->query.= "INNER JOIN ccc c ON c.idb = b.idb WHERE a.ida = :ida";
$this->stmtparam = array(':ida' => $this->ida);
return parent::fillArray(); // it fills a PDO FETCH_ASSOC array and returns it as JSON
suppose that this is a 10 times more complicated query and I have many of this in a company information system;
My question is: Is it possible to make an stored function in postqresql which do the same and returns a SET of many tables, then fetch the results into an associative array in php?
Does it worth to do it?
postgresql does not have stored procedures, but you can write a function which is essentially the same thing. I prefer to put complex queries into a function. This way you can make fixes and performance improvements on the database side instead of having to push out new PHP code each time.
Here's a resource that demonstrates how to create a pg function and call it from PHP:
http://pgedit.com/resource/php/pgfuncall

Having difficulties sorting data from mysql query using php

This code is used to get a specific list of ID's from one table, then use those ID's to get the information from another table. Once I get all the information from the 2nd table, I am attempting to sort the data alphabetically based on a field in the 2nd table.
Example, I am getting the name based on a correlating ID and then want to display the entire result in alphabetical order by name (artist_name).
Here is the code I have. When I execute this without the sort(), it works fine but is not in alphabetical order. When I add the sort() in the 2nd while statement, the page looks the same but the name and other data do not display. The source code in the browser shows that the results are being accounted for but the sort must be preventing the variables or information from being displayed for some reason.
I haven't used a sort function before and I tried looking at some examples but couldn't really find something specific to my situation. Any and all help would be greatly appreciated. I have already looked at the PHP manual for sort so no need to send me a link to it ;-)
<?php $counter = 0;
$artistInfo = mysql_query("SELECT DISTINCT event_url_tbl.artist_id FROM event_url_tbl WHERE (SELECT cat_id FROM artist_tbl WHERE artist_tbl.artist_id = event_url_tbl.artist_id) = 1");
while ($aID = mysql_fetch_array($artistInfo))
{
$getArtistInfo = mysql_query("SELECT * FROM artist_tbl WHERE artist_id = '" . $aID['artist_id'] . "'");
while($artist = mysql_fetch_array($getArtistInfo))
{
sort($artist);?>
<a class="navlink" href="<?=HOST?><?=$artist['page_slug']?>/index.html">
<?=$artist['artist_name']?>
</a><br />
<?php }
}
?>
Your best bet, as a commenter mentioned, is to use an ORDER BY clause in SQL.
SELECT *
FROM artist_tbl
WHERE artist_id = XXX
ORDER BY artist_name ASC
The other commenter who suggested using PDO or mysqli is also correct, but that's a different issue.
To answer your specific question about sorting, according to the manual,
Blockquote Note: This function assigns new keys to the elements in array. It will remove any existing keys that may have been assigned, rather than just reordering the keys.
This means all of your array keys ('page_slug', 'artist_name', etc) are wiped out. So when you try to refer to them later, there is no data there.
Were you to use this method, you would want to use asort to sort an associative array.
However, you don't want to use sort here. What you're sorting is the variables for one row of data (one individual artists), not all of your artists. So if you think of each artist row as an index card full of data (name, id#, page slug, etc) all you're doing is moving those items around on the card. You're not reorganizing your card catalog.
Using an order by clause in the SQL statement (and rewriting in PDO) is your best bet.
Here is how I would rewrite it. I have to take some guesses at the SQL because I'm not 100% sure of your database structure and what you're specifically trying to accomplish, but I think this would work.
$query_str = "
SELECT
artist.name,
artist.page_slug
FROM
artist_tbl AS artist
INNER JOIN event_tbl AS event
ON event.artist_id = artist.artist_id
WHERE
artist.cat_id = 1
ORDER BY
artist.name ASC";
$db_obj = new PDO (/*Connection stuff*/);
$artists_sql = $db_obj->prepare ($query_str);
$artists_sql->execute ();
while ($artist = $artists_sql->fetch (PDO::FETCH_ASSOC)) {
$return_str .= "<a class='navlink' href='{HOST}
{$artist['page_slug']}/index.html'>
{$artist['artist_name']}</a><br/>";
}
echo $return_str;
In all honesty, I would probably create an artist class with a display_link method and use PDO's fetchObject method to instantiate the artists, but that's getting ahead of ourselves here.
For now I stuck with procedural code. I don't usually like to mix my HTML and PHP so I assign everything to a return string and echo it out at the end. But this is close to what you had, using one SQL query (in PDO - seriously worth starting to use if you're creating new code) that should give you a list of artists sorted by name and their associated page_slugs.
You could do all of this in one query:
SELECT * FROM event_url_tbl AS event
INNER JOIN artist_tbl AS artist ON event.artist_id = artist.id
ORDER BY artist.name DESC;
This cuts out a lot of the complexity/foreaches in your script. You'll end up with
Label1 (Label 1 details..) Artist1 (Artist1 details..)
Label1 (Label 1 details..) Artist2 (Artist1 details..)
Label2 (Label 2 details..) Artist3 (Artist1 details..)
Always good to bear in mind "one query is better than many". Not a concrete rule, just if it's possible to do, try to do it. Each query has overheads, and queries in loops are a warning sign.
Hopefully that helps

Codeigniter 2.1 - active record

I have reached dead end with the brain o.O. In DB I have two tables:
store_module->caffe_id, module_id, position, order
module->id_module, name, description, image
I have query where I take all modules for set ID (store_module table), and I need to get all modules which appear in this query (module_id). What I need to do?
This is the code (I am awake for 30+ hours and my brain is refusing to communicate with me, deadline is almost here, and this on of the last things I need to do. So, please help :D):
function mar_get_modules($id){
$q = $this->db->get_where('store_module', array('caffe_id' => $id));
$modules = $q->result_array();
}
Start simple, by using a regular query (if I guess right, you need a JOIN there).
This query should work:
$sql = "SELECT m.*,sm.* FROM module m
LEFT JOIN store_module sm ON sm.id_module = m.module_id
WHERE sm.caffe_id = ?";
return $this->db->query($sql, array($id))->result_array();
Now, you can transform it into an AR query:
$query = $this->db->select('module.*,store_module.*')
->from('module')
->join('store_module', 'store_module.id_module = module.module_id','left')
->where('store_module.caffe_id',$id)
->get();
return $query->result_array();
While AR is quicker sometimes, I usually prefer writing my queries "by hand", taking advantage of the binding to prevent SQL injections; it's a lot easier to see how things are working if you have a query fully laid under your eyes
Sasha,
In the function above, you are not returning anything. You'll need to update the 3rd line something to the effect of return $q->result_array();

PHP/Mysql - Dynamically selecting data?

I'm a bit new to OOP, but i've been playing with it for about a month now. Usually, i create a class called Mysql which has a __construct function that connects to a database directly. And after that i have lots of different functions that gets or inserts data into different tables.
On the bus home today, i began thinking and i came up with a brilliant idea that would make it less cluttered. My idea is to use one single function that selects data (and one for inserting), and depending on how the query that's passed in looks, it will select different data from different tables. Nice, right?
But i'm kind of stuck here. I'm not sure at all how to achieve this. I've got a small clue how it could work, but i don't know how i would bind the results, or fetch them into an array. The query will be created in another method, and then be passed into the select/insert function within the Mysql class.
I drew a "sketch" on how i think it may work. Here it is:
Of course, the function below will be placed in the Mysql class, and will already have connection to a database.
// This is an example query that could be passed in.
$query = "SELECT * FROM table WHERE id=150";
function select_data($query) {
if ( $smtp = $this->conn->prepare($query) ) {
$smtp->execute();
$smtp->bind_results(What happens here?);
if ( $smtp->fetch() ) {
foreach ( fetched_row? as $key => $value ) {
$return[] = $key => $value;
}
return $return;
}
else return NULL;
}
else return $this->conn->error;
}
Thanks a lot to anyone who can show me how this can be achieved.
You have more options to use in PHP and they has their own specifics.
I can recommend some ORM
like Doctrine because of ease of use, stability, community and most importantly efectivity.
You can use it as easy as:
$q = Doctrine_Query::create()
->select('u.username, p.phone')
->from('User u')
->leftJoin('u.Phonenumbers p');
$users = $q->fetchArray();
or:
// Delete phonenumbers for user id = 5
$deleted = Doctrine_Query::create()
->delete()
->from('Phonenumber')
->andWhere('user_id = 5')
->execute();
// Make all usernames lowercase
Doctrine_Query::create()
->update('User u')
->set('u.username', 'LOWER(u.username)')
->execute();
// 'like' condition
$q = Doctrine_Query::create()
->from('User u')
->where('u.username LIKE ?', '%jwage%');
$users = $q->fetchArray();
I think you are running into problems when you need related data. In other words, when an object of yours has a property which is another object that data should also be gathered and dynamically filled. I once came pretty far but when stuff like INNER, LEFT and RIGHT joins come accross you'll think twice about going further ;)
About bind_results:http://php.net/manual/en/mysqli-stmt.bind-result.php
(Maybe slightly off topic; SMTP? That's a mailprotocol, are you sure you don't mean MySQLi's STMT?)
For reference, PDO already does a lot of what you seem to want to do. It even has a fetchAll method that returns an array of rows, much like your function does. You don't need to bind anything in order to use it, unless you have parameters in your query string (and of course, values to bind to those parameters).
Check out the PDO documentation, and see if that doesn't fit your needs. Particularly PDOStatement->fetchAll().

Categories