Zend DB: Proxying between Table and Row classes? - php

Is there any proxying in place between Zend DB Table and Zend DB Row? For example, if I override the DB_Table delete() method to merely flag deleted records, will I need to do the same thing in DB_Table_Row? Or does row proxy to table?
If proxying is in place, in which direction does it occur? (Row proxies to table?) And for which methods? (Row delete() and save() -to- table delete(), update() and insert()?)
I realise I could test this myself but chance are you will be a lot faster (if you don't already know the answer...)
Thanks!
EDIT
The reason for the question is that I am developing some models which will include ACL. Since I have ACL in controllers too, I am planning only to override selected methods in the DB classes. For example, I want to ensure that a Member can delete their own record only. (I think I need to use ACL asserts to do this).
So I was asking the question above in order to determine whether I had to override pairs of methods (i.e. one in the Table class, one in the Row class), or whether I could just override one. Judging by the responses, however, I'm now wondering whether I'm asking the wrong question.
How do experienced developers deal with this kind of situation? Perhaps you choose to work with just one delete method (e.g. from the Row class). (Ditto for the update method too). If so, do you override the Table class delete to prevent inadvertant usage?
I am curious... Thanks...

From what I understand, the delete method in Zend_DB_Row employs delete method from Zend_DB_Table. Thus, if you overwrite delete from Zend_DB_Table it should be seen by delete in Zend_DB_Row.
Hope this helps. Anyway, if this would be not the case, please let me know.

Line 627 of Zend_Db_Table_Row_Abstract
/**
* Execute the DELETE (this may throw an exception)
*/
$result = $this->_getTable()->delete($where);
gets the table and executes the delete method.
Line 1182 of Zend_Db_Table_Abstract
return $this->_db->delete($tableSpec, $where);
This will call the Zend_Db_Adapter_Abstract::delete().
IMO, it may be best to over write the delete method in your adapter class. This is will ensure that no matter where the delete request comes from, your custom delete logic will be executed.

Related

need to switch between class scopes

I have a class (PersistenceClass), that takes an array of data (posts) and parses that data and puts it into a DB (via doctrine). The field content needs to be parsed by a second class (SyntaxClass) before it is set into the doctrine entity.
Now the problem is, that the SyntaxClass has to set references in the content to other posts (just a link with and ID). So it needs access to the DB, and also needs to search in the persisted but not yet flushed entities from the PersistenceClass.
I can inject a doctrine EM into SyntaxClass and find my references in DB, although I dont like it very much. But the bigger problem is, how I can access the only persisted, but not flushed entities from the PersistenceClass ? I could make an Array of that objects and put it as an parameter to the parser method like:
SyntaxClass->parseSyntax($content, $persistedObjects);
But that does not look very clean. Aside from that, I dont know if it is somehow possible to search in the data of the persisted objects?
Your question is full of sub-question, so, first I'll try to make some things clear.
First, the naming convention you used is a bit abiguos and this not helps, me and also other people that may work on your code in future (maybe you'll grow and need to hire more developers! :P ). So, let's start with some nomenclature.
What you are calling PersistenceClass may be something like this:
class PersistenceClass
{
public function parse(array $posts)
{
foreach ($posts as $post) {
// 1. Parse $post
// 2. Parse content with SyntaxClass
// 3. Persist $post in the database
}
}
}
The same applies also for SyntaxClass: it receives the $content and parses it in some ways, then sets the references and then persists.
This is just to set some boundaries.
Now, go to your questions.
I can inject a doctrine EM into SyntaxClass and find my references in
DB, although I dont like it very much.
This is exactly what you have to do! The OOP development works this way.
But, and here come the problems with naming conventions, the way you inject the entity manager depends on the structure of your classes.
A good design should use services.
So, what currently are PersistenceClass and SyntaxClass in reality should be called PersistenceService and SyntaxService (also if I prefere call them PersistenceManager and SyntaxManager, because in my code I always distinguish between managers and handlers - but this is a convention of mine, so I'll not write more about it here).
Now, another wrong thing that I'm imaging you are doing (only reading your question, I'M IMAGING!): you are instantiating SyntaxService (you currently named SyntaxClass) from inside PersistenceService (your currently named PersistenceClass). This is wrong.
If you need a fresh instance of SyntaxService for each post, then you should use a factory class (say SyntaxFactory), so calling SyntaxFactory::create() you'll get a fresh instance of SyntaxService. Is the factory itself that injects the entity manager in the newly created SyntaxClass.
If you don't need a fresh instance each, time, instead, you'll declare SyntaxClass simply as a service and will pass it to PersistenceService by injection. Below this last simpler example:
# app/config/service.yml
services:
app.service.persistence:
class: ...\PersistenceService
# Pass the SyntaxInstance directly or a factory if you need one
aguments: ["#doctrine.orm.default_entity_manager", "#app.service.syntax"]
app.service.syntax:
class: ...\SyntaxService
aguments: ["#doctrine.orm.default_entity_manager"]
But the bigger problem is, how I can access the only persisted, but
not flushed entities from the PersistenceClass ?
Now the second question: how to search for {persisted + flushed} and {persisted + not flushed} entities?
The problem is that you cannot use the ID as the search parameter as the persisted but not flushed entities doesn't have one before the flushing.
The solution may be to create another service: SearchReferencesService. In it you'll inject the entity manager too (as shown before).
So this class has a method search() that does the search.
To search for the entities persisted but not flushed, the UnitOfWork gives you some interesting methods: getScheduledEntityInsertions(), getScheduledEntityUpdates(), getScheduledEntityDeletions(), getScheduledCollectionDeletions() and getScheduledCollectionUpdates().
The array of which you are speaking about is already there: you need to only cycle it and compare object by object, basing the search on fields other than the ID one (as it doesn't exist yet).
Unfortunately, as you didn't provided more details about the nature of your search, it is not possible for me to be more precise about how to do this search, but only tell you you have to search using the unit of work and connecting to the database if null results are returned by the first search. Also the order in which you'll do this search (before in the database and then in the unit of work or viceversa) is up to you.
Hope this will help.

Handling relational tables as entities with Doctrine

I need some help dealing with a relational table that is an entity due to the existence of an additional property.
Here is a gist of the entities in question: https://gist.github.com/chasepeeler/efd7efd890c58eafb81f
Do I have something configured wrong that is forcing me to do the flush in controller.php line 15?
I've also tried just updating the rank attribute of the queueItem record in the Queue::queueItems collection, but when I do that, it doesn't even save the changes to the database.
$queueItems->clear() does the same thing as clearQueueItems, but one time.
And if you want to override current queue state, you should just implement and call setQueueItems(ArrayCollection $queueItemList) method.
UnitOfWork will compute your changes to insert and remove new/deleted items.
Every OneToMany annotated field should implement setItems, addItem and removeItem methods, where Item is related entity name.
Your sortQueue method shouldn't persist and commit changes into database.
It should only return a sorted Collection.
Maybe I didn't get that, it's hard to say what you want to achieve, controller's code says me nothing.

Is doing Transaction Management in the Controller bad practice?

I'm working on a PHP/MySQL app using the Yii framework.
I've come across the following situation:
In my VideoController, I have a actionCreate which creates a new Video and actionPrivacy which sets the privacy on the Video. The problem is that during the actionCreate the setPrivacy method of the Video model is called which currently has a transaction. I would like the creation of the Video to be in a transaction as well which leads to an error since a transaction is already active.
In the comment on this answer, Bill Karwin writes
So there's no need to make Domain Model classes or DAO classes manage
transactions -- just do it at the Controller level
and in this answer:
Since you're using PHP, the scope of your transactions is at most a
single request. So you should just use container-managed transactions,
not service-layer transa. That is, start the transaction at the start
of handling the request, and commit (or rollback) as you finish
handling the request.
If I manage the transactions in the controller, I would have a bunch of code that looks like:
public function actionCreate() {
$trans = Yii::app()->getDb()->beginTransaction();
...action code...
$trans->commit();
}
That leads to duplicated code in a lot of places where I need transactions for the action.
Or I could refactor it into the beforeAction() and afterAction() methods of the parent Controller class which would then automatically create transactions for each action being performed.
Would there be any problems with this method? What is a good practice for transaction management for a PHP app?
The reason that I say transactions don't belong in the model layer is basically this:
Models can call methods in other models.
If a model tries to start a transaction, but it has no knowledge of whether its caller started a transaction already, then the model has to conditionally start a transaction, as shown in the code example in #Bubba's answer. The methods of the model have to accept a flag so that the caller can tell it whether it is permitted to start its own transaction or not. Or else the model has to have the ability to query its caller's "in a transaction" state.
public function setPrivacy($privacy, $caller){
if (! $caller->isInTransaction() ) $this->beginTransaction();
$this->privacy = $privacy;
// ...action code..
if (! $caller->isInTransaction() ) $this->commit();
}
What if the caller isn't an object? In PHP, it could be a static method or simply non-object-oriented code. This gets very messy, and leads to a lot of repeated code in models.
It's also an example of Control Coupling, which is considered bad because the caller has to know something about the internal workings of the called object. For example, some of the methods of your Model may have a $transactional parameter, but other methods may not have that parameter. How is the caller supposed to know when the parameter matters?
// I need to override method's attempt to commit
$video->setPrivacy($privacy, false);
// But I have no idea if this method might attempt to commit
$video->setFormat($format);
The other solution I have seen suggested (or even implemented in some frameworks like Propel) is to make beginTransaction() and commit() no-ops when the DBAL knows it's already in a transaction. But this can lead to anomalies if your model tries to commit and finds that its doesn't really commit. Or tries to rollback and has that request ignored. I've written about these anomalies before.
The compromise I have suggested is that Models don't know about transactions. The model doesn't know if its request to setPrivacy() is something it should commit immediately or is it part of a larger picture, a more complex series of changes that involve multiple Models and should only be committed if all these changes succeed. That's the point of transactions.
So if Models don't know whether they can or should begin and commit their own transaction, then who does? GRASP includes a Controller pattern which is a non-UI class for a use case, and it is assigned the responsibility to create and control all the pieces to accomplish that use case. Controllers know about transactions because that's the place all the information is accessible about whether the complete use case is complex, and requires multiple changes to be done in Models, within one transaction (or perhaps within several transactions).
The example I have written about before, that is to start a transaction in the beforeAction() method of an MVC Controller and commit it in the afterAction() method, is a simplification. The Controller should be free to start and commit as many transactions as it logically requires to complete the current action. Or sometimes the Controller could refrain from explicit transaction control, and allow the Models to autocommit each change.
But the point is that the information about what tranasction(s) are necessary is something that the Models don't know -- they have to be told (in the form of a $transactional parameter) or else query it from their caller, which would have to delegate the question all the way up to the Controller's action anyway.
You may also create a Service Layer of classes that each know how to execute such complex use cases, and whether to enclose all the changes in a single transaction. That way you avoid a lot of repeated code. But it's not common for PHP apps to include a distinct Service Layer; the Controller's action is usually coincident with a Service Layer.
Best Practice: Put the the transactions in the model, do not put the transactions in the controller.
The primary advantage of the MVC design pattern is this: MVC makes model classes reusable without modification. Make maintenance and implementing new features easy.
For example, presumably you are primarily developing for a browser where a user enters one collection of data at a time, and you move data manipulation into the controller. Later you realize you need to support allowing the user to upload a large number of collections of data to be imported on the server from the command line.
If all the data manipulation was in the model, you could simply slurp in the data and pass it to the model to handle. If there is needful (transactional) functionality in the controller, you would have to replicate that in your CLI script.
On the other hand, perhaps you end up with another controller that needs to perform the same functionality, from a different point. You will need to replicate code in that other controller as well now.
To that end, you merely need to solve the transaction challenges in the model.
Assuming you have a Video class (model) with the setPrivacy() method that already has transaction build in; and you want to call it from another method persist() which needs to also wrap its functionality in a larger transaction, you could merely modify setPrivacy() to perform a conditional transaction.
Perhaps something like this.
class Video{
private $privacy;
private $transaction;
public function __construct($privacy){
$this->privacy = $privacy;
}
public function persist(){
$this->beginTransaction();
// ...action code...
$this->setPrivacy($this->privacy, false);
// ...action code...
$this->commit();
}
public function setPrivacy($privacy, $transactional = true){
if ($transactional) $this->beginTransaction();
$this->privacy = $privacy;
// ...action code..
if ($transactional) $this->commit();
}
private function beginTransaction(){
$this->transaction = Yii::app()->getDb()->beginTransaction();
}
private function commit(){
$this->transaction->commit();
}
}
In the end, your instincts are correct (re: That leads to duplicated code in a lot of places where I need transactions for the action.). Architect your models to support the myriad of transactional needs you have, and let the controller merely determine which entry point (method) it will use in it's own context.
No you are right. The transaction is delegated by the "create" method which is what a controller is supposed to do. Your suggestion of using a 'wrapper' like beforeAction() is the way to go. Just make the controller extend or implement this class. It looks like you are looking for an Observer type pattern or a factory-like implementation.
Well, one disadvantage of these broad transactions (over the whole request) is that you limit concurrency capabilities of your database engine and you also increase deadlocks probability. From this point of view, it might pay off to put transactions only where you need them and let them cover only code that needs to be covered.
If possible, I would definitely go for placing transaction in models. The problem with overlapping transactions can be solved by introducing BaseModel (ancestors of all models) and variable transactionLock in that model. Then you simply wrap your begin/commit transaction directives into BaseModel methods that respect this variable.

Best OOP approach for this simple PHP app?

Ok, I couldn't insert the overview image, but I'm required to create a PHP app for my studies, it must allow student to register, and the administrator to edit course and student info.
We are not required to code it in an OOP style, but since its the best programming practice to code in OOP, why not learn OOP from the beginning.
I'm a beginner but I know the basics about OOP, classes, inheritance, setters and getters and all that cool lingo, but I'm struggling to decide which parts of this app should be objects, should I make course and student classes or add, edit and delete classes? Any advice on how to approach and visualize such a problem would be appreciated.
Very roughly: This is how I would do it:
Store your data in SQL or XML. You will need two SQL tables, one for Students and one for Courses. You can use one XML file containing all the data, or you can use two files (which I recommend).
Create a class called, for example, dataItem with a property like '$arr_fields' corresponding to a single data record (a single row in a SQL table, or an XML record).
The dataItem class should have the following methods (all public):
loadFromSQL() (or loadFromXML())
saveToSQL() (or saveToXML())
add(), edit() and delete()
a view() method using HTML
These methods are obviously used to read and write data between the SQL/XML data and $arr_fields of the class, and to display the data in $arr_fields. The keys of $arr_fields are the SQL column names (or XML tag or attribute names) for the specific SQL table.
Try not to call loadFromSQL() or saveToSQL() in your constructor or in any of the other methods which are used to modify only the class data. Keep these actions separate. EDIT: This is a personal preference which helps me to keep track of the state of my objects.
Create Student and Course classes that extends the dataItem class.
You can override methods, for instance the view() method, inside your extended classes if you need to.
Then you can call the methods in Students and Courses from an Admin object (like rcdmk suggested) or maybe from StudentFolder and CourseFolder classes whose view() method contains buttons for the actions that need to be performed. (Let StudentFolder and CourseFolder extend a Folder class that you create).
UPDATE:
For example: If your primary key in a SQL table is id, then dataItem's loadFromSQL($id, $tablename) should set $arr_fields so that its keys are the column names and it's values are the values from the row whose primary value is equal to $id.
In Students, you can then override loadFromSQL() as follows:
class Students extends dataItem {
// other attributes
public function loadFromSQL($id) {
parent::loadFromSQL($id, "Students");
}
}
EDIT: On reconsideration, it might be better to set $arr_fields["id"] = $id and also set $tablename with the constructor for dataItem - then you never have to override loadFromSQL() or specify parameters for it. loadFromSQL() should then load the record if it exists. saveToSQL() should save $arr_fields in SQL if $arr_fields["id"] is set and create a new record if it is not set. Anyway, you must find a consistent way of interacting with the data which works for you, these are just possibilities.
However, if you are not experienced with OOP and SQL or XML, you might be opening a can of worms for yourself and it might be better to just do your assignment using functions only and php arrays for your data. Unless you have some time to learn...
From a simple perspective:
Abstract the main objects as classes and use methods for actions of this objects:
Student (object) are deleted (action) by the Admin (object), so
Admin class will have a deleteStudent method, because Admin deletes Students.
Another aprouch is to concentrate all Student related actions in the Student class:
Student class will have a public delete method that Admin can use.
Anyone that think this in better ways of explanation can edit this wiki.
Think about which aspects of your system are actually objects, you know, something you can do something with. The methods are what you do to the objects. So, you're on the right track with course and student classes, and add, edit, and delete would be methods of those classes.
But don't get too bogged down with it. If it's not your core assignment objective, you could quickly get in over your head by trying to do everything exactly the right way. If you can formulate a clear way to get to where you need to go, then go for it, if it seems confusing, back off it a little and learn some more.
You say that you know the basis of OOP, however you ask whether you should create Course, Student classes OR Add, Delete, Edit classes. Well maybe there are other practices, but I guess the most popular one and the only I am aware of is to use nouns as classes and verbs as their methods. Hence, intuitively there is something wrong with class "Add" or "Edit". What I would have done if I were were, is to think of all "entities" that might be considered an object - like Student, Course, Lecturer, Class (Room) and depending on how advanced your model should be you can add more like Building etc. Then try to implement basic things like creating new student, registering for a course, associating teacher with a course etc. Once you have it in place and IT IS WORKING you might want to add advanced things, like inheritance. For example you might want to say, that both Teacher and Student are a Person so you might want to create such abstract class and use inheritance.

How much should doctrine record do?

I'm creating my own CMS and use doctrine for database.
Now I wonder, when I crate Post record, how much work should that record do?
An example:
I have Post -> Categories relation (one to many), should I create separate functions to append categories (to look if Post already has category, etc. ) or should Post do that using accessors / mutators?
What's the best practice?
I think adding methods for the purprose you described is a good idea. Doctrine can sometimes be a bit tricky if you try to override the default actions that happen when accessing the properties.
In general, if there's anything that needs more than the default action, I would recommend having it as a method in the model class.
If you have a specific table with some table-specific actions, such as get every object by some rule, then it's a good idea to add a new method to the table-specific SomeTable class.
Since this is kind of like ActiveRecord, you would have the domain logic in the Doctrine record object.

Categories