I've a class, Proposal, which has a $status of type ProposalStatus. Now, for the most part the ProposalStatus's identity does not change... but it does (sort of). It's $id is fixed, but the $display_name and $definition (just strings) can change over a long period of time as the master data is updated, but it will NOT change within the lifetime of an HTTP Request-Response.
Question #1 - Entity or Value Object?
Is a value object something is never supposed to change or only never supposed to change over the lifetime of a specific execution of the application? If the display name or definition are changed then really I expect / want it to be changed for everyone. However, since they can be defined outside of the proposal I'm think that just straight up makes them entities instead of value objects.
At no time does the Proposal change the ProposalStatus's attributes, it only changes which ProposalStatus is has.
Question #2 - How to set the status correctly for a domain-driven design?
My proposal object has the ability to manage it's statuses, but in order to do that I need to have a specific ProposalStatus object. Only, where is the list of statuses that allows it to returns the right expected to be?
- I could get it from a the ProposalRepository... but everything is accessed via the aggregate root which the Proposal so that doesn't make sense.
- I could have constants that match the $id of the ProposalStatus, but that seems wrong.
- I could make a ProposalStatusRepository... but should I be accessing another repository from within the Proposal?
- I could make a array of all possible statuses with the $id as the key and add to the proposal, but that isn't much different from a repository...
Example:
class ProposalStatus {
protected $id; // E.g., pending_customer_approval
protected $display_name; // E.g., Pending Customer Approval
protected $definition; // E.g., The proposal needs to be approved by the customer
}
class Proposal {
/**
* The current status of the proposal
* @var ProposalStatus
*/
protected $proposal_status;
public function withdraw() {
// verify status is not closed or canceled
// change status to draft
}
public function submit() {
// verify status is draft
// change status to pending customer approval
}
public function approve() {
// verify status is pending customer approval
// change status to approved
}
public function reject() {
// verify status is pending customer approval
// change status to rejected
}
public function close() {
// verify status is not canceled
// change status to closed
}
public function cancel() {
// verify status is not closed
// change status to canceled
}
}