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.
Related
Good day to all, I am new to Laravel and the thing that I encountered with and cannot understand is utility methods that are used in the framework, for example, Customer::all() where Customer is model or Customer::find(). So, what is the point of utility methods and why all() and find() are static.
Utility functions in general offer some sort of utility, i.e. functionality which is usually just for convenience and can also be achieved by following a set of steps.
For example Model::find() is functionality that can also be achieved by creating a query builder object and then performing a query e.g.
Model::getQuery()->where('id', '=', $id)->first();
For convenience you can just do Model::find($id) which is shorter and more intuitive.
It is static because it does not make sense for it not to be static. A non-static method requires an instance of the class however in ORMs an instance of a class corresponds to a potential database entry (which either exists or could exist).
Therefore since find is used to retrieve a database entry it makes no sense to require a backing database entry in order to use it.
In short what this means is, if you execute method $object = Model::find(1) you will get back a model which corresponds to database entry with identifier 1. There is a 1 to 1 mapping of the PHP object to the relational object. If make changes to $object and call $object->save() then changes will be persisted in the database (i.e. $object already exists). If on the other hand you do $object = new Model() you will get back a new model which does not currently correspond to a database entry. However calling $object->save() will make that object correspond to a new database entry and it will be updated accordingly (i.e. the new object could exist). If a framework required you to make a "dummy" object just to access some helper methods there's always a chance that (either by omission or through unknown side-effects) save() gets called on that dummy object and you end up filling up your database with what is essentially junk.
The takeaway from this is that in an ORM it does not make sense to create a model instance if you don't intend to store it in the database. Laravel does not strictly obey this rule, but in general it does, and you should too.
The same applies to all which gets all database entries. It doesn't make sense to get all database entries by requiring to first get one entry.
Same applies to getQuery used above which returns a query builder instance. Note that most people don't actually use getQuery because it runs implicitly when someone uses something like e.g. Model::where(..) so technically Model::where() is also a utility. I mention this because when you see something like Model::where('id', $id)->where('name', $name) the 2nd where is after a -> which implies it's on an instance rather than static, however that instance is actually a query builder instance and not a model instance.
When you do User::find() , you are actually asking for a new instance, either an instance of Collection or a QueryBuilder.
Illuminate\Database\Eloquent\Model : https://github.com/laravel/framework/blob/master/src/Illuminate/Database/Eloquent/Model.php
As a side note, you'll also see another way of using static methods in Laravel e.g. Input::get(). These are called Facades.
Facades provide a "static" interface to classes that are available in the application's IoC container ... Laravel "facades" serve as "static proxies" to underlying classes in the IoC container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.
When a user references any static method on the ... facade, Laravel resolves the cache binding from the IoC container and runs the requested method (in this case, get) against that object.
You can read more about Laravel Facades at: http://laravel.com/docs/facades
Laravel includes a variety of global "helper" PHP functions. Many of
these functions are used by the framework itself; however, you are
free to use them in your own applications if you find them convenient.
So, basically, helpers in Laravel are built-in utility functions that you can call from anywhere within your application. If they hadn't been provided by the core framework, you might have ended up developing your own helper classes.
Although the core provides a variety of helpers already, there’s always a chance that you’ll need your own and would like to develop one so you don’t have to repeat the same code here and there, thus enforcing better maintainability.
all() find() where() etc.. these methods are not utility methods, they are orm methods and coming from Query Builder.
They are static so they provide you using them without creating an instance
Those methods are part of the Eloquent system and help you to retrieve records from your database.
The all method gets all of the records for the given model from the database and returns a Collection of instances of that model. If you were to do User::all(), a collection of every single user in your database would be returned as a Collection of User objects.
$users = User::all(); // Returns a Collection of User objects
foreach ($users as $user) {
// Here, each $user will be an instance of User
}
The find method is used to find a model in the database by its primary key. This method actually returns a single model instance if it finds a record matching the given primary key, or null if it doesn't find anything.
$user = User::find(1); // Find a User with the primary key 1, or null
Those methods aren't actually static, though you can use them as if they were. The find method is a non-static method on the Illuminate\Database\Eloquent\Builder object and the all method is a utility method on Illuminate\Database\Eloquent\Model which eventually calls the Builder object's get method.
When you call User::find(1), Laravel will create a new query or a Builder object and call the find method on the Builder which will return you a new User object, or null. Similarly, when calling User::all(), Laravel will create a new query or Builder object and call the get() method which will return your collection of models.
The Illuminate\Database\Eloquent\Model class uses the __callStatic magic method to redirect static method calls for non-existent static methods to the Builder object. That's how you're able to call them in a static context:
public static function __callStatic($method, $parameters)
{
return (new static)->$method(...$parameters);
}
So you could effectively do this to achieve the same results:
$user = (new User)->find(1);
$allUsers = (new User)->get();
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.
I'm just wondering if someone can help me understand how to make the best use of objects in PHP.
My understanding of a PHP object is that is should represent an entity, providing methods to get and alter the properties of that entity. For example an object entitled Post would hold all the properties of a single post, which could be accessed and modified as appropriate.
What causes me some confusion is that libraries like CodeIgniter don't use objects in this manor. They treat classes more like wrappers for a group of functions. So a 'Posts' class in CodeIgniter would not hold properties of one post, it would provide functions for fetching, editing and deleting posts.
So what happens if I want to get every post out of a database and put it into a Post object? My understanding of it is I would in fact need two classes 'Posts' and 'Post', one that defines the Post object and one that handles fetching the Posts from the database and putting them into Post objects.
Do these two types of class have a name ('Proper' objects / Collections of functions)? And is it common to have two classes working together like this or have I completely misunderstood how to use objects?
Instead of having a Post object would it make more sense to have a method in my Posts class called getSinglePost($id) that just returned an array?
Hopefully that question makes sense, looking forwards to getting some feedback.
For an introduction, see What is a class in PHP?
For the answer, I'll just address your questions in particular. Search for the terms in bold to learn more about their meaning.
My understanding of a PHP object is that is should represent an entity, providing methods to get and alter the properties of that entity.
Entities are just one possible use for objects. But there is also Value Objects, Service Objects, Data Access Objects, etc. - when you go the OO route, everything will be an object with a certain responsibility.
What causes me some confusion is that libraries like CodeIgniter don't use objects in this manor.
Yes, Code Igniter is not really embracing OOP. They are using much more of a class-based-programming approach, which is more like programming procedural with classes and few sprinkles of OOP.
They treat classes more like wrappers for a group of functions. So a 'Posts' class in CodeIgniter would not hold properties of one post, it would provide functions for fetching, editing and deleting posts.
That is fine though. A posts class could be Repository, e.g. an in-memory collection of Post Entities that has the added responsibility to retrieve and persist those in the background. I'd be cautious with Design Patterns and Code Igniter though since they are known to use their own interpretation of patterns (for instance their Active Record is more like a Query Object).
So what happens if I want to get every post out of a database and put it into a Post object?
Lots of options here. A common approach would be to use a Data Mapper, but you could also use PDO and fetch the data rows directly into Post objects, etc.
My understanding of it is I would in fact need two classes 'Posts' and 'Post', one that defines the Post object and one that handles fetching the Posts from the database and putting them into Post objects.
That would be the aforementioned Repository or Data Mapper approach. You usually combine these with a Table Data Gateway. However, an alternative could also be to not have a Posts class and use an Active Record pattern, which represents a row in the database as an object with business and persistence logic attached to it.
Do these two types of class have a name ('Proper' objects / Collections of functions)? And is it common to have two classes working together like this or have I completely misunderstood how to use objects?
Yes, they work together. OOP is all about objects collaborating.
Instead of having a Post object would it make more sense to have a method in my Posts class called getSinglePost($id) that just returned an array?
That would be a Table Data Gateway returning Record Sets. It's fine when you don't have lots of business logic and can spare the Domain Model, like in CRUD applications
Class should ideally has the same interpretation as anywhere else in PHP as well. Class starts with abstraction, refining away what you don't need. So it's entirely up to you to define the class the way you want it.
Codeigniter does have a strange way of initiating and accessing objects. Mainly because they are loaded once and used afterwards, prevents it from having functionality around data. There are ways around it and normal handling of classes still possible. I usually use a auto loader and use normal classes.
"So what happens if I want to get every post out of a database and put it into a Post object? My understanding of it is I would in fact need two classes 'Posts' and 'Post',"
You are essentially referring to a MODEL to access the data ("posts") and an Entity to represent the "post". So you would load the model once and use it to load up as many entities as you would like.
$this->load->model("posts");
$this->posts->get_all(); // <- This can then initiate set of objects of type "Post" and return. Or even standard classes straight out from DB.
Your understanding of an object is correct. A post is a single object of a class Post. But of course you need a function, that retrieves posts from a database or collects them from somewhere else. Therefore you have so called Factory classes. That's what can cause some confusion.
Factories can be singletons, which normally means that you have one instance of this class. But you don't need to instantiate a factory at all (and instead use static functions to access the functionality):
$posts = PostFactory::getPosts();
And then the function:
static function getPosts() {
$list = array();
$sql = "select ID from posts order by datetime desc"; // example, ID is the primary key
// run your sql query and iterate over the retrieved IDs as $id
{
...
$post = new Post($id);
array_push($list, $post);
}
return $list;
}
Inside this factory you have a collection of "access"-functions, which do not fit elsewhere, like object creation (databasewise) and object retrieval. For the second part (retrieval) it is only necessary to put the function into a factory, if there is no "parent" object (in terms of a relation). So you could have an entity of class Blog, you instantiate the blog and then retrieve the posts of the blog via the blog instance and don't need a separate factory.
The naming is only there to help you understand. I wouldn't recommend to call a class Post and it's factory Posts since they can easily be mixed up and the code is harder to read (you need to pay attention to details). I usually have the word "factory" mixed in the class name, so I know that it is actually a factory class and others see it too.
Furthermore you can also have Helper classes, which don't really relate to any specific entity class. So you could have a PostHelper singleton, which could hold functionality, which doesn't fit neither in the object class nor in the factory. Although I can't think of any useful function for a Post object. An example would be some software, which calculates stuff and you have a Helper, which performs the actual calculation using different types of objects.
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).
My question is more like a theoretical.
Say you have an object, that represents the list of something (articles, pages, accounts etc.)
class ObjCollection
You have a class, that represents a specific item in collection:
class objItem
I have a problem thinking of a basic responsibilities of each object.
Which class is responsible for creating a new objItem?
Which class is responsible for deleting a objItem? Should it delete itself as a method?
Update 1:
Techpriester: Is it ok to use object's constructor as a function to create new item?
I think of that like:
class objItem {
public function __construct($id = 0) {
if ($id > 0) {
// load item data...
} else {
// make new item...
}
}
}
But what if something goes wrong in the code, and instead of passing an $id > 0, it passes 0? In this case a more expected behavior would be an empty object, and not the new one, or am I wrong?
A way of thinking about this:
objItem usually have a class constructor so this class might be responsible for creating objects of type objItem.
When an objItem is inserted in a list/collection let's say objCollection it can be objCollection responsability to delete it from the collection.
objItem usually have a class
constructor so this class is
responsible for creating objects of
type objItem.
Constructor has nothing to do with responsibility (usually). Thinking this way, every object would be only responsible for itself.
Responsiblity is a concept not directly binded with class hierarchy.
If:
ObjCollection = Nest objItem = Egg. And there is third object Bird, Then Bird takes responsibility for creating egs (even if nest contains egg). It is not about programming it is about common sense... :)
There is not such thing like "empty object". Objects have "state". You can create an object and then you have it, or you may not to create it and there is no object then.
All you have to worry about is if your constructor will work fine in both cases, with new object created and without it.
Usually it is better to inject object as a constructor parameter (instead of $id) not to create it inside another object.
I know this doesn't answer your question, but since you tagged this as PHP I'm going to assume that it will almost certainly be applied with some sort of database model.
In that case, it's probably a better idea to do away with 'collections' altogether since if you made each class represent only one object, if you wanted to view 10 blog posts, for example, you would be calling 10 separate SELECT queries each retrieving only an individual database record, because you decided to have the 'BlogPost' class encapsulate its retrieval method.
The alternative is to let the class represent either one or more records, that way, you only need to run one SELECT query whether you're retrieving 5000 records or only one. Pretty much every object-relational-mapper does this.
When doing object-oriented programming, it's better to think in terms of behavior or responsibility than whether or not the object is a tangible 'thing'. That's the problem with theoretical discussion of OOP. It's very tempting to use analogies like animals and fruits which have very little relevance to real-world programming.
Since an object cannot delete itself, that has to be the responsibility of the collection.
Wether you let the collection create it's objects like $collection->makeNewItem(); (which then calls the items constructor) or use $item = new Item(); directly and then some $collection->addItem($item);method is entirely up to you and the needs of your application.
I'd recommend using regular instantiation if the items themselves are also used outside of the collection.