Entities and Value Objects should never be dependent on anything except for each other. These are the most fundamental of all the building blocks of DDD. They represent the concepts of Your problem domain and thus should focus on the problem. By making them dependent on Factories, Repositories and Services You make that focus blur. There is another problem with having a reference to Services in Entities and Value Objects. Because Services also possess the domain logic You will be tempted to delegate some of the responsibilities of the domain model to Services which eventually may lead to the Anemic Domain Model.
Factories and Repositories are just helpers used for creation and persistence of Entities. Most of the time they just have no analogy in the real problem domain, so having a reference from Factories and Repositories to Services and Entities would make no sense according to the domain logic.
Regarding the example You provided, this is how I would implement it
$article->addTag($tag);
$articleRepository->save($article);
I wouldn't give the direct access to the underlying collection, because I might want the Article
to perform some domain logic (imposing constraints, validating) on the Tag
before adding it to the collection.
Avoid this
$articleService->addTag($article, $tag);
Use Services only to perform operations that don't belong to any Entity conceptually. First, try to fit it to an Entity, make sure it doesn't fit any. And only then use a Service for it. This way You won't end up with anemic domain models.
UPDATE 1
A quote from Eric Evans's "Domain-Driven Design: Tackling Complexity in the Heart of Software" book:
SERVICES should be used judiciously and not allowed to strip the
ENTITIES and VALUE OBJECTS of all their behavior.
UPDATE 2
Somebody has downvoted this answer and I don't know why. I can only suspect the reason. It could be about the references between Entities and Services or it could be about the example code. Well, I can't do much about the example code, because it was my opinion based on my own experience. But, I did some more research on the references part and here is what I came up with.
I am not the only one who thinks that referencing Services, Repositories and Factories from Entities is not a good idea. I found similar questions here in SO:
There are also some good articles on the subject, especially this one How not to inject services in entities which also presents a solution, if You desperately need to call a Service from Your Entity, named Double Dispatch. Here is an example from the article ported to PHP:
interface MailService
{
public function send($sender, $recipient, $subject, $body);
}
class Message
{
//...
public function sendThrough(MailService $mailService)
{
$subject = $this->isReply ? 'Re: ' . $this->title : $this->title;
$mailService->send(
$this->sender,
$this->recipient,
$subject,
$this->getMessageBody($this->content)
);
}
}
So, as You can see You don't have a reference to the MailService
service inside Your Message
entity, instead it's passed as an argument to the entity's method. The same solution is proposed by the author of this article "DDD: Services" at http://devlicio.us/ in the comments section.
I have also tried to look at what Eric Evans says about this in his "Domain-Driven Design: Tackling Complexity in the Heart of Software" book. Having briefly searched, I didn't find the exact answer, but I found an example where an Entity actually calls the service statically, that is without having a reference to it.
public class BrokerageAccount {
String accountNumber;
String customerSocialSecurityNumber;
// Omit constructors, etc.
public Customer getCustomer() {
String sqlQuery =
"SELECT * FROM CUSTOMER WHERE" +
"SS_NUMBER = '" + customerSocialSecurityNumber + "'";
return QueryService.findSingleCustomerFor(sqlQuery);
}
public Set getInvestments() {
String sqlQuery =
"SELECT * FROM INVESTMENT WHERE" +
"BROKERAGE_ACCOUNT = '" + accountNumber + "'";
return QueryService.findInvestmentsFor(sqlQuery);
}
}
And the note below states the following:
Note: The QueryService, a utility for fetching rows from the database
and creating objects, is simple for explaining examples, but it's not
necessarily a good design for a real project.
If You have a look at the source code of the DDDSample project I've mentioned above, You'll see that Entities don't have any reference to anything except for the objects in the model
package, i.e. Entities and Value Objects. By the way, the DDDSample project is described in the "Domain-Driven Design: Tackling Complexity in the Heart of Software" book in detail...
Also, one more thing I would like to share with You is a similar discussion on the
domaindrivendesign Yahoo Group. This message from the discussion quotes Eric Evans on the subject of model objects referencing Repositories.
Conclusion
To summarize, having a reference to Services, Repositories and Factories from Entities is NOT good. This is the most accepted opinion. Even though Repositories and Factories are citizens of the Domain layer, they are not part of the problem domain. Sometimes (e.g. in the Wikipedia article on the DDD) the concept of the Domain services is called Pure Fabrication which implies that the class (Service) "does not represent a concept in the problem domain". I'd rather refer to Factories and Repositories as Pure Fabrications, because Eric Evans does say something else in his book about the concept of Services:
But when an operation is actually an important domain concept, a
SERVICE forms a natural part of a MODEL-DRIVEN DESIGN. Declared in the
model as a SERVICE, rather than as a phony object that doesn't
actually represent anything, the standalone operation will not mislead
anyone.
According to the above-said, sometimes calling a Service from Your Entity might be a sane thing to want. Then, You can use the Double Dispatch approach, so that You won't have to keep a reference to the Service in Your Entity class.
Of course, there are always some people who disagree with the mainstream opinion like the author of Accessing Domain Services from Entities article.