Question:
Is there a preferred design pattern for handling an object under different contexts? For example: if I need to GET a user from the database then that object needs to have an id and a privilege level. However, if I want to create a NEW user for registration then it does not need an id since this will be added in the database via auto_increment. A GUEST user does not need an id but should have a username of 'Guest'.
Attempted Solutions
Using a constructor seems to neglect context.
Creating new objects for registered_user, new_user, and guest_user seems wasteful.
Creating methods within the user object that can be used to initialize it in unique ways is tempting.
As of now I believe that I should create a separate factory that has functions such as create_guest($x), create_new_user($x, $y), create_registered_user($x, $y, $z)? This would allow the user object to have one purpose: hold a user (while still allowing it to have a constructor to establish a bare minimum requirement), and also have a user factory with the sole purpose of: initiating different types of users.
Please excuse any ignorance, just looking for the best design pattern for handling the same object in unique contexts.
Example:
<?php
class user
{
private id;
private username;
private privilege;
public function __construct()
{
some code...
}
public function is_admin()
{
some code...
}
}
?>
Using the provided class, you can always autoinitialize the value for $this->id to be 0 and use it to determine if this user is a guest. Main idea is that you will never have an id of 0 in your database (if you are using auto-increment for this column).
This can also be used to check if you are to update or create the record. A simple check on the id would reveal either 0 or another int. If it is 0, then it is either guest or it should be created. If it is greater than 0, it has already been created and it needs to be updated.
Generally, I prefer to pack the create and update into the user class itself by adding load(), update(), create() and delete() methods, where load() would accept an array/object which if passed will be used to load the data into the current context or if not supplied, the function will try to read the data from a different source (such as a DB).
Related
I have a question regarding how to populate objects from the Data base, it's more about the architecture than populating it self.
Let's say I have a table called receipts which has: receipt_id, user_id, issue_date, business_id, product_id abd type.
Now I want to create a Receipt class which will be populated from that table, I would do something like this:
class Receipt {
public function __construct($receipt_id = null) {
if(!is_null($receipt_id))
$this->populate($receipt_id);
}
public function populate($receipt_id){
//Get data from data base
}
public function save(){
//Saves the current receipt into the data base.
}
public static function getReceiptsFromUser($user_id){
}
}
My question is about getReceiptsFromUser, should it be static?. It makes sense for the User class to have a method called getReceipts which would return an array of receipts objects calling this static method. I think it should be static because it doesn't make any sense to create an empty receipt to generate the user's receipts. Is there any flaws in this architecture or better aproaches?
Yes, it should be static. As you already mentioned yourself, you don't need a Receipt object in order to retrieve other Receipts.
From the PHP documentation:
Declaring class properties or methods as static makes them accessible without needing an instantiation of the class.
By the way, what you're doing here is called the Active Record pattern. If you're going to use this approach, it's a good idea to create a base class (you can call it Record or something similar) that defines the shared methods (such as save, find, etc.) and let your models extend them (class Receipt extends Record, class User extends Record, etc.). This way, you don't need to repeat this code in all of your models.
A nice (PHP) example for this approach is given by the PHP ActiveRecord project. A look into their documentation should give you some ideas about how it works.
Another approach is the Data Mapper pattern. The benefit is that your models don't know anything about how they're being saved, so you have great flexibility in how you want to persist your data, instead of being tied to the limitations of ActiveRecord.
I am using Cassandra with heavy denormalization so I cannot use some kind of universal class to delete/add/update/etc.. objects since every type of object has its own list of tables that needs to be changed.
For example to delete User I will need to touch 3 tables, not just one. To delete Item I will need to touch 7 tables, etc.. It means that logic is completely different based on object type.
Scenario 1
User class contains only fields that I need (id, name, etc..) and static functions to find users, delete users etc..
<?php
class User {
private $id;
private $name;
// Magic getters and setters removed to save space here
public static function delete($id) {
// find user by id
// delete that user
}
}
Scenario 2
User class has everything - fields (id, name, etc..) and also functions that will delete/edit/create/etc.. that particular user
<?php
class User {
private $id;
private $name;
// Magic getters and setters removed to save space here
public function delete() {
// find user by $this->id
// delete that user
}
}
Which scenario is better and maybe there is some other way to do this that is even better?
I vote #2.
The main thing is to choose one, be clear why and stick to it. Things are going to get very confusing if you mix these approaches or you are not clear about why you have chosen a particular approach.
I Scenario 2 because its clear what you are deleting, its always related to $this.
Also in Scenario 2 your delete method needs less validation as this validation can be offloaded to the constructor, or simple check if $id is set before deleting the object or database row.
In Scenario 1 though you would need to take $id and check that is exists before attempting to remove it in order to be sure you are actually removing something. You could also return the number of rows deleted too, which could be validation in itself too. But in the future this validation may be more complex than just checking what is being deleted.
Better to let the construction or a load() function deal with as much of the validation.
Let's say I have a Widget table and the Yii Model class that goes with it.
I want to be able to instantiate it ($tempWidget = new Widget) but somehow make sure it cannot be saved to the database. I want to use the model just for the user to test things, simulate...
Obviously, I could just avoid to call $tempWidget->save() but I'd like some kind of flag that would prevent save from saving, in case some other part of the code tries to do so.
There are a few ways to accomplish what you want. The easiest way is to modify the models beforeSave() method to prevent the model from being able to save by unsetting all the attributes using the CModel unsetAttributes method , example:
public function beforeSave(){
$this->attributes = $this->unsetAttributes();
}
This will work only if you have rules associated with this model that have required fields (at least one required field), otherwise this would create an entry in your table consisting only of the primary key (assuming PK is auto increment).
I'm working on a PHP web app and I'm trying to use the MVC model. I have a lot of things that exist as 'database entities' -- a row, or a set of related rows, that are conceptually one human recognizable 'thing'. So I often try to provide an interface to that thing in a model class.
So of course, the run of the mill functionality is to have an existing entity, get some data from it, and sometimes update it. However, where I run into problems is when I need to create a new entity. None of the default data for an existing entity exists yet!
For instance, my __construct() methods will often have arguments (i.e. $id for WHERE id = $id) so that I can select data from the database and populate all the properties of the object from that data. However, when I want to create a new entity, the values for those arguments don't exist yet!
How do you all handle this situation? Do you
try to provide functionality for both creation and subsequent manipulation in the same object
have another class just for generating the entity
avoid __construct and have somthing like create() for new entities and instantiate() for existing ones
something else?
If you need the ability to create "new" objects, then I don't think your constructors should be loading from the database by default. Since PHP doesn't support function overloading (so you can't have overloaded constructors), you can either just remove the "populate from database" code from the constructor into a function for that purpose, or give the $id-type argument a default value that indicates that properties shouldn't be populated from the database:
function __construct($id = 0)
{
if ($id == 0)
// create with blank properties
else
// load from database
}
Then if you want a new object, you just call it with no arguments, and if you want to load from the database, you include the id argument.
Bit of an abstract problem here. I'm experimenting with the Domain Model pattern, and barring my other tussles with dependencies - I need some advice on generating Identity for use in an Identity Map.
In most examples for the Data Mapper pattern I've seen (including the one outlined in this book: http://apress.com/book/view/9781590599099) - the user appears to manually set the identity for a given Domain Object using a setter:
$UserMapper = new UserMapper;
//returns a fully formed user object from record sets
$User = $UserMapper->find(1);
//returns an empty object with appropriate properties for completion
$UserBlank = $UserMapper->get();
$UserBlank->setId();
$UserBlank->setOtherProperties();
Now, I don't know if I'm reading the examples wrong - but in the first $User object, the $id property is retrieved from the data store (I'm assuming $id represents a row id). In the latter case, however, how can you set the $id for an object if it has not yet acquired one from the data store?
The problem is generating a valid "identity" for the object so that it can be maintained via an Identity Map - so generating an arbitrary integer doesn't solve it.
My current thinking is to nominate different fields for identity (i.e. email) and demanding their presence in generating blank Domain Objects. Alternatively, demanding all objects be fully formed, and using all properties as their identity...hardly efficient.
(Or alternatively, dump the Domain Model concept and return to DBAL/DAO/Transaction Scripts...which is seeming increasingly elegant compared to the ORM implementations I've seen...)
You would use the setId function if you are controlling the IDs, if you want to override the data store ID, or if you want to update/delete the data without having to retrieve it first (i.e. already have the ID from a POST).
Another alternative would be calling setId() to reserve an ID by "querying" (insert a record) the data store for the next available ID.
It's not really relevant what the ID is set to until you actually need to use it to reference something. Calling setId with no parameter would do nothing except flag the object as new data. Once you actually try to "get" the ID is when one would be generated. Sort lazy ID generation.