Zend Framework Multiple Table Query - php

I am looking to execute this statement via Zend Framework. As I understand it, I can use Zend_Db_Select. Is it possible to use Zend_Db_Table?
Three tables: classes, students, and class_students
select classes.name, students.student_id, students.fname, students.lname from students, classes, class_students where class_students.student_id=students.student_id AND class_students.class_id=classes.class_id;

yes, is possible - Zend_Db_Table provides you with an interface to execute a variety of operations on a table. For example, considering the multiple table selection that you want to perform, and assuming you have your db adapter properly configured, we can end up with something like the following:
$table = new Model_DbTable_Classes(); // which extends Zend_Db_Table_Abstract
$select = $table->select()->setIntegrityCheck(false);
$select->join('class_students', 'class_students.class_id = classes.class_id')
->join('students', 'student.student_id = class_students.student_id')
->where('classes.class_id = ?', 1)
->where('student.student_id = ?', 10);
$result = $table->fetchAll($select);
print_r($result->toArray());
For this particular case I wouldn't use the Zend_Db_Table though, I tend to use Zend_Db_Table when I need just to take actions upon one single table. As for multiple table selections I'd rather go with db select, or structuring my query old-school-fashioned (SQL string), and fetch it using my db object.
Hope it helps :)
M.

Related

Unite/join Database and Eloquent's model query in Laravel 5.2

I have to check if an user is online (in-game), and if he's not then do another checks to perform a sql update.
Actually, I have these two queries.
$isOnline = DB::connection('mssql')->table('USER_STAT')->where('user_id', $userID)->value('ConnectionStat');
$character = Character::where('acc_id', $userID)->where('Name', $characterName)->firstOrFail();
Is there a way I can use union or join in order to save a DB query? I believe this is not a good practice, and some better method is out there, which I can't find in the docs.
I tried something like this, but without success:
$character = Character::where('acc_id', $userID)->where('Name', $characterName)->firstOrFail();
$result = DB::connection('mssql')->table('USER_STAT')->where('user_id', $userID)->union($character)->get();
Thanks in advance!
Using a relation in your Character Model to the Model of the USER_STAT table you can easily lookup the things you need to determine if an update somewhere is needed.
Eloquent Relationships
This does not consolidate the queries into one, like with a join, but they are not heavy anyway, and using the ORM to the fullest will have more significant advantages in the long run.
If you think you must use an SQL-join you must stick to the querybuilder, but the ORM is usually the better choice
Query Builder Joins

If I'm already using PDO then what is the advantage to further abstracting SELECT queries into Laravel's Eloquent ORM?

Consider the following READ and WRITE queries:
Read
// Retrieves a person (and their active game score if they have one)
$sql = "SELECT CONCAT(people.first_name,' ',people.last_name) as 'name',
people.uniform as 'people.uniform',
games.score as 'games.score'
FROM my_people as people
LEFT JOIN my_games as games ON(games.person_id = people.id AND games.active = 1)
WHERE people.id = :id";
$results = DB::select(DB::raw($sql),array("id"=>$id));
Write
// Saves a person
$person = new People;
$person->data = array('first_name'=>$input['first_name'],
'last_name'=>$input['last_name'],
'uniform'=>$input['uniform']);
$personID = $person->save();
// Save the game score
$game = new Games;
$game->data = array('person_id'=>$personID,
'active'=>$input['active'],
'score'=>$input['score']);
$game->save();
I put every write (INSERT/UPDATE) operation into my own centralized repository classes and call them using class->methods as shown above.
I may decide to put some of the read queries into repository classes if I find myself using a query over and over (DRY). I have to be careful of this, because I tend to go back and adjust the read query slightly to get more or less data out in specific areas of my application.
Many of my read queries are dynamic queries (coming from datagrids that are filterable and sortable).
The read queries will commonly have complex things like SUMs, COUNTs, ORDERing, GROUPing, COMPOSITE keys, etc.
Since my reads are so diverse, why would I need to further abstract them into Laravel's Eloquent ORM (or any ORM), especially since I'm using PDO (which has 12 different database drivers)? The only advantage I can see at the moment is if I wanted to rename a database field then that would be easier to do using the ORM. I'm not willing to pay the price in greater abstraction/obscurity for that though.

How to access db views using Laravel models?

