Doctrine with static entities - php

I have a database, where I store some fixed values like product categories. When I create a new product and I want to assign a category to it, I do it this way:
$categories = new ProductCategoryRepository();
$category = $categories->find(ProductCategory::EXAMPLE);
$product = new Product();
$product->setCategory($category);
However, I'm not sure why I have to lookup the database all the time to get static entities my app is already aware of.
It should be enough to assign the category statically. Maybe something like this:
$category = ProductCategory::EXAMPLE;
Now Doctrine should persist the relation with the correct ID (described by the ProductCategory class (which could be an entity?)) and I no longer have to lookup the database for static properties.
I don't know how to do this, yet. I could create new entities all the time, but this doesn't seem to be correct, because the values are already stored in the DB and they are always the same and not new entities.
$category = new ProductCategory::EXAMPLE;
Fetching the relation from the product however should return the property as an entity:
$category = $product->getCategory();
return $category instanceof ProductCategory; // true
Is there a way to achieve this behaviour?
It is more an architecture question than a performance tweak. I don't want to describe information multiple times (db entries, php constants, entity relations etc.).

There is something called "second level cache" in Doctrine, but the feature is considered experimental and you should maybe read the documentation carefully before using it.
A quote from the official documentation of this feature:
The Second Level Cache
The second level cache functionality is marked as experimental for now. It is a very complex feature and we cannot guarantee yet that it works stable in all cases.
Entity cache definition is done like this: (documentation)
/**
* #Entity
* #Cache(usage="READ_ONLY", region="my_entity_region")
*/
To improve performance for such entities like you are talking about in your question you should also consider to mark them as "read only", which will lead to performance increase from Doctrine 2.1, as can be found in the Doctrine documentation on improving performance:
Read-Only Entities
Starting with Doctrine 2.1 you can mark entities as read only (See metadata mapping references for details). This means that the entity marked as read only is never considered for updates, which means when you call flush on the EntityManager these entities are skipped even if properties changed. Read-Only allows to persist new entities of a kind and remove existing ones, they are just not considered for updates.
The entity should be configured like this: (documentation)
/** #Entity(readOnly=true) */
Second level cache and read only for your ProductCategory:
So after setting up second level read only caching with for example a region named read_only_entity_region your configuration for your ProductCategory would look something like this:
/**
* #Entity(readOnly=true)
* #Cache(usage="READ_ONLY", region="read_only_entity_region")
*/
class ProductCategory
{
//...your entity definition...
}

If you don't want it to hit the database every time you could just store it in the Cache:
public function getCategory(){
return Cache::rememberForever('category-'.$this->category_id, function() {
return $categories->find($this->category_id);
});
}
This will pull the info from the database if it has never been pulled, but will just grab it from the cache if it has been. You would have to use Cache::forget('category-2') to remove it, or php artisan cache:clear. Your static values would just be integer IDs and your products would have a category_id but the categories themselves would be cached.

Related

CakePHP: How do I load associated data from inside an entity class?