I am porting a Postgres-backed web app to Laravel 4.2, and I can't see a way to utilize the existing eight or so summation views which are built in the psql db. These views preform various aggregation and averaging functions, and as such are properly part of the schema as they illustrate the relationships between the table entities.
Surely someone has had to use db views with the active record style interface of Laravel? How do you go about it?
Your question is about database views and if I'm not wrong then you are talking about the dynamic table that gets created on the fly, for example, in MySql, it's possible to create a View using something like this:
CREATE VIEW students AS SELECT * FROM profiles where type='student' ORDER BY id;
So, it'll allow to query the dynamic table which is the students view here, for example:
select * from students;
This will return the filtered data from students view. So, if I'm right about your question then I think you are able to use Eloquent just like you use for real tables, for example, to create an Eloquent model for students view you can simply create it using something like this:
class ViewStudent extends Eloquent {
protected $table = 'students';
}
So, now you can use this model as usully you may use for other tables, for example;
$students = ViewStudent::all();
It's just the same way. Since you asked for psql so I'm not sure about the syntax of that or how it works in that system but I believe it's possible same way.

PHP / Zend Framework: Which object would handle a complex table join?

I think one of the more difficult concepts to understand in the Zend Framework is how the Table Data Gateway pattern is supposed to handle multi-table joins. Most of the suggestions I've seen claim that you simply handle the joins using a $db->select()...
Zend DB Select with multiple table joins
Joining Tables With Zend Framework PHP
Joining tables wthin a model in Zend Php
Zend Framework Db Select Join table help
Zend DB Select with multiple table joins
My question is: Which object is best suited to handle this kind of multi-table select statement? I feel like putting it in the model would break the 1-1 Table Data Gateway pattern between the class and the db table. Yet putting it in the controller seems wrong because why would a controller handle a SQL statement? Anyway, I feel like ZF makes handling datasets from multiple tables more difficult than it needs to be. Any help you can provide is great...
Thanks!
By definition, TableData Gateway handles one table only.
ZF enforces this definition with an integrity check on Zend_Db_Table_Selects. However, the integrity check can be disabled and then you can do joins. Just create a method inside your table class to do the Join via the select object like this:
public function findByIdAndJoinFoo($id)
{
$select = $this->select();
$select->setIntegrityCheck(false) // allows joins
->from($this)
->join('foo', 'foo.id = bar.foo_id');
return $this->fetchAll($select);
}
If you want to stick to the definition, you you can use some sort of Service Layer or DataMapper that knows how to handle multiple tables. These sit between the Db classes and the Controllers.
Another alternative is not to use Joins but table relationships and then lazy load dependent rowsets as needed. Of course, that's not Joins then, but multiple queries.
And finally, you can still just use Zend_Db_Statement and craft your SQL by hand:
$stmt = $db->query(
'SELECT * FROM bugs WHERE reported_by = ? AND bug_status = ?',
array('goofy', 'FIXED'));

MVC data design problem with Zend framework

If I have a class representing access to one table in my database in a class:table relationship, so I can hide table details in one class. But as any useful application I have to query several tables. How can I accomodate this using the class:table design?
There's a couple of different ways you can achieve this, however, which one you choose really depends on your circumstances.
1) Break the connection between your objects and your database
Write your objects to have no connection with your database tables. First normalise your database tables, then, look at how the user of your application will interact with your data. Model the data to objects, but don't tie each object to the table (ie with a Zend_DB_Table_Abstract class)
Once you have established your objects, then write mapper classes which map your objects back to the relevant tables in your database. These are the classes which extend Zend_DB_Table (if appropriate).
You can handle joins in two ways, either map the joins through the Zend_DB_Table relationship functionallity, or, (IMHO a better choice) just use Zend_DB_Select to make the relevant methods within your your mapper class.
So you've then got two classes (probably per table, but not always)
Person
PersonMapper
In your code, when you want to work with some objects, either create a new object
$person = new Person();
$person->setName('andrew taylor');
Then write pass it to the mapper to save it:
$personMapper = new PersonMapper();
$pesonnMapper->save($person);
Or, do it the other way:
$personMapper = new PersonMapper();
$person = personMapper->load(29);
$person->setName('joe bloggs');
$personMapper->save($person);
The next step on from here would be a collection class based on the SPL:
$personList = $personMapper->loadAllMen();
foreach($personList AS $person) {
echo $person->getName();
}
Where $personMapper->loadAllMen() is a method like:
$select = $this->select();
$select=>where('gender = "Male"');
$zendDbRows = this->fetchAll($select);
return new PersonList($zendDbRows);
2) MySQL Views
If you have a lot of joined tables where there is one row per join, so, you're joining customer information based on an id in your orders table, and you're doing it read-only (so you don't want to update any information through the Zend_DB_Table adaptor) you create your normalised tables, then, a single view across the top. The view handles the joins behind the scenes so through Zend it feels like you're connecting to a single table.
There are some caveats with this, MySQL views do have some performance problems (which is why it's best on single row FK joins), and, they're strictly read only.

Categories