Let's say I have a AuthorsTable with a defined "belongs to many" association with the Articles table defined like so:
// In the initialize function of the AuthorsTable class.
$this->belongsToMany('Articles',
['joinTable' => 'authors_articles']
);
(I don't think that the nature of the join is relevant to the question, but just in the interest of giving full context.)
And now, a I have an $author entity that was passed to my function that does not have the associated data loaded with it (i.e., it was created using something like $author = $authorsTable->get(19);, so it only has the information in the authors table, not from the articles table.
Is there some kind of entity function in which I can load the associated data, i.e., the articles data after the entity has already been created?
chriss's answer suggests using loadInto for this. For CakePHP 3, the PHP you need within any Author Entity method is:
TableRegistry::get($this->source())->loadInto($this, ['Articles']);
The same code from within an AuthorsTable method:
$this->loadInto($author, ['Articles']);
It's a little bit over and I do not know if it's still important to you, but maybe for everyone else.
You can either use the model's loadInto (https://book.cakephp.org/3.0/en/orm/retrieving-data-and-resultsets.html#loading-additional-associations) or you can just use the Lazy Loading Plugin, mentioned in the docs (https://book.cakephp.org/3.0/en/orm/entities.html#lazy-loading-associations)
You can find the plugin here:
https://github.com/jeremyharris/cakephp-lazyload
The plugin works with both methods! If you prefer Eager Loading, you can use contain (normaly faster). Otherwise, the associations will be loaded "on demand" (saving memory).
Personally, I prefer Eager Loading but use the Lazy Loading Plugin if another member of the team (out of ignorance) forgot to load the Associations.

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.

Symfony and Doctrine: lazy loading is not working

Using Symfony 2.8.
I have Community and MenuItem entities, where a Community has a set of MenuItems.
Community.php has the following code:
...
/**
* #ORM\OneToMany(targetEntity="MenuItem", mappedBy="community", fetch="LAZY")
* #ORM\OrderBy({"sequence" = "ASC"})
*/
private $menuItems;
...
MenuItem.php has the following code:
...
/**
* #var Community
*
* #ORM\ManyToOne(targetEntity="Community", inversedBy="menuItems")
*/
private $community;
...
The point is, when I use:
$menuItems = $community->getMenuItems();
the $menuItems variable will be an empty collection.
The problem can be solved by setting fetch="EAGER" instead of fetch="LAZY", because in that way the $menuItems attribute of the Category entity is loaded immediatly.
LAZY vs EAGER (source) :
Whenever you have a managed entity instance at hand, you can traverse and use any associations of that entity that are configured LAZY as if they were in-memory already. Doctrine will automatically load the associated objects on demand through the concept of lazy-loading.
Whenever you query for an entity that has persistent associations and these associations are mapped as EAGER, they will automatically be loaded together with the entity being queried and is thus immediately available to your application.
The point is that while EAGER loading is working as expected, LAZY loading seems not working at all. Any idea about why?
This seems to work to load the lazy relationship.
$logs = $entity->getLogs(); // lazy relationship
$this->getDoctrine()->getManager()->initializeObject($logs);
$logs will now populate.
Docs for initializeObject:
Helper method to initialize a lazy loading proxy or persistent
collection.
When you are doing $community->getMenuItems(); :
In EAGER mode: the data are already fetched, so the array is returned.
In LAZY mode: the database request is done when you do the call. Behind the scene it works by generating "proxies" in front of your entities that will call doctrine for you.
Carefull with lazy loading :
Traversing the object graph for parts that are lazy-loaded will easily trigger lots of SQL queries and will perform badly if used to heavily.
It's better to fetch directly the data, by doing a DQL fetch. See for instance http://blog.bemycto.com/good-practices/2015-05-31/understanding-doctrine-orm-lazy-load-fetch-join/
Personally, I'm not a fan of lazy/eager loading as many queries will be fired when they can be done in one query with joins.
Please see my answer here on how to implement a custom repository to build a custom query, link

Laravel - Where to store statuses (flags)? Model, Class or config folder?

I need to extensively use statuses in mt project. I need them for my users (active, suspended, etc), an entity (active, pending_activation, inactive) and for my subscriptions(active, on_grace_period, not_subscribed, never_subscribed).
So far I thought that the best way is to store them in the DB but i have a feeling it's much easier to have them in the other 3 options.
I also thought that i can store them in my Eloquent Model as constants. For example my subscription model would look like this:
// SubscriptionModel
const SUBSCRIBED_ACTIVE = 1;
const SUBSCRIBED_ON_GRACE_PERIOD = 2;
const NOT_SUBSCRIBED = 3;
const NEVER_SUBSCRIBED = 4;
and retrieving them, for example in a blade view:
// subscription/index.blade.php
#if($user->subscription->status == /App/SubscriptionModel::SUBSCRIBED_ACTIVE)
<div>You are subscribed. Thank you</div>
#elseif($user->subscription->status == /App/SubscriptionModel::NEVER_SUBSCRIBED)
<div>You need to create a subscription before being granted full access!</div>
#elseif(...)
// and so on
How about doing the same but using the config folder and adding a file called status.php. Accessing it in the view would be like:
#if($user->subscription->status == Config::get('status.subscription.SUBSCRIBED_ACTIVE'))
<div>You are subscribed. Thank you</div>
#elseif(...)
// etc
Is there a better way?
Also, how about the other part of the equation, meaning the status stored in the DB. Should I only have a status column for the subscription table and store what the app dictates or even bettter create a separate table subscription_statuses and have a foreign_key subscription_status_id in the subscriptions table?
I tend to create a specific model for statuses, that acts as an enum. So if I have an Event model, I may have a corresponding EventStatus model that looks like this:
class EventStatus
{
public const CANCELLED = 'EventCancelled';
public const POSTPONED = 'EventPostponed';
public const RESCHEDULED = 'EventRescheduled';
public const SCHEDULED = 'EventScheduled';
}
I can then do checks like this:
$event->status === EventStatus::CANCELLED;
And I’ll usually add convenience methods to my models too:
class Event extends Model
{
public function isCancelled(): bool
{
return $this->status === EventStatus::CANCELLED;
}
}
For the “human-friendly” strings, I’ll then have a language file that has the text strings:
<?php // resources/lang/en/event_status.php
return [
EventStatus::CANCELLED => 'Cancelled',
EventStatus::POSTPONED => 'Postponed',
EventStatus::RESCHEDULED => 'Rescheduled',
EventStatus::SCHEDULED => 'Scheduled',
];
In my applications I do similar to #Martin Bean except I don't create separate classes for status, I store that inside the existent class/Model.
I'm going to call user, subscription and entity a entity.
Entity have a status that exists in it's Model and table in the database.
Each Model have constants of possible values of status like ACTIVE, INACTIVE, PENDING, etc, and those may vary for each Model.
Create methods for dealing with it like getStatusLabel(), listStatus(), isActive(), isX(), etc.
Those isActive/X() are only created if really necessary, maybe a Model have 4 status but you only do comparisons against one specific, so I'd create only one isX() for that status.
Example
class User
{
const STATUS_ACTIVE = 1;
const STATUS_SUSPENDED = 2;
const STATUS_INACTIVE = 3;
/**
* Return list of status codes and labels
* #return array
*/
public static function listStatus()
{
return [
self::STATUS_ACTIVE => 'Active',
self::STATUS_SUSPENDED => 'Suspended',
self::STATUS_INACTIVE => 'Inactive'
]
}
/**
* Returns label of actual status
* #param string
*/
public function statusLabel()
{
$list = self::listStatus();
// little validation here just in case someone mess things
// up and there's a ghost status saved in DB
return isset($list[$this->status])
? $list[$this->status]
: $this->status;
}
/**
* Some actions will happen only if it's active, so I have
* this method for making things easier.
* Other status doesn't have a specific method because
* I usually don't compare agains them
* #return Boolean
*/
public function isActive()
{
return $this->status == self::STATUS_ACTIVE;
}
}
I do not agree with the other answers. Your status information should be stored in the database. A well designed database should be clear and usable without the application. What happens if you decide to use this database to power something like a mobile application as well? You will be taking some of the information away from the database and storing it only in Laravel, meaning you would have to duplicate that list of statuses in your mobile application too, and maintain it across the two.
This kind of information should be stored in the database.
Option 1
If your users can only ever have one status, then you should use an enum field with the values subscribed, subscribed-grace, not-subscribed, never-subscribed
This is just as simple in your views:
#if($user->subscription->status == 'subscribed'
Option 2
If however, you might have multiple statuses, then you should almost certainly have a separate field for each status, and use a TINYINT to store a 1 or 0.
Separate status table?
I cannot see a good reason to use a separate status table unless you anticipate you might add many more statuses, and even if you are adding more, you can just add new values to the enum or add a new field depending on which option would suit.
A status table would be ideal if you plan to use the statuses for many other tables in the database besides users.
The only other reason for a seperate status table would be if you decided to change the meaning of a particular status. This would mean you could rename the status in the status table, but the users would still be linked to it via it's primary key. Changing the meaning of a status with the previous two methods would involve changes to the structure.
It really comes down to how you anticipate you will use them, but there is no reason not to keep them in the database.
There are advantages and disadvantages to each method. It's good to be aware of each.
Table - Pros and cons (AJReading's method):
Adding and maintaining a table SEEMS tedious
Just having another table and model can make our code feel more cluttered (not saying it's a good reason not to use just saying it's kinda true)
It gets awkward when we have application logic dependent upon something in the database (things in the database feel like they should be variable, when we base application logic on them they're required)
Now we have migrations, but before them these used to be the bane of developers existence (they would make switching between servers an awful chore because you had to remember to add new statuses or your app would crash)...you would have had to do this with any database change but still these were the ones I'd have to do the most frequently
Good for data integrity
Using constants: Pros/cons (Martin Bean's method):
Avoids the disadvantages above
These are easy to reference in your code and base logic on
You don't have to create a new model or table even (he does in his example, but you could also just put them in the Events model)
They're great for values that will ONLY be used behind the scenes
They reduce the amount of queries
They just don't feel like as much work. They seem easier to refactor.
Con: they get kinda awkward when you get into labeling them, retrieving all of them, getting descriptions, etc. The translation solution is a good one but if you don't use translations in your app then this is a bit awkward as well.
Ultimately they're breaking the ORM flow you have going. If all your other models extend Eloquent then this breaks the mold a bit.
There's no real agreement on how to best do this. A lot of people use a different method each time.
Like AJReading said, if you need to use the database alone for another aspect of the project it won't work
I use the constant method but sometimes I'd think my code might be cleaner and simpler if I'd used tables. It's a hard call. I'd like there to be a well documented solution for the constant method to at least create consistency but I haven't seen one yet. Either way I don't think there's a right or wrong answer. Pick one and go with it!
For decisions of this nature, ask yourself this:
"Will there ever be an instance of my application where it would make
sense for these constants to have different values?"
e.g. a test environment, some sort of clone, some not yet defined but possible future version...
If the answer to that question is "yes", then it should probably go in application config.
If it is unlikely, (or daft) to have the values change, they belong to, and should go in the model.
I suggest in this case there would be no sensible reason to ever have a version of the application with different values, so I'd put it in the model.

How does the Doctrine Repository mechanism of lazy loading entities work?

So, I want to understand how the Doctrine Repository mechanism works.
For my entities I use annotations, so the resulting object is built somewhere during the execution of the script.
I'd like to unserstand which are the possibile ways of implementing the lazy loading of entities from another entity.
In concrete, using Doctrine, I have the ability to fetch information of related object (from the Symfony book). This fetching is done in a lazy way: only if I call the method to get the information about the Entity it is loaded from the database querying it.
Now, I'd like to better understand this mechanism: how an entity can implement repository methods?
How can I reproduce this mechanism to implement it in other context similar to the one of a database data retrieval?
As the resulting object is really big, is there someone who can put me on the right way?
Which classes should have I read to understand the mechanism?
Are there any articles/posts that better explain how this mechanism is implemented?
Are there better (or simply simpler) ways of implementing it?
I think the best description of the lazy loading can be found in Doctrine developer articles.
http://www.giorgiosironi.com/2009/07/lazy-loading-of-objects-from-database.html
http://www.giorgiosironi.com/2009/08/doctrine-2-now-has-lazy-loading.html
The main idea is to insert into Product's category list a set of objectes that are subclasses of Category. These and called "proxy objects" and created "on the fly" when Product is retrieved from database. These proxy objects have the same interface as Category object, but add functionality of loading actual Category items from database when needed.
Doctrine actually creates a extra object (think proxy) that keeps a record of what properties have actually been accessed.
See this part from the documentation :
32.4.2. Association proxies
The second most important situation where Doctrine uses proxy objects is when querying for objects. Whenever you query for an object that has a single-valued association to another object that is configured LAZY, without joining that association in the same query, Doctrine puts proxy objects in place where normally the associated object would be. Just like other proxies it will transparently initialize itself on first access.
doctrine documentation
You can create a custom repository for an entity: http://symfony.com/doc/current/book/doctrine.html#custom-repository-classes
Once you have your own custom repository class you can create queries that fetch all of the information you need in one query rather than relying on lazy loading.
So say you have an Product entity which has one or more Category entities using a ManyToMany relationship you could create a function in your custom repository to fetch all products with their categories in one query:
public function fetchProductsWithCategories()
{
return $this->getEntityManager()
->createQuery(
'SELECT p, c FROM Product p join p.categories c'
)
->getResult();
}
Then in your controller you would have something like:
$repo = $this->getDoctrine()->getManager()->getRepository('Product');
$products = $repo->fetchProductsWithCategories();
Edit: missed c in select

Categories